diff --git a/docs/changelog.md b/docs/changelog.md index b5b3eaf6..275dffab 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,7 @@ description: Release history for OpenChoreo | Version | Date | Changelog | | ----------- | ---------- | ----------------------------------------------------------------------------------------- | +| v1.2.0-rc.2 | 2026-07-24 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.2.0-rc.1...v1.2.0-rc.2) | | v1.2.0-rc.1 | 2026-07-17 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.1.0...v1.2.0-rc.1) | | v1.2.0-m.1 | 2026-06-12 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.1.1...v1.2.0-m.1) | | v1.1.3 | 2026-07-22 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.1/CHANGELOG.md#v113) | diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 6eb5e563..873ed805 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -126,6 +126,11 @@ const config: Config = { docs: { lastVersion, versions: { + 'v1.2.0-rc.2': { + label: 'v1.2.0-rc.2 (pre-release)', + banner: 'unreleased', + noIndex: true, + }, 'v1.2.0-rc.1': { label: 'v1.2.0-rc.1 (pre-release)', banner: 'unreleased', diff --git a/versioned_docs/version-v1.2.0-rc.2/_constants.mdx b/versioned_docs/version-v1.2.0-rc.2/_constants.mdx new file mode 100644 index 00000000..af1718a7 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/_constants.mdx @@ -0,0 +1,13 @@ +[//] # (This file stores the constants used across the documentation.) + +export const versions = { + dockerTag: "v1.2.0-rc.2", + githubRef: "release-v1.2.0-rc.2", // Used for the GitHub Raw URL references. Example: main, latest, v0.1.0 + helmChart: "1.2.0-rc.2", + helmSource: "oci://ghcr.io/openchoreo/helm-charts", +}; + +export const defaultCredentials = { + username: "admin@openchoreo.dev", + password: "Admin@123", +}; diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/finops-agent.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/finops-agent.mdx new file mode 100644 index 00000000..98ad0da6 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/finops-agent.mdx @@ -0,0 +1,195 @@ +--- +title: FinOps Agent +description: Configure the FinOps Agent in OpenChoreo for AI-powered cloud cost analysis and optimization. +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# FinOps Agent + +The FinOps Agent is an AI-powered component that analyzes Kubernetes resource usage and cloud cost data from your OpenChoreo components to generate reports with cost optimization recommendations. It integrates with Large Language Models (LLMs) to provide cost attribution, rightsizing suggestions, and actionable insights to help teams reduce cloud spend. + +## Prerequisites + +Before enabling the FinOps Agent, ensure the following: + +- OpenChoreo Observability Plane installed with at least a metrics module. +- An LLM API key from [OpenAI](https://platform.openai.com/) (support for other providers coming soon) +- [Metrics collection configured](../platform-engineer-guide/observability-alerting.mdx) for your components. + +## Enabling the FinOps Agent + +### Step 1: Install a FinOps module + +The FinOps Agent relies on a FinOps module to provide Kubernetes resource cost data. Install a FinOps module before enabling the agent — for example, the [OpenCost FinOps module](https://github.com/openchoreo/community-modules/tree/main/finops-opencost). + +### Step 2: Create the FinOps Agent Secret + +The FinOps Agent requires a Kubernetes Secret named `finops-agent` in the `openchoreo-observability-plane` namespace with the following keys: + +| Key | Description | +| --------------------- | -------------------------------------------------- | +| `LLM_API_KEY` | Your LLM provider API key | +| `OAUTH_CLIENT_SECRET` | OAuth client secret (only needed for external IdP) | + +You can create this secret using any method you prefer. If you followed the [Try It Out on k3d locally](../getting-started/try-it-out/on-k3d-locally.mdx) guide, you can follow along: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/finops-llm-api-key value="" +``` + +```bash +kubectl apply -f - < + {`helm upgrade --install openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --reuse-values \\ + --set finOpsAgent.enabled="true" \\ + --set finOpsAgent.llmName= \\ + --set finOpsAgent.remediationEnabled=true`} + + +:::note Supported Models +The FinOps Agent currently supports the [OpenAI](https://platform.openai.com/) GPT model series (e.g., `gpt-5.4`, `gpt-5.2-pro`, `gpt-5` etc.). Support for additional model providers is coming soon. + +The `gpt-5.6` series is not supported at the moment. Support is coming soon. +::: + +If the observability plane and control plane are in separate clusters, also set `finOpsAgent.openchoreoApiUrl` to the control plane API URL (defaults to `http://api.openchoreo.localhost:8080`). + +### Step 4: Register with the control plane + +Configure `finOpsAgentURL` in the `ClusterObservabilityPlane` resource so the UI knows where to reach the FinOps Agent: + + + {`kubectl patch clusterobservabilityplane default --type=merge -p '{"spec":{"finOpsAgentURL":"http://finops-agent.openchoreo.localhost:11080"}}'`} + + +### Step 5: Verify the installation + +Check that the FinOps Agent pod is running: + +```bash +kubectl get pods -n openchoreo-observability-plane -l app.kubernetes.io/component=finops-agent +``` + +If you are using the default identity provider (ThunderID) and the default SQLite report storage, your setup is complete. + +
+Authentication and Authorization (External IdP) + +By default, OpenChoreo configures ThunderID as the identity provider for the FinOps Agent with a pre-configured OAuth client for testing purposes. If you are using an external identity provider, follow the steps below. + +#### Authentication + +Create an OAuth 2.0 client that supports the `client_credentials` grant type for service-to-service authentication. + +Store your OAuth client secret in OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/finops-agent-oauth-client-secret value="" +``` + +Then configure the Observability Plane Helm values with your client credentials: + +```yaml +security: + oidc: + tokenUrl: "" + +finOpsAgent: + secretName: "finops-agent" + oauth: + clientId: "" +``` + +See [Identity Provider Configuration](../platform-engineer-guide/identity-configuration.mdx) for detailed setup instructions. + +#### Authorization + +The FinOps Agent uses the `client_credentials` grant to authenticate with the OpenChoreo API as a service account. The API matches the `sub` claim in the issued JWT to identify the caller, so the new client must be granted the `finops-agent` role via a bootstrap authorization mapping. + +Add the following to your Control Plane values override, replacing `` with the same client ID used above: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: finops-agent-binding + roleRef: + name: finops-agent + entitlement: + claim: sub + value: "" + effect: allow +``` + +
+ +
+Report Storage + +By default, FinOps reports are stored in **SQLite** with a persistent volume — no external database required. + +For production deployments that need horizontal scaling or shared storage, you can use **PostgreSQL** instead. + +Store the PostgreSQL connection URI in OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/finops-sql-backend-uri value="postgresql+asyncpg://:@:/" +``` + +Add the `SQL_BACKEND_URI` key to the ExternalSecret from [Step 2](#step-2-create-the-finops-agent-secret): + +```bash +kubectl patch externalsecret finops-agent -n openchoreo-observability-plane --type=json \ + -p '[{"op":"add","path":"/spec/data/-","value":{"secretKey":"SQL_BACKEND_URI","remoteRef":{"key":"finops-sql-backend-uri","property":"value"}}}]' +``` + +Then set the report backend in your Helm values: + +```yaml +finOpsAgent: + reportBackend: postgresql +``` + +
diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/mcp-prompt-scenarios.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/mcp-prompt-scenarios.mdx new file mode 100644 index 00000000..dba491ce --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/mcp-prompt-scenarios.mdx @@ -0,0 +1,70 @@ +--- +title: MCP Prompt Scenarios +--- + +# MCP Prompt Scenarios + +This page provides a collection of practical prompt scenarios for using the OpenChoreo MCP server with AI assistants. Each scenario is a hands-on guide that walks you through real-world tasks using natural language prompts. + +## Prerequisites + +Before trying these scenarios: + +1. **Configure your MCP server** — follow the [Configuring MCP Servers with AI Assistants](./mcp-servers.mdx) guide +2. **Review available tools** — see the [MCP Servers Reference](../reference/mcp-servers.mdx) for the full list of MCP tools + +## Scenarios + +### 1. Getting Started + +Learn the basics of connecting your AI assistant to OpenChoreo and performing simple operations like listing namespaces and projects. + +**Time:** ~2 minutes + +[View guide on GitHub →](https://github.com/openchoreo/openchoreo/tree/main/samples/mcp/getting-started) + +--- + +### 2. Service Deployment + +Deploy a complete service from source code to production using the OpenChoreo MCP server. Choose between a step-by-step guided walkthrough or a natural conversation-based deployment. + +**Time:** ~15-20 minutes + +[View guide on GitHub →](https://github.com/openchoreo/openchoreo/tree/main/samples/mcp/service-deployment) + +--- + +### 3. Log Analysis & Debugging + +Debug a cascading failure in the GCP Microservices Demo (Online Boutique) application. You'll intentionally break the product catalog service by scaling it to zero replicas, then use AI-assisted observability — logs, distributed traces, and deployment inspection — to diagnose and fix the issue across service boundaries. + +**Key MCP tools:** `list_components`, `query_component_logs`, `query_traces`, `query_trace_spans`, `get_release_binding`, `update_release_binding` + +**Time:** ~10 minutes + +[View guide on GitHub →](https://github.com/openchoreo/openchoreo/tree/main/samples/mcp/log-analysis) + +--- + +### 4. Build Failure Diagnosis + +Debug a Docker build failure in the Go Greeter service. You'll trigger a build with a misconfigured Dockerfile path, then use AI-assisted workflow inspection and log analysis to diagnose the root cause, compare with the previous successful build, and apply the fix. + +**Key MCP tools:** `list_workflow_runs`, `get_workflow_run`, `query_workflow_logs`, `create_workflow_run` + +**Time:** ~10 minutes + +[View guide on GitHub →](https://github.com/openchoreo/openchoreo/tree/main/samples/mcp/build-failures) + +--- + +### 5. Resource Optimization + +Detect and fix over-provisioned deployments in the GCP Microservices Demo (Online Boutique). You'll intentionally allocate excessive CPU and memory to several services, then use AI-assisted analysis to compare allocation vs actual usage, get right-sizing recommendations, and apply optimized configurations. + +**Key MCP tools:** `list_components`, `list_release_bindings`, `get_release_binding`, `query_resource_metrics`, `update_release_binding` + +**Time:** ~10 minutes + +[View guide on GitHub →](https://github.com/openchoreo/openchoreo/tree/main/samples/mcp/resource-optimization) diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/mcp-servers.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/mcp-servers.mdx new file mode 100644 index 00000000..596afa35 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/mcp-servers.mdx @@ -0,0 +1,350 @@ +--- +title: Configuring MCP Servers with AI Assistants +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { defaultCredentials } from "../_constants.mdx"; + +# Configuring MCP Servers with AI Assistants + +This guide shows how to connect your AI assistant to OpenChoreo MCP servers using the pre-configured default OAuth applications or custom setups. + +## Prerequisites + +Before following this guide: + +1. Review the [MCP Servers Reference](../reference/mcp-servers.mdx) to understand the available MCP servers and tools +2. Note your MCP server URLs from the MCP Servers Reference page +3. Have your AI assistant installed and ready to configure + +## Quick Start (Default Setup) + +This guide uses the pre-created OAuth applications available in the default ThunderID IdP that ships with the k3d setup. No manual IdP configuration is required. The following AI agents are supported: + +| AI Agent | Browser-Based | Client Credentials | +| ------------------------ | :-----------: | :----------------: | +| Claude Code | Yes | Yes | +| Codex CLI | — | Yes | +| Cursor | Yes | Yes | +| Gemini CLI | Yes | Yes | +| OpenCode CLI | Yes | Yes | +| VS Code (GitHub Copilot) | — | Yes | + + + + +Browser-based authentication uses the `user_mcp_client` OAuth application (public client with PKCE, authorization code grant), which is pre-created in the default ThunderID IdP. + +When prompted, log in with the default credentials: + +- **Username**: {defaultCredentials.username} +- **Password**: {defaultCredentials.password} + + + + +Add both MCP servers using the Claude Code CLI: + +```bash +claude mcp add --transport http \ + --client-id user_mcp_client --callback-port 8075 \ + openchoreo-cp http://api.openchoreo.localhost:8080/mcp + +claude mcp add --transport http \ + --client-id user_mcp_client --callback-port 8075 \ + openchoreo-obs http://observer.openchoreo.localhost:11080/mcp +``` + +Then, inside a Claude Code session, run `/mcp` to verify the servers are connected. Select a server and authenticate in the browser when prompted. + + + + +Add the following to `~/.cursor/mcp.json` (or via **Cursor Settings > Tools & Integrations > Add Custom MCP**): + +```json +{ + "mcpServers": { + "openchoreo-cp": { + "protocol": "http", + "url": "http://api.openchoreo.localhost:8080/mcp", + "auth": { + "CLIENT_ID": "user_mcp_client" + } + }, + "openchoreo-obs": { + "protocol": "http", + "url": "http://observer.openchoreo.localhost:11080/mcp", + "auth": { + "CLIENT_ID": "user_mcp_client" + } + } + } +} +``` + +On first use, a browser window opens for authentication. Log in with the default credentials above. + + + + +Add both MCP servers using the Gemini CLI. The CLI will automatically detect the OAuth 2.0 configuration from the server. + +```bash +gemini mcp add --transport http \ + openchoreo-cp http://api.openchoreo.localhost:8080/mcp + +gemini mcp add --transport http \ + openchoreo-obs http://observer.openchoreo.localhost:11080/mcp +``` + +On first use, a browser window opens for authentication. Log in with the default credentials above. Note that Gemini CLI uses `http://localhost:7777/oauth/callback` as its default redirect URI, so ensure it is added to your OAuth application's allowed redirect URIs. + + + + +Add the MCP server using the OpenCode CLI interactive wizard: + +```bash +opencode mcp add +``` + +When prompted, provide the following values: + +| Prompt | Value | +| -------------------------------------------------- | ------------------------------------------------------------------- | +| **Server name** | `openchoreo-cp` | +| **MCP server URL** | `http://api.openchoreo.localhost:8080/mcp` (or your MCP server URL) | +| **Does this server require OAuth authentication?** | `yes` | +| **Enter client ID** | `user_mcp_client` | +| **Do you have a client secret?** | `No` | + +Repeat the process for the observability server: + +```bash +opencode mcp add +``` + +| Prompt | Value | +| -------------------------------------------------- | ------------------------------------------------------------------------- | +| **Server name** | `openchoreo-obs` | +| **MCP server URL** | `http://observer.openchoreo.localhost:11080/mcp` (or your MCP server URL) | +| **Does this server require OAuth authentication?** | `yes` | +| **Enter client ID** | `user_mcp_client` | +| **Do you have a client secret?** | `No` | + +On first use, a browser window opens for authentication. Log in with the default credentials above. + + + + + + + +Client credentials authentication uses the `service_mcp_client` OAuth application (confidential client, client_credentials grant), which is pre-created in the default ThunderID IdP. This method works with any AI agent that supports custom HTTP headers. + +**Step 1: Obtain an Access Token** + +```bash +curl -s -X POST "http://thunder.openchoreo.localhost:8080/oauth2/token" \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -u 'service_mcp_client:service_mcp_client_secret' \ + -d 'grant_type=client_credentials' +``` + +The response contains an `access_token`: + +```json +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "token_type": "Bearer", + "expires_in": 3600 +} +``` + +Copy the `access_token` value and replace `` in the configuration below. + +**Step 2: Configure Your AI Agent** + + + + +```bash +claude mcp add --transport http \ + openchoreo-cp http://api.openchoreo.localhost:8080/mcp \ + --header "Authorization: Bearer " + +claude mcp add --transport http \ + openchoreo-obs http://observer.openchoreo.localhost:11080/mcp \ + --header "Authorization: Bearer " +``` + + + + +Set the access token as an environment variable: + +```bash +export OPENCHOREO_MCP_TOKEN="" +``` + +Then add the following to `~/.codex/config.toml`: + +```toml +[mcp_servers.openchoreo-cp] +url = "http://api.openchoreo.localhost:8080/mcp" +bearer_token_env_var = "OPENCHOREO_MCP_TOKEN" + +[mcp_servers.openchoreo-obs] +url = "http://observer.openchoreo.localhost:11080/mcp" +bearer_token_env_var = "OPENCHOREO_MCP_TOKEN" +``` + + + + +Add the following to `~/.cursor/mcp.json` (or via **Cursor Settings > Tools & Integrations > Add Custom MCP**): + +```json +{ + "mcpServers": { + "openchoreo-cp": { + "protocol": "http", + "url": "http://api.openchoreo.localhost:8080/mcp", + "headers": { + "Authorization": "Bearer " + } + }, + "openchoreo-obs": { + "protocol": "http", + "url": "http://observer.openchoreo.localhost:11080/mcp", + "headers": { + "Authorization": "Bearer " + } + } + } +} +``` + + + + +```bash +gemini mcp add --transport http \ + --header "Authorization: Bearer " \ + openchoreo-cp http://api.openchoreo.localhost:8080/mcp + +gemini mcp add --transport http \ + --header "Authorization: Bearer " \ + openchoreo-obs http://observer.openchoreo.localhost:11080/mcp +``` + + + + +Add the following to `~/.config/opencode/opencode.json`: + +```json +{ + "mcp": { + "openchoreo-cp": { + "type": "remote", + "url": "http://api.openchoreo.localhost:8080/mcp", + "headers": { + "Authorization": "Bearer " + } + }, + "openchoreo-obs": { + "type": "remote", + "url": "http://observer.openchoreo.localhost:11080/mcp", + "headers": { + "Authorization": "Bearer " + } + } + } +} +``` + + + + +Create a `.vscode/mcp.json` file in your workspace: + +```json +{ + "servers": { + "openchoreo-cp": { + "type": "http", + "url": "http://api.openchoreo.localhost:8080/mcp", + "headers": { + "Authorization": "Bearer " + } + }, + "openchoreo-obs": { + "type": "http", + "url": "http://observer.openchoreo.localhost:11080/mcp", + "headers": { + "Authorization": "Bearer " + } + } + } +} +``` + + + + +:::note Token Expiry +Access tokens expire (default: 1 hour). When your token expires, re-run the `curl` command from Step 1 to obtain a new token and update your AI agent configuration. +::: + + + + +:::tip To get the most out of MCP, pair it with skills +MCP gives your agent the **capabilities** to talk to OpenChoreo. **Skills** teach it how to use them well, so it gets it right first try instead of you correcting it along the way. You can stay in your agentic environment instead of jumping to the UI or CLI. To get started, install one (or both) of the skills below: + +- **[`openchoreo-developer`](https://openchoreo.dev/ecosystem/item/?id=skill-openchoreo-developer)**: daily developer tasks like deploying components, triggering builds, configuring workloads, promoting across environments, and troubleshooting. +- **[`openchoreo-platform-engineer`](https://openchoreo.dev/ecosystem/item/?id=skill-openchoreo-platform-engineer)**: daily platform engineering tasks like authoring ComponentTypes, Traits, and Workflows, setting up environments and pipelines, registering planes, and configuring identity and authorization. + +Browse [our ecosystem](https://openchoreo.dev/ecosystem/?group=skill) for all available skills. +::: + +## Advanced Configuration + +For custom AI agents, non-default IdP configurations, or custom OAuth application setups. + +### Creating a Custom OAuth Application + +If you need to create your own OAuth application (e.g., for a different IdP, custom redirect URIs, or non-default client settings), create an application in your IdP with one of the following configurations: + +**Client Credentials (Programmatic Access):** + +| Setting | Value | +| ----------------- | ------------------------- | +| **Grant Type** | `client_credentials` | +| **Client ID** | Your chosen client ID | +| **Client Secret** | Your chosen client secret | + +:::info Custom Role and Role Binding Required +Client credentials clients require a role binding to authorize access to OpenChoreo resources. See the [Custom Roles and Bindings](../platform-engineer-guide/authorization/custom-roles.mdx) guide for details on creating roles and role bindings via the UI. +::: + +**Authorization Code (Browser-Based Access):** + +| Setting | Value | +| ------------------------ | ------------------------------------------ | +| **Grant Types** | `authorization_code`, `refresh_token` | +| **Client ID** | Your chosen client ID | +| **Public Client (PKCE)** | `true` | +| **Redirect URIs** | Configure per your AI agent's callback URL | +| **Scopes** | `openid`, `profile`, `email` | + +:::note Redirect URIs +The redirect URI must match your AI agent's OAuth callback URL. Refer to your AI agent's MCP documentation for the correct callback URL and port. +::: + +### Configuring Non-Default Installations + +If your OpenChoreo installation uses a custom base domain or non-standard ports, refer to the [MCP Servers Reference](../reference/mcp-servers.mdx#finding-mcp-server-urls) for instructions on constructing the correct MCP server URLs. Replace the `openchoreo.localhost` URLs in the examples above with your actual MCP server URLs. diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/overview.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/overview.mdx new file mode 100644 index 00000000..b7eba19b --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/overview.mdx @@ -0,0 +1,38 @@ +--- +title: Working with AI +--- + +# Working with AI + +AI is reshaping how platform engineering teams build, operate, and troubleshoot software. OpenChoreo is built to meet that shift — with first-class AI integration that lets your developers and operators work alongside AI assistants naturally. Whether you're using Claude Code, Cursor, Gemini CLI, or another AI assistant, OpenChoreo gives it the context it needs to act. + +![](../resources/ai-overview-diagram.svg) + +## MCP Servers + +OpenChoreo exposes [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers for both the **Control Plane** and the **Observability Plane**. This means your AI assistant can: + +- **Discover and manage resources** — list namespaces, projects, components, environments, and deployment pipelines directly from a chat prompt +- **Trigger and monitor builds** — kick off workflow runs and check their status without leaving your editor +- **Query observability data** — fetch logs, metrics, traces, alerts, and incidents by asking questions in natural language +- **Deploy and promote** — update release bindings and promote components across environments through conversational workflows + +This turns your AI assistant into an active participant in your platform operations — not just a code suggester, but a collaborator that understands your infrastructure. + +See the [MCP Servers Reference](../reference/mcp-servers.mdx) for the full list of available tools and server configuration options, and follow [Configuring MCP Servers with AI Assistants](./mcp-servers.mdx) to connect your AI assistant to OpenChoreo. + +## Built-in Agents + +Beyond MCP, OpenChoreo ships with AI agents that run autonomously inside the platform. + +### FinOps Agent + +Cloud costs grow quietly until they become a problem. The **[FinOps Agent](./finops-agent.mdx)** analyzes Kubernetes resource usage of your OpenChoreo components and generates cost optimization reports with rightsizing recommendations. Instead of manually correlating utilization data, teams get clear, LLM-generated guidance on where spend can be reduced. + +### SRE Agent + +When something goes wrong in production, finding the root cause is expensive. The **[SRE Agent](./sre-agent.mdx)** automates that investigation by analyzing logs, metrics, and traces from your OpenChoreo deployments and generating a report with likely root causes. Instead of engineers spending hours correlating signals across dashboards, the SRE Agent delivers actionable insights the moment an alert fires. + +### Portal Assistant + +Platform context is scattered across CRDs, dashboards, and log stores — answering "what is this component doing?" often means jumping between five tools. The **[Portal Assistant](./portal-assistant.mdx)** is a read-only chat assistant embedded in Backstage that talks to the OpenChoreo and Observability MCP servers (and the SRE Agent when deployed) so your team can ask questions in natural language — list projects, inspect a component, query runtime logs, or pull an existing RCA report — without leaving the developer portal. The Portal Assistant is read-only by contract: it can list, get, and query, but never create, update, or delete. diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/portal-assistant.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/portal-assistant.mdx new file mode 100644 index 00000000..23c24a22 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/portal-assistant.mdx @@ -0,0 +1,262 @@ +--- +title: Portal Assistant +description: Configure the Portal Assistant in OpenChoreo for AI-powered chat over your platform and runtime telemetry. +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Portal Assistant + +The Portal Assistant is an AI-powered, chat assistant for OpenChoreo. The Portal Assistant is read-only by contract. It can list, get, and query — it cannot create, update, delete, or trigger anything. Write-style requests are politely declined. + +## Prerequisites + +Before enabling the Portal Assistant, ensure the following: + +- OpenChoreo Control Plane installed (this is where the Portal Assistant runs). +- OpenChoreo Observability Plane installed if you want runtime-debug answers (the Portal Assistant's "what's going wrong in my logs?" path calls the Observer MCP). +- Backstage deployed and reachable — the Portal Assistant is a backend; users interact with it through Backstage's chat drawer. +- An LLM API key from OpenAI (support for other providers coming soon) +- (Optional) The [SRE Agent](./sre-agent.mdx) deployed if you want Tier-2 deep analysis from inside a chat. + +:::note +The Portal Assistant streams responses over HTTP/ndjson and can issue several MCP tool calls per turn. Choose a model with reasonable streaming + tool-use quality (e.g. `openai:gpt-5`). +::: + +## Enabling the Portal Assistant + +### Step 1: Create the Portal Assistant Secret + +The Portal Assistant requires a Kubernetes Secret in the `openchoreo-control-plane` namespace with the following key: + +| Key | Description | +| ------------------------------ | ------------------------- | +| `PORTAL_ASSISTANT_LLM_API_KEY` | Your LLM provider API key | + +The Secret name is referenced from the chart via `portalAssistant.llm.secretName`, so pick any name (the deployment fails fast at install time if the value is unset). + +You can create this secret using any method you prefer. If you followed the [Try It Out on k3d locally](../getting-started/try-it-out/on-k3d-locally.mdx) guide: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/portal-assistant-llm-api-key value="" +``` + +```bash +kubectl apply -f - <" +``` + +### Step 2: Upgrade the Control Plane + +Enable the Portal Assistant and point it at your secret + model. The `--reuse-values` flag preserves your existing configuration. + + + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set portalAssistant.enabled=true \\ + --set portalAssistant.llm.secretName=portal-assistant-secret \\ + --set portalAssistant.llm.modelName=openai:gpt-5.4-mini`} + + +:::note Supported Models +Any `provider:model` string accepted by LangChain's `init_chat_model` works. Common picks: + +- `openai:gpt-5.4-mini` — lightweight, low-cost option for development and quick chats. +- `openai:gpt-5` — base model, good default for development. +- `openai:gpt-5.2-pro` — better tool-use reasoning, recommended for production. +- `openai:gpt-5.4` — latest, highest-quality option. + +The `gpt-5.6` series is not supported at the moment. Support is coming soon. +::: + +If your Observer or SRE Agent live outside the cluster, also point the Portal Assistant at them: + +```bash +--set portalAssistant.config.observerApiUrl=http://observer.example.com:8080 +--set portalAssistant.config.rcaAgentApiUrl=http://rca-agent.example.com:11080 +``` + +When `rcaAgentApiUrl` is empty, the Portal Assistant simply does not register the SRE Agent MCP — chat keeps working with just the OpenChoreo + Observability tools. + +### Step 3: Wire Backstage to call the Portal Assistant + +Backstage ships with the Portal Assistant chat drawer behind a feature flag. The control-plane chart exposes it as `backstage.features.assistant`: + + + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set backstage.features.assistant.enabled=true`} + + +| Value | Default | Notes | +| ------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `backstage.features.assistant.enabled` | `false` | Toggles the "Ask Portal Assistant" affordance on the Logs tab and the chat drawer. Renders as `OPENCHOREO_FEATURES_ASSISTANT_ENABLED`. | +| `backstage.features.assistant.portalAssistantUrl` | `http://portal-assistant.openchoreo-control-plane.svc.cluster.local:8080` | Cluster-internal Service URL the Backstage forwarder calls. Renders as `OPENCHOREO_PORTAL_ASSISTANT_URL`. | + +If the Portal Assistant runs in a different cluster or namespace, override the URL: + +```bash +--set backstage.features.assistant.portalAssistantUrl=http://portal-assistant.example.com:8080 +``` + +After this, restart the Backstage pod so the new env vars take effect: + +```bash +kubectl -n openchoreo-control-plane rollout restart deployment/backstage +``` + +### Step 4: Verify the installation + +Check that the Portal Assistant pod is running: + +```bash +kubectl get pods -n openchoreo-control-plane -l app.kubernetes.io/component=portal-assistant +``` + +Hit the health endpoint over a port-forward: + +```bash +kubectl -n openchoreo-control-plane port-forward svc/portal-assistant 8088:8080 & +curl -sf http://localhost:8088/health # {"status":"healthy"} +``` + +Open Backstage in a browser, navigate to any component's Logs tab, and you should see an "Ask Portal Assistant" affordance — click it to send your first chat. The drawer streams tokens as the model produces them. + +If the drawer never appears, the most common cause is the Backstage feature flag — check the running pod's env: + +```bash +kubectl -n openchoreo-control-plane get deployment backstage \ + -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \ + | grep -i 'assistant' +``` + +You should see both `OPENCHOREO_FEATURES_ASSISTANT_ENABLED=true` and `OPENCHOREO_PORTAL_ASSISTANT_URL=...`. + +### Where Portal Assistant appears in Backstage + +With the feature flag enabled, the Portal Assistant surfaces from two places in Backstage: + +- **Build page** — the Portal Assistant appears automatically when a component's latest build is failing, and is also available when you open any failed build run. The chat opens already scoped to that run, so you can ask about the failure without re-pasting context. +- **Logs page** — every log row has an Investigate button in its hover-action column. Clicking it opens the Portal Assistant scoped to that specific log line (with the surrounding trace, when present), so you can investigate the error without copy-pasting the line. + +
+Exposing the Portal Assistant externally via HTTPRoute + +By default, the Portal Assistant is only reachable in-cluster. To expose `/api/v1alpha1/portal-assistant/*` through the OpenChoreo Gateway, set a hostname: + +```bash +helm upgrade --install openchoreo-control-plane \ + oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \ + --namespace openchoreo-control-plane \ + --reuse-values \ + --set 'portalAssistant.http.hostnames[0]=portal-assistant.openchoreo.example.com' +``` + +The chart renders an `HTTPRoute` for `/chat` (with `backendRequest: 450s` to allow long LLM turns) and `/warmup`. A streaming `TrafficPolicy` (`streamIdle: 24h`, `request: 0s`) is also applied so the ndjson stream is not torn down mid-turn by the gateway. + +
+ +
+Authentication and Authorization (External IdP) + +By default, OpenChoreo configures ThunderID as the identity provider for the Portal Assistant with a pre-configured OAuth client (`openchoreo-backstage-client`) bound to the `backstage-catalog-reader` role — which is granted the `portal-assistant:invoke` action. Chat requests originate from Backstage with the end user's JWT; the Portal Assistant validates the JWT against the ThunderID JWKS and forwards it verbatim to the MCP servers, so the per-tool authorization is end-user scoped, not service-account scoped. + +If you are using an external identity provider, configure the JWKS / issuer / audience on the Portal Assistant via the standard control-plane security values: + +```yaml +security: + oidc: + jwksUrl: "" + issuer: "" + jwt: + audience: "" +``` + +For service accounts that need to call `/chat` programmatically (rather than via Backstage forwarding a user JWT), create an OAuth client that supports `client_credentials` and grant it the `portal-assistant:invoke` action: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: portal-assistant-service-binding + roleRef: + name: backstage-catalog-reader # or a dedicated role that has portal-assistant:invoke + entitlement: + claim: sub + value: "" + effect: allow +``` + +See [Identity Provider Configuration](../platform-engineer-guide/identity-configuration.mdx) for detailed setup. + +
+ +
+Tuning capacity and behaviour + +| Value | Default | What it does | +| -------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `portalAssistant.replicas` | `1` | Increase for HA / higher chat throughput. The Portal Assistant is stateless — adding replicas is safe. | +| `portalAssistant.config.maxConcurrentChats` | `20` | Per-pod concurrent-chat semaphore. Bound to your LLM provider's per-minute rate limit; raising it past your provider quota will surface as 429s. | +| `portalAssistant.config.authzTimeoutSeconds` | `30` | Hard timeout for the per-request authz check. | +| `portalAssistant.config.logLevel` | `INFO` | Set to `DEBUG` for verbose MCP / tool-call logging during incident investigation. | +| `portalAssistant.cors.allowedOrigins` | `[]` | Only relevant if you hit `/chat` directly from a browser bypassing the Backstage forwarder. | +| `portalAssistant.extraEnvs` | `[]` | Inject additional env vars without editing the chart. | + +
+ +
+Bring-your-own auth-config + +The Portal Assistant ships with a default `/app/auth-config.yaml` baked into the image that defines its action catalog (`portal-assistant:invoke`) and subject-type rules. To override, create a `ConfigMap` with your replacement file and point the chart at it: + +```bash +kubectl create configmap portal-assistant-auth-config \ + -n openchoreo-control-plane \ + --from-file=auth-config.yaml=./my-auth-config.yaml + +helm upgrade --install openchoreo-control-plane \ + oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \ + --namespace openchoreo-control-plane \ + --reuse-values \ + --set portalAssistant.authConfigConfigMap=portal-assistant-auth-config +``` + +The chart will mount the ConfigMap at `/etc/openchoreo/auth-config.yaml` and set `AUTH_CONFIG_PATH` accordingly. + +
diff --git a/versioned_docs/version-v1.2.0-rc.2/ai/sre-agent.mdx b/versioned_docs/version-v1.2.0-rc.2/ai/sre-agent.mdx new file mode 100644 index 00000000..73ad604a --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ai/sre-agent.mdx @@ -0,0 +1,196 @@ +--- +title: SRE Agent +description: Configure the SRE Agent in OpenChoreo for AI-powered root cause analysis. +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# SRE Agent + +The SRE Agent is an AI-powered component that performs root cause analysis (RCA) by analyzing logs, metrics, and traces from your OpenChoreo deployments to generate reports with likely root causes of issues. It integrates with Large Language Models (LLMs) to provide intelligent analysis and actionable insights. + +## Prerequisites + +Before enabling the SRE Agent, ensure the following: + +- OpenChoreo Observability Plane installed with at least a logs module. +- An LLM API key from [OpenAI](https://platform.openai.com/) (support for other providers coming soon) +- [Alerting configured](../platform-engineer-guide/observability-alerting.mdx#ai-powered-root-cause-analysis) for your components with `triggerAiRca` enabled. + +:::note +Enable automatic RCA only for critical alerts to manage LLM costs. +::: + +## Enabling the SRE Agent + +### Step 1: Create the SRE Agent Secret + +The SRE Agent requires a Kubernetes Secret named `rca-agent-secret` in the `openchoreo-observability-plane` namespace with the following keys: + +| Key | Description | +| --------------------- | -------------------------------------------------- | +| `RCA_LLM_API_KEY` | Your LLM provider API key | +| `OAUTH_CLIENT_SECRET` | OAuth client secret (only needed for external IdP) | + +You can create this secret using any method you prefer. If you followed the [Try It Out on k3d locally](../getting-started/try-it-out/on-k3d-locally.mdx) guide, you can follow along: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/rca-llm-api-key value="" +``` + +```bash +kubectl apply -f - < + {`helm upgrade --install openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --reuse-values \\ + --set rca.enabled=true \\ + --set rca.llm.modelName=`} + + +:::note Supported Models +The SRE Agent currently supports the [OpenAI](https://platform.openai.com/) GPT model series (e.g., `gpt-5.4`, `gpt-5.2-pro`, `gpt-5` etc.). Support for additional model providers is coming soon. + +The `gpt-5.6` series is not supported at the moment. Support is coming soon. +::: + +If the observability plane and control plane are in separate clusters, also set `rca.openchoreoApiUrl` to the control plane API URL (defaults to `http://api.openchoreo.localhost:8080`). + +### Step 3: Register with the control plane + +Configure `rcaAgentURL` in the `ClusterObservabilityPlane` resource so the UI knows where to reach the SRE Agent: + + + {`kubectl patch clusterobservabilityplane default --type=merge -p '{"spec":{"rcaAgentURL":"http://rca-agent.openchoreo.localhost:11080"}}'`} + + +### Step 4: Verify the installation + +Check that the SRE Agent pod is running: + +```bash +kubectl get pods -n openchoreo-observability-plane -l app.kubernetes.io/component=ai-rca-agent +``` + +If you are using the default identity provider (ThunderID) and the default SQLite report storage, your setup is complete. + +For a full, end-to-end walkthrough of setting up alerting with AI-powered root cause analysis, refer to the [URL Shortener sample](https://github.com/openchoreo/openchoreo/tree/main/samples/from-source/projects/url-shortener). + +
+Authentication and Authorization (External IdP) + +By default, OpenChoreo configures ThunderID as the identity provider for the SRE Agent with a pre-configured OAuth client for testing purposes. If you are using an external identity provider, follow the steps below. + +#### Authentication + +Create an OAuth 2.0 client that supports the `client_credentials` grant type for service-to-service authentication. + +Store your OAuth client secret in OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/rca-oauth-client-secret value="" +``` + +Then configure the Observability Plane Helm values with your client credentials: + +```yaml +security: + oidc: + tokenUrl: "" + +rca: + secretName: "rca-agent-secret" + oauth: + clientId: "" +``` + +See [Identity Provider Configuration](../platform-engineer-guide/identity-configuration.mdx) for detailed setup instructions. + +#### Authorization + +The SRE Agent uses the `client_credentials` grant to authenticate with the OpenChoreo API as a service account. The API matches the `sub` claim in the issued JWT to identify the caller, so the new client must be granted the `rca-agent` role via a bootstrap authorization mapping. + +Add the following to your Control Plane values override, replacing `` with the same client ID used above: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: rca-agent-binding + roleRef: + name: rca-agent + entitlement: + claim: sub + value: "" + effect: allow +``` + +
+ +
+Report Storage + +By default, RCA reports are stored in **SQLite** with a persistent volume — no external database required. + +For production deployments that need horizontal scaling or shared storage, you can use **PostgreSQL** instead. + +Store the PostgreSQL connection URI in OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/rca-sql-backend-uri value="postgresql+asyncpg://:@:/" +``` + +Add the `SQL_BACKEND_URI` key to the ExternalSecret from [Step 1](#step-1-create-the-sre-agent-secret): + +```bash +kubectl patch externalsecret rca-agent-secret -n openchoreo-observability-plane --type=json \ + -p '[{"op":"add","path":"/spec/data/-","value":{"secretKey":"SQL_BACKEND_URI","remoteRef":{"key":"rca-sql-backend-uri","property":"value"}}}]' +``` + +Then set the report backend in your Helm values: + +```yaml +rca: + reportBackend: postgresql +``` + +
diff --git a/versioned_docs/version-v1.2.0-rc.2/changelog.md b/versioned_docs/version-v1.2.0-rc.2/changelog.md new file mode 100644 index 00000000..5d71d9fa --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/changelog.md @@ -0,0 +1,48 @@ +--- +title: Changelog +description: Release history for OpenChoreo +--- + +# Changelog + +## v1.x Releases + +| Version | Date | Changelog | +| ----------- | ---------- | ----------------------------------------------------------------------------------------- | +| v1.2.0-rc.2 | 2026-07-23 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.2.0-rc.1...v1.2.0-rc.2) | +| v1.2.0-rc.1 | 2026-07-17 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.1.0...v1.2.0-rc.1) | +| v1.2.0-m.1 | 2026-06-12 | [Changelog](https://github.com/openchoreo/openchoreo/compare/v1.1.1...v1.2.0-m.1) | +| v1.1.3 | 2026-07-22 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.1/CHANGELOG.md#v113) | +| v1.1.2 | 2026-07-08 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.1/CHANGELOG.md#v112) | +| v1.1.1 | 2026-05-29 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.1/CHANGELOG.md#v111) | +| v1.1.0 | 2026-05-18 | [Changelog](https://github.com/openchoreo/openchoreo/blob/main/CHANGELOG.md#v110) | +| v1.0.3 | 2026-07-22 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.0/CHANGELOG.md#v103) | +| v1.0.2 | 2026-07-08 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.0/CHANGELOG.md#v102) | +| v1.0.1 | 2026-05-07 | [Changelog](https://github.com/openchoreo/openchoreo/blob/release-v1.0/CHANGELOG.md#v101) | +| v1.0.0 | 2026-03-22 | [Changelog](https://github.com/openchoreo/openchoreo/blob/main/CHANGELOG.md#v100) | +| v1.0.0-rc.2 | 2026-03-20 | [Changelog](https://github.com/openchoreo/openchoreo/blob/main/CHANGELOG.md#v100-rc2) | +| v1.0.0-rc.1 | 2026-03-15 | [Changelog](https://github.com/openchoreo/openchoreo/blob/main/CHANGELOG.md#v100-rc1) | + +## v0.x Releases + +| Version | Date | Release Notes | +| ------- | ---------- | ------------------------------------------------------------------------------ | +| v0.17.0 | 2026-03-05 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.17.0) | +| v0.16.0 | 2026-02-23 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.16.0) | +| v0.15.0 | 2026-02-17 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.15.0) | +| v0.14.0 | 2026-02-07 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.14.0) | +| v0.13.0 | 2026-01-30 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.13.0) | +| v0.12.0 | 2026-01-23 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.12.0) | +| v0.11.0 | 2026-01-16 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.11.0) | +| v0.10.0 | 2026-01-09 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.10.0) | +| v0.9.0 | 2025-12-23 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.9.0) | +| v0.8.0 | 2025-12-18 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.8.0) | +| v0.7.0 | 2025-12-08 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.7.0) | +| v0.6.0 | 2025-12-01 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.6.0) | +| v0.5.0 | 2025-11-23 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.5.0) | +| v0.4.0 | 2025-11-17 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.4.0) | +| v0.3.2 | 2025-09-18 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.3.2) | +| v0.3.1 | 2025-09-02 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.3.1) | +| v0.3.0 | 2025-07-31 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.3.0) | +| v0.2.0 | 2025-06-06 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.2.0) | +| v0.1.0 | 2025-03-20 | [Release Notes](https://github.com/openchoreo/openchoreo/releases/tag/v0.1.0) | diff --git a/versioned_docs/version-v1.2.0-rc.2/concepts/developer-abstractions.md b/versioned_docs/version-v1.2.0-rc.2/concepts/developer-abstractions.md new file mode 100644 index 00000000..1e39b786 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/concepts/developer-abstractions.md @@ -0,0 +1,160 @@ +--- +title: Developer Abstractions +description: Developer abstractions for building and running applications +--- + +# Developer Abstractions + +Developer abstractions in OpenChoreo enable teams to build, deploy, and operate cloud-native applications without +managing infrastructure complexity. These abstractions provide a declarative model for expressing application +architecture, dependencies, and operational requirements while the platform handles the underlying Kubernetes resources, +networking, and security configurations automatically. + +## Project + +A **Project** represents a bounded context in Domain-Driven Design terms - a cohesive collection of components that +together implement a specific business capability or application domain. It serves as the primary organizational unit +for developers, defining clear boundaries for code ownership, deployment coordination, and operational responsibility. + +Projects establish both logical and physical boundaries in the platform. Logically, they group related components that +share common business logic, data models, and team ownership. Physically, they translate into isolated deployment units +with dedicated namespaces, network boundaries, and security policies. This alignment between organizational structure +and technical architecture enables teams to work autonomously while maintaining clear integration points with other +projects. + +The project boundary also defines the scope for internal communication and shared resources. Components within a project +can communicate freely with each other. This locality principle reduces complexity for +developers while maintaining security and isolation between different application domains. + +## Component + +A **Component** represents a deployable unit of software - the fundamental building block of applications in OpenChoreo. +Each component encapsulates a specific piece of functionality, whether it's a microservice handling business logic, a +web application serving user interfaces, or a background job processing data. + +Components use a **ComponentType** reference to determine their deployment characteristics. This reference is a structured +object with `kind` and `name` fields, where `kind` specifies the resource type (`ComponentType` or `ClusterComponentType`, +defaulting to `ComponentType`) and `name` follows the `{workloadType}/{componentTypeName}` format, such as +`deployment/web-service` or `cronjob/data-processor`. The default platform setup provides ClusterComponentTypes that are +visible to all namespaces, so you should set `kind: ClusterComponentType` explicitly when referencing them. Namespace-scoped ComponentTypes can be used for isolation. This explicit typing allows +platform engineers to define multiple variations of deployment patterns for the same workload type, each tuned for +different use cases. + +The Component resource connects four essential elements: + +**ComponentType Reference** specifies which platform-defined template governs this component's deployment. The +ComponentType defines the available configuration schema, resource templates, and allowed workflows. This separation +of concerns means developers work with a simplified interface while platform engineers maintain control over +infrastructure patterns. + +**Parameters** provide the component-specific configuration values that conform to the schema defined in the +ComponentType. When a ComponentRelease is created, these parameter values are captured in the release snapshot. The +same values then apply wherever that release is deployed—if you deploy the same ComponentRelease to dev, staging, and +prod, the parameters are identical across all environments. To change parameter values, you update the Component and +create a new ComponentRelease. Environment-specific values (like resource limits or storage sizes) are handled +separately through `environmentConfigs` in ReleaseBinding resources. + +**Traits** enable composition of additional capabilities into the component. Each trait instance adds specific +functionality like persistent storage, caching, or monitoring. Traits can be instantiated multiple times with +different configurations using unique instance names. For example, a component might attach multiple persistent volume +traits for different storage needs, each with its own size, storage class, and mount configuration. Traits use the +same schema-driven approach as ComponentTypes, with parameters set in the Component and environment-specific overrides +applied through ReleaseBinding resources. + +**Workflow Configuration** optionally specifies how to build the component from source code. This references a +Workflow and provides the developer-configured schema values needed to execute builds. The workflow integration +enables automated container image creation triggered by code changes or manual developer actions. + +The component abstraction thus becomes a declarative specification that combines: + +- A ComponentType that defines _how_ to deploy +- Parameters that configure _what_ to deploy +- Traits that compose _additional capabilities_ +- A Workflow that defines _how to build_ + +This composition-based approach enables developers to assemble complex applications from reusable building blocks +while the platform ensures consistency, governance, and operational best practices through the underlying ComponentType +and Trait templates. + +## Workload + +A **Workload** defines the runtime contract of a component - specifying what the component needs to run. The workload +focuses on application requirements rather than infrastructure details, which are handled by the platform through ComponentTypes. + +Each component has one workload that describes its runtime needs through several key specifications: + +**Container** defines the container image to deploy, along with its commands, arguments, and environment variables. +This tells the platform what code to run and how to configure it. + +**Endpoints** specify the network interfaces that the component exposes - the ports and protocols it listens on. Each +endpoint declares its type (HTTP, gRPC, GraphQL, Websocket, TCP, or UDP) and port number. These definitions tell the +platform what network services the component provides, enabling automatic service creation and network policy generation. + +**Dependencies** declare the component's dependencies on other services and managed infrastructure. Endpoint +dependencies target endpoints exposed by other components: the platform resolves the +target address, injects it through environment variables, and configures network policies for the traffic. Resource +dependencies target a Resource in the same project: the outputs declared by the +referenced ResourceType are injected as environment variables or file mounts in +the consuming container. + +This declarative specification can be generated from configuration files in the source repository or applied directly +to the cluster. The separation between workload (what the application needs) and ComponentType (how the platform provides it) +enables platform teams to control infrastructure policies while developers focus on application requirements. Resource +limits, scaling parameters, and operational policies come from the ComponentType and Traits, while the +workload simply declares what the application needs to function. + +## Resource + +A **Resource** represents a managed-infrastructure dependency declared by a developer—a database, queue, cache, object +store, or any other piece of stateful infrastructure the application needs. A Resource is project-bound: it belongs to +exactly one Project, and the components in that project consume it through Workload dependencies. + +A Resource is a thin declaration. It references a **ResourceType** (or **ClusterResourceType**) by name, mirroring how +Components reference ComponentTypes. The Resource provides parameter values that conform to the ResourceType's +schema—such as database engine version, replica count, or storage size—and the platform handles provisioning through +the resource templates defined on the ResourceType. Developers do not write the provisioning logic; that lives in the +ResourceType authored by platform engineers. + +Each Resource is bound to environments through one **ResourceReleaseBinding** per environment. A binding selects a +specific **ResourceRelease**—an immutable snapshot of the Resource and ResourceType spec taken at release time—and +carries per-environment configuration overrides. + +Components consume Resource outputs through their Workload's dependencies. Each output declared by the ResourceType +can be mapped to an environment variable or a file mount inside the consuming container. Sensitive values remain on +the data plane: the consuming pod reads them from a Secret resolved at pod-start, and only the reference travels +through the control plane. + +The Resource abstraction follows the same separation of concerns as Components. Developers express what +infrastructure they need; platform engineers control how that infrastructure is provisioned, what defaults apply, and +which resource templates are available. + +## WorkflowRun + +A **WorkflowRun** represents a runtime execution instance of a Workflow. While Workflows define the automation template +and parameter schema, WorkflowRuns represent actual executions with specific parameter values. + +WorkflowRuns bridge the gap between developer intent and automation execution. Developers create WorkflowRun resources +to trigger workflows, providing parameter values. The platform handles all the complexity of rendering the final +workflow specification, resolving external references, synchronizing secrets, and managing execution in the workflow plane. + +Each WorkflowRun captures: + +**Workflow Reference and Parameters** specify which Workflow to execute and provide the developer-supplied parameter +values. These values are validated against the Workflow's parameter schema, which can include repository URLs, build +configuration, test modes, resource allocations, and any other fields the platform engineer has defined. + +**Component Ownership** (for CI workflows) is tracked through metadata labels (`openchoreo.dev/component` and +`openchoreo.dev/project`) that link the execution to a specific component and project. This enables traceability, +build history per component, and component-specific operations. These labels are accessible in the Workflow's CEL +expressions for injecting component context into the execution. + +**Execution Status** tracks the workflow through conditions (`WorkflowRunning`, `WorkflowCompleted`, +`WorkflowSucceeded`, `WorkflowFailed`), individual task status with a vendor-neutral step abstraction, timestamps, +and references to the actual workflow plane resources for debugging and cleanup. + +This abstraction provides a unified interface for both generic automation and component builds, where developers +interact with curated parameter schemas rather than complex CI/CD pipeline definitions. The separation of concerns +allows platform engineers to control workflow implementation and security policies through Workflow templates while +developers manage parameter values through WorkflowRun instances. WorkflowRuns can be created manually for ad-hoc +executions or automatically by platform controllers in response to code changes, supporting both interactive development +and fully automated CI/CD pipelines. diff --git a/versioned_docs/version-v1.2.0-rc.2/concepts/platform-abstractions.md b/versioned_docs/version-v1.2.0-rc.2/concepts/platform-abstractions.md new file mode 100644 index 00000000..3f1ee9f5 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/concepts/platform-abstractions.md @@ -0,0 +1,315 @@ +--- +title: Platform Abstractions +description: Platform abstractions for managing infrastructure +--- + +# Platform Abstractions + +Platform abstractions in OpenChoreo provide the foundational infrastructure layer that platform engineers use to build +and manage Internal Developer Platforms. These abstractions establish logical boundaries, manage infrastructure +resources, and define the operational policies that enable developer self-service while maintaining security and +compliance. + +## Namespace + +OpenChoreo uses Kubernetes namespaces to organize and isolate groups of related resources. By default, platform resources like ComponentTypes, Traits, Workflows, DataPlanes, and WorkflowPlanes are created as cluster-scoped resources (ClusterComponentType, ClusterTrait, ClusterWorkflow, ClusterDataPlane, ClusterWorkflowPlane, ClusterObservabilityPlane), making them automatically visible to all namespaces. This means any new namespace has access to them out of the box. Platform teams can create namespace-scoped variants when they need to customize or isolate resources for a particular namespace. Resources like Projects, Environments, and DeploymentPipelines remain namespace-scoped since they are inherently tied to a specific namespace context. + +OpenChoreo identifies and manages namespaces through a label (`openchoreo.dev/control-plane: true`). The control plane uses this label to discover namespaces, perform list/get operations, and organize platform resources. When an OpenChoreo cluster is created, the default namespace is automatically labeled with this identifier, enabling immediate platform resource creation. + +## Infrastructure Planes + +OpenChoreo separates infrastructure concerns into specialized planes, each serving a distinct purpose in the platform architecture. This separation enables independent scaling, security isolation, and operational management of different platform functions. + +### Control Plane + +The **Control Plane** is the Kubernetes cluster where OpenChoreo itself runs. It hosts the platform's custom resource definitions (CRDs), controllers, and the OpenChoreo API. Platform engineers interact with the control plane to define platform abstractions—ComponentTypes, Traits, Workflows, Environments, and more—and the controllers running here reconcile those resources into running workloads on the connected data planes. + +The control plane does not run application workloads directly. Instead, it orchestrates all other planes: rendering releases and applying them to DataPlanes, dispatching builds to WorkflowPlanes, and collecting observability signals from across the fleet. Because all platform state lives here, the control plane is the single source of truth for the entire OpenChoreo installation. + +### DataPlane + +A **DataPlane** represents a Kubernetes cluster where application workloads run. It abstracts the complexity of cluster +management, providing a unified interface for deploying applications across multiple clusters regardless of their +location or underlying infrastructure. + +DataPlanes encapsulate all the configuration needed to connect to and manage a Kubernetes cluster, including connection +credentials, TLS certificates, and cluster-specific settings. They enable platform teams to register multiple clusters - +whether on-premises, in public clouds, or at edge locations - and manage them through a single control plane. + +Each DataPlane can host multiple environments and projects, with OpenChoreo managing the creation of namespaces, network +policies, and other cluster resources automatically. This abstraction allows platform teams to treat clusters as +interchangeable infrastructure resources, enabling strategies like geographic distribution, compliance-based placement, +and disaster recovery. + +### WorkflowPlane + +A **WorkflowPlane** provides dedicated infrastructure for executing continuous integration and build workloads. By +separating build operations from runtime workloads, WorkflowPlanes ensure that resource-intensive compilation and testing +processes don't impact production applications. + +WorkflowPlanes integrate with Argo Workflows to provide a scalable, Kubernetes-native CI/CD execution environment. They +handle the complete build lifecycle, from source code retrieval through compilation, testing, and container image +creation. This separation also provides security benefits, isolating potentially untrusted build processes from +production environments. + +Platform engineers configure WorkflowPlanes with the necessary tools, credentials, and policies for building applications. +This includes container registry credentials, build tool configurations, and security scanning policies. WorkflowPlanes can +be scaled independently based on build demand and can be distributed geographically to reduce latency for development +teams. + +### Observability Plane + +The **Observability Plane** provides centralized infrastructure for collecting and analyzing logs, metrics, and traces +across all other planes - Control, Data, and Workflow - providing a unified view of platform operations and +application behavior. + +The Observability Plane uses a pluggable adapter-pattern, with OpenSearch as the default backend for logs and traces, +and Prometheus for metrics. The Observer API provides authenticated access to observability data, enabling integration +with external monitoring tools and dashboards. Module authors can swap in alternative backends by implementing the adapter API. + +Platform engineers can configure alerting rules to define conditions on logs and metrics, and route notifications via email or webhook. + +Platform engineers configure the Observability Plane during initial setup, establishing collection pipelines, +retention policies, and access controls. This centralized approach ensures that all platform activity is auditable and +debuggable while maintaining security boundaries between namespaces. + +## Environment + +An **Environment** represents a stage in the software delivery lifecycle, such as development, staging, or production. +Environments provide the context for deploying and running applications, defining the policies, configurations, and +constraints that apply to workloads in that stage. + +Environments are not just labels or namespaces - they are first-class abstractions that define where applications +should be deployed (which DataPlane) and serve as targets for deployment pipelines. This abstraction enables platform +teams to organize different stages of the delivery pipeline. + +Each environment represents a distinct deployment target. Development environments might target smaller clusters or +shared infrastructure, while production environments target dedicated, high-availability clusters. The Environment +resource primarily defines the mapping to infrastructure (DataPlane) and serves as a reference point for deployments +and promotion workflows. + +## DeploymentPipeline + +A **DeploymentPipeline** defines the allowed progression paths for applications moving through environments. It +represents the organization's software delivery process as a declarative configuration, encoding promotion rules and quality gates. + +DeploymentPipelines go beyond simple environment ordering to define complex promotion topologies. They can specify +parallel paths for different types of releases and conditional progressions based on application characteristics. +This flexibility allows organizations to implement sophisticated delivery strategies while maintaining governance and +control. + +The pipeline abstraction also serves as an integration point for organizational processes. Automated testing can be +triggered at promotion boundaries, and compliance checks can be enforced before production deployment. This ensures +that all applications follow organizational standards regardless of which team develops them. + +## ReleaseBinding + +A **ReleaseBinding** connects a ComponentRelease to a specific Environment. This is what actually deploys a release to +a data plane—but it's more than just a reference. + +ReleaseBinding provides a way to override configuration for a specific environment. Values defined in the ComponentType's +`environmentConfigs` and Trait's `environmentConfigs` can be customized per environment through the ReleaseBinding. +This is where environment-specific differences reside: scaling in production versus development, resource limits, +storage classes, and so on—while the ComponentRelease itself remains unchanged. + +Once a ReleaseBinding is created, the ReleaseBinding controller renders the ComponentType and Trait templates with the +combined configuration, generates the necessary Kubernetes resources (Deployments, Services, ConfigMaps, etc.), and +produces a **RenderedRelease** resource that is applied to the target plane. + +## ResourceReleaseBinding + +A **ResourceReleaseBinding** is the resource-side counterpart of ReleaseBinding. It pins a specific **ResourceRelease** +to an Environment and carries per-environment configuration overrides for the referenced ResourceType. This is where +settings like dev-vs-prod replica counts, storage sizes, or admin-UI enablement live—while the ResourceRelease +snapshot itself remains unchanged across environments. + +ResourceReleaseBindings are authored by platform engineers or GitOps tooling, not by the Resource controller. The +controller for the parent Resource never creates or modifies bindings on its own; this keeps developer-facing Resource +spec edits from triggering automatic redeploys. Promoting a release into an environment is always an explicit step. + +A binding can also override the ResourceType's retention policy for its environment, allowing production environments +to preserve underlying state (volumes, databases) on deletion while dev and staging defer to the type-level default. + +When a ResourceReleaseBinding is created, the binding controller renders the ResourceType template with the combined +Resource parameters and environment overrides, produces a RenderedRelease that is applied to the target plane, and +resolves the declared outputs so consuming workloads can read them. + +## Component Types + +A **ComponentType** is a platform engineer-defined template that governs how components are deployed and managed in +OpenChoreo. It represents the bridge between developer intent and platform governance, encoding organizational +policies, best practices, and infrastructure patterns as reusable templates. + +ComponentTypes separate developer intent from platform governance. While developers create Components +that express their application requirements, platform engineers define ComponentTypes that specify how those +requirements should be fulfilled. This separation enables developers to focus on application logic while platform +engineers maintain control over infrastructure policies, resource limits, security configurations, and operational +standards. + +OpenChoreo also provides **ClusterComponentType**, a cluster-scoped variant of ComponentType. The default platform setup uses ClusterComponentTypes so that all namespaces can reference them without duplication. Namespace-scoped ComponentTypes are available when platform engineers need to customize or override the defaults for a specific namespace. + +Each ComponentType (or ClusterComponentType) is built around a specific **workload type** - the primary Kubernetes +resource that will run the application. OpenChoreo supports four fundamental workload types: + +- **deployment**: For long-running services that need continuous availability +- **statefulset**: For applications requiring stable network identities and persistent storage +- **cronjob**: For scheduled tasks that run at specific times or intervals +- **job**: For one-off tasks that run to completion +- **proxy**: For proxy workloads that route traffic without running application containers + +The ComponentType uses a **schema-driven architecture** that defines what developers can configure when creating +components. This schema consists of two types of parameters: + +**Parameters** are configurations captured in the ComponentRelease and applied uniformly wherever that release is +deployed. These include settings like replica counts, image pull policies, and container ports. When you deploy the +same ComponentRelease to multiple environments, the parameter values are identical. To change parameters, you update +the Component and create a new ComponentRelease. + +**EnvironmentConfigs** are configurations that can be overridden on a per-environment basis through ReleaseBinding resources. +These typically include resource allocations, scaling limits, and environment-specific policies. This flexibility +allows platform engineers to provide generous resources in production while constraining development environments to +optimize infrastructure costs. + +The schema uses standard [OpenAPI v3 JSON Schema](https://swagger.io/specification/) format (`openAPIV3Schema`), making +configuration requirements explicit and self-documenting. For example, `type: integer` with `default: 1` declares an +integer parameter with a default value, while `type: string` with `enum: [Always, IfNotPresent, Never]` restricts a +string to specific allowed values. This format supports validation rules like minimum/maximum values, required fields, +and enumerated choices. + +ComponentTypes define **resource templates** that generate the actual Kubernetes resources for components. Each +template uses CEL (Common Expression Language) expressions to dynamically generate resource manifests based on +component specifications. Templates can access component metadata, schema parameters, and workload specifications +through predefined variables like `${metadata.name}` and `${parameters.replicas}`. + +Templates support advanced patterns through conditional inclusion and iteration. The `includeWhen` field uses CEL +expressions to conditionally create resources based on configuration, enabling optional features like autoscaling or +ingress. The `forEach` field generates multiple resources from lists, useful for creating ConfigMaps from multiple +configuration files or managing multiple service dependencies. + +ComponentTypes can also restrict which **Workflows** developers can use for building components through the +`allowedWorkflows` field. This enables platform engineers to enforce build standards, ensure security scanning, or +mandate specific build tools for different component types. For instance, a web application ComponentType might only +allow Workflows that use approved frontend build tools and security scanners. + +This schema-driven approach ensures consistency across the platform while providing flexibility for different +application patterns. Platform engineers create ComponentTypes that encode organizational knowledge about how to run +applications securely and efficiently, while developers benefit from simplified configuration and automatic compliance +with platform standards. + +## Traits + +A **Trait** is a platform engineer-defined template that augments components with operational behavior without modifying +the ComponentType. Traits enable composable, reusable capabilities that can be attached to any component—such as +persistent storage, autoscaling, network policies, or sidecar injection. + +Similar to ComponentTypes, OpenChoreo provides **ClusterTrait**, a cluster-scoped variant. The default platform setup uses ClusterTraits so that shared cross-cutting concerns are available to all namespaces. Namespace-scoped Traits can override or extend these defaults within a specific namespace. + +Traits use the same schema-driven approach as ComponentTypes, with `parameters` for static configuration and +`environmentConfigs` for environment-specific values. Developers attach Traits to their Components with instance-specific +parameters, while platform engineers can override environment-specific values through ReleaseBindings. + +Each Trait defines two types of operations: + +**Creates** generate new Kubernetes resources that don't exist in the base ComponentType. For example, a storage Trait +might create PersistentVolumeClaims, or a monitoring Trait might create ServiceMonitor resources. + +**Patches** modify existing resources generated by the ComponentType. Using JSON Patch operations with array filtering, +Traits can inject environment variables, add volume mounts, attach sidecar containers, or add labels and annotations +to existing resources. + +This separation between ComponentTypes (base deployment patterns) and Traits (composable capabilities) enables platform +engineers to define orthogonal concerns independently. Rather than creating separate ComponentTypes for every combination +of features, platform engineers define focused Traits that developers can mix and match as needed. + +## Resource Types + +A **ResourceType** is a platform engineer-defined template that governs how managed infrastructure is provisioned in +OpenChoreo. Where ComponentTypes describe how a code component is deployed, ResourceTypes describe how a Resource is +provisioned: what Kubernetes manifests the platform emits on the data plane, what parameters the developer can set, +what outputs (hostnames, credentials, connection URLs) the resulting infrastructure exposes to consumers, and what +retention behavior applies on deletion. + +OpenChoreo also provides **ClusterResourceType**, a cluster-scoped variant that is available across all namespaces. +Use ClusterResourceType for templates intended to be shared platform-wide and namespace-scoped ResourceType for +templates that are only relevant to a single namespace. + +ResourceTypes use the same schema-driven approach as ComponentTypes, with two schemas: + +**Parameters** capture developer-supplied values that become part of the immutable ResourceRelease snapshot—engine +version pin, schema name, replica count, anything that should stay identical across environments for a given release. +The schema is `openAPIV3Schema` with support for defaults, enums, validation, and CEL-based rules. + +**EnvironmentConfigs** capture per-environment overrides applied through ResourceReleaseBinding's +`resourceTypeEnvironmentConfigs`—storage size, request limits, dev-only admin UI toggles. The same ResourceRelease +deployed to dev and prod uses different environment overrides while the snapshot itself is unchanged. + +A ResourceType defines two further sections: + +**Resources** are the Kubernetes manifest templates the provisioner emits on the data plane—StatefulSets, Services, +Secrets, or third-party CRs like Crossplane claims. Each entry has a unique `id`, an optional `includeWhen` CEL +expression for conditional rendering, the manifest template, and an optional `readyWhen` CEL expression for per-Kind +health beyond the default heuristic. Templates have access to `metadata.*`, `parameters.*`, `environmentConfigs.*`, +and `dataplane.*` through the same CEL surface ComponentTypes use. + +**Outputs** declare the named values that consuming workloads bind to environment variables and file mounts. Each +output is one of three source kinds: a literal or CEL-rendered `value`, a `secretKeyRef` to a data-plane Secret, or a +`configMapKeyRef` to a data-plane ConfigMap. Output CEL has access to the same context as the resource templates plus +`applied..status.*` for reading fields populated by the provisioner. Sensitive material—passwords, tokens, private +keys—is declared with `secretKeyRef`; only the `{name, key}` reference transits to the control plane while the +underlying credential never leaves the data plane. + +The **`retainPolicy`** field on a ResourceType sets the default retention behavior for bindings of that type. The +default is `Delete`. Platform engineers opt into `Retain` for templates that emit non-recoverable state (production +databases, persistent volumes), and individual environments can still override the policy through the binding. + +## Workflow and ClusterWorkflow + +A **Workflow** is a platform engineer-defined template for running automation tasks in OpenChoreo. Workflows provide +a unified mechanism for both component builds and generic automation — infrastructure provisioning, data pipelines, +end-to-end testing, and more. + +OpenChoreo also provides **ClusterWorkflow**, a cluster-scoped variant of Workflow. While Workflows are +namespace-scoped and available only within their namespace, ClusterWorkflows are available across all namespaces. +This is useful when platform engineers want to define shared workflow templates once and allow WorkflowRuns in any +namespace to reference them, eliminating duplication. Because ClusterWorkflows are cluster-scoped, they can only +reference ClusterWorkflowPlanes (not namespace-scoped WorkflowPlanes) for their workflow operations. + +Each Workflow defines: + +**Parameter Schema** provides complete freedom for platform engineers to define developer-facing parameters. The schema +can include any structure — repository URLs, build version numbers, test modes, resource allocations, timeout settings, +and more. The schema supports all types including integers, booleans, strings, arrays, and nested objects, with full +validation through defaults, minimums, maximums, and enums. + +**Run Template** contains the actual Kubernetes resource specification (typically an Argo Workflow) with CEL template +variables for dynamic value injection. These expressions access context variables like `${metadata.workflowRunName}` +and `${metadata.namespaceName}` for runtime information, developer parameter values through `${parameters.*}` for +configuration, and resolved external references through `${externalRefs..spec.*}` for secret data. Platform +engineers can also hardcode platform-controlled parameters directly in the template, such as builder images, registry +URLs, and security scanning settings. + +**External References** declare references to external CRs (currently `SecretReference`) that are resolved at runtime +and injected into the CEL context. This enables secure access to credentials without embedding them in the Workflow +definition. + +**Resources** are additional Kubernetes resource templates (e.g., ExternalSecrets, ConfigMaps) created in the workflow +plane alongside the workflow run, with optional `includeWhen` conditions for conditional creation. + +Workflows can be triggered directly via WorkflowRun resources and are suitable for +tasks like infrastructure provisioning, data pipelines, scheduled jobs, and other automation that is not tied to a +specific component's build lifecycle. A Workflow becomes a **component workflow** when it is bound to a Component. +Component workflows carry the label `openchoreo.dev/workflow-type: "component"`, which identifies the workflow +as component-scoped and is used by developer tooling (e.g., `occ`) for categorization. To enable auto-build via +Git webhooks and UI integration, the Workflow's `openAPIV3Schema` uses vendor extensions +(e.g., `x-openchoreo-component-parameter-repository-url: true`, `x-openchoreo-component-parameter-repository-branch: true`) +to map schema fields to logical parameter keys. Component workflows must also be listed in a ComponentType's +`allowedWorkflows` field to be available for components. + +ComponentTypes govern which Workflows developers can use through the `allowedWorkflows` field. This enables platform +engineers to enforce build standards per component type, ensuring that web applications use approved frontend build +tools, backend services use appropriate security scanners, and different component types follow their specific build +requirements. + +Components reference Workflows in their `workflow` field, providing parameter values for build configuration. The +platform handles template rendering, external reference resolution, secret synchronization, and execution management +in the workflow plane, with WorkflowRun resources tracking individual executions. diff --git a/versioned_docs/version-v1.2.0-rc.2/concepts/resource-relationships.md b/versioned_docs/version-v1.2.0-rc.2/concepts/resource-relationships.md new file mode 100644 index 00000000..ef832746 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/concepts/resource-relationships.md @@ -0,0 +1,211 @@ +--- +title: Resource Relationships +description: How resources connect and interact within the platform +--- + +# Resource Relationships + +OpenChoreo's resources form a carefully designed hierarchy that balances flexibility with governance. Understanding how +these resources relate to each other is essential for designing applications, troubleshooting issues, and managing the +platform effectively. These relationships define ownership, inheritance, and dependencies throughout the system. + +## Ownership Hierarchy + +The ownership model in OpenChoreo follows a strict hierarchical structure where each resource has a clear parent and +defined scope. This hierarchy provides namespace isolation, access control boundaries, and lifecycle management. + +### Namespace-Scoped Resources + +OpenChoreo organizes most resources within **Namespaces**, which serve as containers for related platform and application resources. Namespace-scoped resources include DataPlanes, Environments, Projects, Components, and runtime resources generated by the platform. These resources are isolated within their namespace boundaries, leveraging Kubernetes RBAC and network policies to maintain security and access control. + +OpenChoreo also supports cluster-scoped resources that exist at the cluster level. This hybrid model enables both namespace-level isolation for team-specific resources and cluster-wide sharing of common platform infrastructure. + +### Project Ownership + +Within a namespace, **Projects** form the next level of ownership for application resources. Projects own both +**Components** and **Resources**, establishing team boundaries and application domains. This ownership relationship +means that components and resources cannot exist without a parent project, and deleting a project removes all its +components and resources. + +The project ownership boundary also defines the scope for internal communication and resource sharing. Components +within the same project can reference each other's endpoints directly and consume the project's Resources through +Workload dependencies. This locality enables teams to work efficiently within their domain while maintaining +isolation from other projects. + +### ComponentType + +**ComponentTypes** define platform-level templates that govern how components are deployed. Each ComponentType +specifies a workload type (deployment, statefulset, cronjob, job, or proxy) and provides a schema for configurable +parameters. Platform engineers create ComponentTypes that encode organizational policies, resource templates, and +operational best practices. + +ComponentTypes serve as the platform's contract for component deployment. They define what developers can configure +through parameter schemas, what resources will be created through resource templates, and which workflows are allowed +for building components. By centralizing these definitions in ComponentTypes, platform teams ensure consistency across +all applications while maintaining control over infrastructure patterns. + +### Component to ComponentType + +**Components** reference a ComponentType using the format `{workloadType}/{componentTypeName}`. This relationship +establishes which template governs the component's deployment. The component provides parameter values that conform to +the schema defined in the ComponentType, and these parameters are validated automatically. + +The component-to-ComponentType relationship is fundamental to OpenChoreo's governance model. Components cannot be +created without referencing a valid ComponentType, ensuring all deployments follow platform standards. This +relationship also determines which resource templates will be used to generate the actual Kubernetes resources. + +### Trait Composition + +**Traits** attach additional capabilities to components through composition. Each component can instantiate multiple +traits, such as persistent storage, caching, or monitoring. Traits use the same schema-driven approach as +ComponentTypes, with parameters that can be overridden per environment through ReleaseBinding resources. + +Traits maintain an independent lifecycle from components but are applied together during deployment. This separation +enables platform engineers to define reusable capabilities that can be composed into different component types. The +trait relationship provides flexibility while maintaining governance through schema validation. + +### Workflow Integration + +**Workflows** define build and automation templates that components can reference through their workflow configuration. +ComponentTypes can restrict which workflows are allowed, ensuring components use appropriate build strategies. This +relationship between components, ComponentTypes, and Workflows enables platform teams to enforce build standards and +security policies. + +When a component references a Workflow, it provides schema values that configure the workflow execution. The Workflow +template uses these values along with platform-controlled parameters to generate the actual CI/CD pipeline. This +separation enables developers to trigger builds with simple configuration while platform engineers maintain control +over build infrastructure and security. + +### Component to WorkflowRun + +Components trigger **WorkflowRuns** through their workflow configuration to build container images. Each WorkflowRun +represents an execution instance of a Workflow template with specific parameter values. WorkflowRuns maintain a +relationship back to their originating component and the specific commit that triggered them. + +This relationship provides complete traceability from running containers back to source code. Platform operators can +trace any container image to the WorkflowRun that built it, which links to the component and ultimately to the source +repository and commit. This traceability is essential for debugging, compliance, and security auditing. + +### ComponentRelease and ReleaseBinding + +A **ComponentRelease** is an immutable snapshot of a component at a specific point in time. It captures the Component, +its Workload configuration, the selected ComponentType, and any attached Traits into a single versioned resource. This +snapshot works like a lock file—preserving the exact state so that the release remains stable and repeatable, even if +the original resources are later updated. + +To deploy a ComponentRelease to an environment, you create a **ReleaseBinding**. This resource binds the release to a +specific environment and provides environment-specific overrides for ComponentType and Trait parameters. The +ReleaseBinding controller renders the final Kubernetes manifests and produces a **RenderedRelease** resource that is applied +to the target plane. + +This relationship chain—Component → ComponentRelease → ReleaseBinding → RenderedRelease—ensures complete governance while +enabling environment-specific customization. Because ComponentRelease is immutable, the same release can be promoted +across environments (dev → staging → prod) without drift. + +### Resource and ResourceType + +**ResourceTypes** define platform-level templates for managed infrastructure—databases, caches, queues, object stores. +Each ResourceType declares a parameter schema, the Kubernetes manifests the provisioner emits on the data plane, the +named outputs that consumers bind to, and a default retention policy. The cluster-scoped variant +**ClusterResourceType** is available across all namespaces. + +**Resources** reference a ResourceType (or ClusterResourceType) by name. The Resource provides parameter values that +conform to the referenced template's schema; validation failures surface on the Resource itself. The reference is +fixed at create time, so a Resource cannot be retargeted to a different template after it is created. + +The Resource-to-ResourceType relationship mirrors Component-to-ComponentType. Resources cannot be created without a +valid ResourceType reference, ensuring every Resource is governed by a template the platform team has approved. + +### ResourceRelease and ResourceReleaseBinding + +A **ResourceRelease** is an immutable snapshot of a Resource and its referenced ResourceType at a specific point in +time. When either input changes, a new ResourceRelease is cut; existing releases remain unchanged so the same +snapshot can be promoted to multiple environments without re-rendering. This mirrors how ComponentRelease works for +components. + +To deploy a ResourceRelease to an environment, a platform engineer or GitOps process creates a +**ResourceReleaseBinding**. The binding pins a specific ResourceRelease, targets an Environment, and provides +per-environment configuration overrides. The captured ResourceType template is rendered with the combined +configuration, producing a **RenderedRelease** that is applied to the target data plane, and the declared outputs +are resolved so consuming workloads can read them. + +The chain—Resource → ResourceRelease → ResourceReleaseBinding → RenderedRelease—is the resource-side parallel of the +Component chain. The Resource controller never authors bindings on its own; promoting a release into an environment +is always an explicit action by a platform engineer or GitOps tooling. This isolation keeps developer-facing Resource +spec edits from triggering automatic redeploys against stateful infrastructure. + +## Network Relationships + +Network relationships in OpenChoreo define how components communicate and expose functionality. These relationships +translate into concrete network policies, routing rules, and security configurations. + +### Endpoint Exposure + +**Endpoints** establish relationships between components and their network interfaces. A component can expose multiple +endpoints with different visibility scopes and protocols. These relationships define how the component can be accessed +and by whom. + +The endpoint relationship includes more than just network configuration. It establishes contracts about protocols, +expected behavior, and API compatibility. Other components can depend on these contracts, with the platform ensuring +that communication follows the declared patterns. + +### Dependencies + +**Dependencies** create explicit relationships from a Component to the things it consumes. A Workload declares +two kinds of dependency: + +**Endpoint dependencies** (`dependencies.endpoints[]`) target endpoints exposed by other components. The platform +resolves the target address, injects it into the consuming container through environment variables, and configures +network policies for the resulting traffic. + +**Resource dependencies** (`dependencies.resources[]`) target a Resource in the same project. The named outputs +declared by the referenced ResourceType—hostnames, ports, credentials, connection URLs—are bound to environment +variables or file mounts on the consuming container. Sensitive outputs are delivered through Kubernetes Secret +references; the underlying values never transit the control plane. + +Both forms of dependency make the consuming relationships explicit. The platform uses them for service discovery, +network policy generation, resource readiness gating, and to track which components depend on which endpoints and +Resources. + +## Environment Progression + +Environment relationships define how applications move through the delivery pipeline from development to production. +These relationships ensure consistent progression while maintaining appropriate governance. + +### Pipeline Definition + +**DeploymentPipelines** establish relationships between environments, defining allowed transitions and promotion rules. +These relationships create a directed graph of environment progression, potentially with multiple paths for different +scenarios. + +Pipeline relationships include more than just ordering. They define testing gates and promotion rules. These +relationships ensure that applications follow organizational processes while enabling automation where appropriate. + +## Lifecycle Dependencies + +Resource relationships in OpenChoreo include lifecycle dependencies that ensure proper initialization, updates, and +cleanup. + +### Creation Order + +Some resources must be created before others can exist. DataPlanes must be registered before environments can target +them. Projects must exist before components can be created within them. These relationships ensure that the platform +maintains consistency during resource creation. + +### Update Propagation + +When resources are updated, changes propagate through relationships to dependent resources. Updating a ComponentType +triggers reconciliation of all components that reference it, creating new ComponentReleases that capture the updated +template. Since ComponentReleases are immutable snapshots, existing deployments are not affected until a new release is deployed. + +### Deletion Cascades + +Resource relationships define deletion behavior. When a project is deleted, all its components and Resources are +removed. When a Component is deleted, its WorkflowRuns, ComponentReleases, ReleaseBindings, and RenderedReleases are +cleaned up. When a Resource is deleted, deletion is blocked while any ResourceReleaseBinding still references it; once +all bindings are gone, the owned ResourceReleases are removed. These cascading relationships ensure that resources are +properly cleaned up without leaving orphaned objects. + +The retention of the underlying data-plane state on a binding deletion is governed by the binding's retention policy. +Production environments can preserve volumes and databases on deletion while dev and staging dispose of them, the same +shape as Kubernetes PersistentVolume reclaim policy applied per binding. diff --git a/versioned_docs/version-v1.2.0-rc.2/concepts/runtime-model.md b/versioned_docs/version-v1.2.0-rc.2/concepts/runtime-model.md new file mode 100644 index 00000000..8ad5a2e8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/concepts/runtime-model.md @@ -0,0 +1,122 @@ +--- +title: Runtime Model +description: Runtime execution and deployment model +--- + +# Runtime Model + +The runtime model describes how OpenChoreo's abstractions transform into running systems. When developers declare +projects and components, the platform orchestrates a sophisticated runtime environment that provides isolation, +security, and observability. Understanding this transformation from declaration to execution helps teams design better +applications and troubleshoot issues effectively. + +## Cell Architecture + +At runtime, each **Project** transforms into a **Cell** - a secure, isolated runtime boundary that encapsulates all +components of an application domain. This transformation represents a fundamental principle of OpenChoreo: +organizational boundaries in code become physical boundaries in infrastructure. + +Cells provide complete isolation between different application domains. Each cell operates as an independent unit with +its own namespace, network policies, and security boundaries. Components within a cell can communicate freely using +cluster-local networking, but all communication across cell boundaries must flow through well-defined gateways. This +architecture ensures that failures, security breaches, or performance issues in one cell cannot directly impact others. + +The cell model aligns with microservices best practices and Domain-Driven Design principles. By mapping bounded contexts +to isolated runtime units, OpenChoreo ensures that architectural boundaries are enforced by infrastructure. This +alignment reduces the cognitive load on developers - the same mental model used for designing applications applies to +their runtime behavior. + +## Traffic Flow Patterns + +OpenChoreo implements a structured approach to network traffic through directional gateways, each serving a specific +purpose in the overall communication architecture. These patterns provide clarity about how data flows through the +system while enabling sophisticated security and routing policies. + +### Northbound Ingress + +Northbound ingress handles traffic entering cells from the public internet. This gateway serves as the entry point for +external users, customers, and third-party integrations accessing public APIs and web applications. The platform +automatically configures load balancing and TLS termination at this boundary. + +The northbound gateway translates friendly DNS names into internal service endpoints, handles HTTP routing based on +hostnames and paths, and enforces public-facing API policies. This abstraction means developers can focus on application +logic while the platform manages the complexities of internet-facing services. + +### Southbound Egress + +Southbound egress manages traffic leaving cells to reach external services on the internet. This gateway provides +controlled access to third-party APIs, cloud services, and external databases. By channeling all outbound traffic +through a managed gateway, the platform can enforce security policies, manage credentials, and provide observability for +external dependencies. + +The southbound gateway enables capabilities like egress filtering to prevent data exfiltration, credential injection for +authenticated external services, and circuit breaking for unreliable external dependencies. This controlled approach to +external communication reduces security risks while improving reliability. + +### Westbound Ingress + +Westbound ingress handles traffic from other parts of the organization entering the cell. This gateway manages internal +API consumption, service-to-service communication across projects, and administrative access. Unlike public northbound +traffic, westbound traffic comes from trusted sources within the organization but still requires authentication and +authorization. + +The westbound gateway enables internal service discovery, allowing components in other cells to locate and communicate +with services using logical names. It enforces organization-wide policies while allowing more permissive communication +than public interfaces. This balance enables productive development while maintaining security boundaries. + +### Eastbound Egress + +Eastbound egress manages traffic leaving the cell to reach other cells or internal services within the organization. +This gateway handles inter-project dependencies, shared service consumption, and platform service integration. By +managing internal outbound traffic, the platform can track dependencies, enforce quotas, and provide circuit breaking +between internal services. + +The eastbound gateway makes internal service dependencies explicit and observable. Teams can understand which other +projects they depend on, platform engineers can track usage patterns across the organization, and the system can prevent +cascading failures through circuit breaking and retry policies. + +## Network Security + +OpenChoreo manages network security through the cell architecture and gateway pattern. Communication within a cell is +allowed between components of the same project, while all cross-cell communication must flow through the defined +gateways. This provides security boundaries between different application domains. + +The platform uses Cilium for network policy enforcement and kgateway for ingress traffic management. Developers +declare their components' endpoints and dependencies in the workload specification, and the platform handles the +underlying network configuration. + +## Workload Execution + +When components deploy to a runtime environment, OpenChoreo orchestrates a complex series of transformations. The +abstract component definition combines with workload specifications, environment configurations, and platform policies +to produce concrete Kubernetes resources. + +The platform manages the complete lifecycle of these resources. It creates deployments with appropriate resource limits +and scaling parameters, configures services for network access and load balancing, injects configuration and secrets +from secure stores, and establishes health checks and readiness probes. This orchestration happens transparently - +developers see their components running while the platform manages the underlying complexity. + +Workload execution is environment-aware. The same component might run with different resource allocations, replica +counts, or configuration values in different environments. The platform manages these variations through the binding +system, where environment-specific bindings override default values from ComponentTypes, Traits, and workload specifications. + +Resources follow the same render-and-apply path. Each ResourceReleaseBinding renders its ResourceType template with +the combined Resource parameters and environment overrides, produces a RenderedRelease, and applies the resulting +manifests to the data plane. The provisioned outputs are resolved back to the binding so consuming components can read +them at pod-start. The render gate on the consuming Component waits for its declared Resource dependencies to be +Ready before producing its own RenderedRelease, so a component is not deployed until the infrastructure it depends on +is healthy. + +## Service Discovery and Load Balancing + +Service discovery uses standard Kubernetes DNS, allowing services to communicate using service names. Within a cell, +components can discover each other using simple service names. Across cells, services require routing through the +appropriate gateways. + +## Observability + +The runtime model includes centralized logs, metrics, and traces collected through the Observability Plane. Logs from all containers flow through the platform's collection pipeline configured in the Observability Plane, enriched with metadata about the source component, project, and environment. This enrichment enables queries across the entire platform while maintaining clear attribution of log entries to their sources. + +The Observer API provides access to these logs, metrics, and traces, allowing developers to search and analyze application behavior across environments. This centralized observability approach ensures that debugging information is always available without requiring additional configuration from developers. + +The platform also provides a centralized alerting and RCA (Root Cause Analysis) system through the Observability Plane. Developers can define alert rules in their components' traits, and the platform will automatically create alert rules in the Observability Plane. When an alert fires, incident creation and AI RCA can be triggered if they are enabled for that rule. diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/endpoints.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/endpoints.md new file mode 100644 index 00000000..d49118ac --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/endpoints.md @@ -0,0 +1,225 @@ +--- +title: Endpoint Dependencies +description: Learn how to define dependencies between components by consuming endpoints from other components +--- + +# Endpoint Dependencies + +Components in OpenChoreo can consume endpoints exposed by other components by declaring **endpoint dependencies** in their Workload. When a dependency is declared, the platform automatically: + +- Resolves the target component's endpoint address +- Injects connection details as environment variables into the consuming component's container +- Configures network policies to allow traffic between the components + +## Defining a Dependency + +Dependencies are defined in the `spec.dependencies.endpoints` array of a Workload. Each entry specifies which component endpoint to consume and how to inject the connection details: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: frontend-workload + namespace: default +spec: + owner: + projectName: my-project + componentName: frontend + container: + image: myregistry/frontend:v1.0.0 + endpoints: + http: + type: HTTP + port: 3000 + visibility: + - external + dependencies: + endpoints: + - component: backend-api + name: http + visibility: project + envBindings: + address: BACKEND_API_URL +``` + +In this example, the `frontend` component declares a dependency on the `backend-api` component's `http` endpoint. The platform resolves the endpoint address and injects it as the `BACKEND_API_URL` environment variable. + +## Dependency Fields + +| Field | Type | Required | Description | +| ------------- | ------ | -------- | ----------------------------------------------------------------------------- | +| `component` | string | Yes | Name of the target component | +| `name` | string | Yes | Name of the target endpoint on the component | +| `visibility` | string | Yes | Visibility level at which to consume the endpoint (`project` or `namespace`) | +| `project` | string | No | Target component's project name. Defaults to the same project as the consumer | +| `envBindings` | object | Yes | Maps connection details to environment variable names | + +### Environment Bindings + +The `envBindings` field controls which connection details are injected as environment variables: + +| Field | Type | Description | +| ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- | +| `address` | string | Env var name for the full connection string. For HTTP/HTTPS/WS/WSS: `scheme://host:port/basePath`. For gRPC/TCP/UDP: `host:port` | +| `host` | string | Env var name for just the hostname | +| `port` | string | Env var name for just the port number | +| `basePath` | string | Env var name for just the base path | + +You can specify any combination of these bindings. At minimum, `address` is the most commonly used. + +## Visibility + +The `visibility` field determines at which network scope the dependency is consumed. Only `project` and `namespace` are supported for dependencies: + +| Visibility | When to Use | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `project` | The target component is in the **same project**. Traffic stays within the project's data plane namespace. | +| `namespace` | The target component is in a **different project** but the same namespace. Requires the target endpoint to have `namespace` (or broader) visibility declared. | + +:::note +The target endpoint must have a visibility level that is equal to or broader than the dependency's visibility. For example, if you consume an endpoint at `namespace` visibility, the target endpoint must include `namespace` (or `internal` or `external`) in its visibility array. +::: + +## Same-Project Dependencies + +When both components are in the same project, use `project` visibility. The `project` field can be omitted since it defaults to the consumer's project: + +```yaml +dependencies: + endpoints: + - component: user-service + name: http + visibility: project + envBindings: + address: USER_SERVICE_URL +``` + +## Cross-Project Dependencies + +When the target component is in a different project, you must specify the `project` field and use `namespace` visibility: + +```yaml +dependencies: + endpoints: + - component: shared-auth-service + name: http + visibility: namespace + project: platform-services + envBindings: + address: AUTH_SERVICE_URL + host: AUTH_SERVICE_HOST + port: AUTH_SERVICE_PORT +``` + +For cross-project dependencies to work, the target component's endpoint must have `namespace` (or broader) visibility declared in its Workload: + +```yaml +# Target component's Workload (in the platform-services project) +spec: + endpoints: + http: + type: HTTP + port: 8080 + visibility: + - namespace # Required for cross-project access +``` + +If a cross-project dependency is failing with a connection refused error, verify that the target endpoint has the appropriate visibility level configured. + +## Multiple Dependencies + +A single Workload can declare up to 50 endpoint dependencies: + +```yaml +dependencies: + endpoints: + - component: user-service + name: http + visibility: project + envBindings: + address: USER_SERVICE_URL + - component: notification-service + name: grpc + visibility: project + envBindings: + address: NOTIFICATION_SERVICE_ADDR + - component: analytics-api + name: http + visibility: namespace + project: analytics + envBindings: + address: ANALYTICS_API_URL + basePath: ANALYTICS_API_BASE_PATH +``` + +## Complete Example + +Here is a full example with a `greeter-service` that depends on both a same-project component and a cross-project component: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: greeter-service + namespace: default +spec: + autoDeploy: true + componentType: + kind: ClusterComponentType + name: deployment/service + owner: + projectName: default +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: greeter-service-workload + namespace: default +spec: + owner: + projectName: default + componentName: greeter-service + container: + image: ghcr.io/openchoreo/samples/greeter-service:latest + args: + - --port + - "9090" + endpoints: + http: + type: HTTP + port: 9090 + visibility: + - external + dependencies: + endpoints: + - component: hello-world-service + name: http + visibility: project + envBindings: + address: HELLO_WORLD_SERVICE_URL + - component: bar-service + name: http + visibility: namespace + project: test-project + envBindings: + address: BAR_SERVICE_URL +``` + +After deployment, you can verify the injected environment variables by exec-ing into the pod: + +```bash +kubectl exec -n -- env | grep -E 'HELLO_WORLD|BAR_SERVICE' +``` + +You should see the resolved addresses: + +```text +HELLO_WORLD_SERVICE_URL=http://hello-world-service..svc.cluster.local:9090 +BAR_SERVICE_URL=http://bar-service..svc.cluster.local:9090 +``` + +## Related Resources + +- [Workload](../workload/overview.md) - How to define Workloads +- [Workload API Reference](../../reference/api/application/workload.md) - Full CRD specification +- [Component](../../reference/api/application/component.md) - Components that own workloads diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/resources.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/resources.md new file mode 100644 index 00000000..cf9f5db0 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/dependencies/resources.md @@ -0,0 +1,235 @@ +--- +title: Resource Dependencies +description: Learn how a Component consumes a project-bound Resource by binding its outputs to environment variables and file mounts +--- + +# Resource Dependencies + +Components in OpenChoreo consume managed infrastructure—databases, queues, caches, object stores—by declaring **resource dependencies** in their Workload. Each entry references a project-bound [Resource](../../concepts/developer-abstractions.md#resource) and wires the named outputs declared on the referenced ResourceType into the consuming container. + +When a resource dependency is declared, the platform automatically: + +- Resolves the active `ResourceReleaseBinding` for the consumer's environment and reads its `status.outputs` +- Gates the consumer's deployment until that binding reports `Ready` +- Injects the resolved outputs as container environment variables (`envBindings`) and file mounts (`fileBindings`) +- Keeps sensitive values on the data plane: only the underlying `{name, key}` reference to a Secret or ConfigMap transits the control plane + +## Defining a Dependency + +Resource dependencies are defined in the `spec.dependencies.resources` array of a Workload. Each entry references a Resource by name and picks which of its outputs to inject: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: doclet-document + namespace: default +spec: + owner: + projectName: doclet + componentName: doclet-document + container: + image: ghcr.io/openchoreo/samples/doclet-document:latest + dependencies: + resources: + - ref: doclet-postgres + envBindings: + host: DB_HOST + port: DB_PORT + username: DB_USER + password: DB_PASSWORD + database: DB_NAME +``` + +In this example, the `doclet-document` Workload declares a dependency on the `doclet-postgres` Resource (a Postgres database provisioned from a `ClusterResourceType`). The platform resolves five outputs—`host`, `port`, `username`, `password`, `database`—and injects each as the corresponding environment variable. The credential is delivered through a `valueFrom.secretKeyRef`; the container reads the actual value from the data-plane Secret at pod-start. + +## Dependency Fields + +| Field | Type | Required | Description | +| -------------- | ----------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ref` | string | Yes | Name of the target Resource. Must live in the same project as the consuming Component | +| `envBindings` | map[string]string | No | Maps a ResourceType output name (key) to a container environment variable name (value) | +| `fileBindings` | map[string]string | No | Maps a ResourceType output name (key) to a container mount path (value). The referenced output must be backed by `secretKeyRef` or `configMapKeyRef` | + +An entry must specify `ref` and at least one of `envBindings` or `fileBindings`. Outputs the ResourceType declares but the Workload does not list are ignored—each Workload picks only the outputs it actually needs. + +### Environment Bindings + +The `envBindings` map binds each output to an environment variable on the consuming container. The shape of the resulting `env` entry depends on the ResourceType output's source kind: + +| Output source kind | Resulting env var shape | +| ------------------ | ----------------------------------------------------------------------------------------------------- | +| `value` | Literal value: `env: [{name: DB_HOST, value: "postgres.doclet.svc.cluster.local"}]` | +| `secretKeyRef` | Secret reference: `env: [{name: DB_PASSWORD, valueFrom: {secretKeyRef: {name: ..., key: ...}}}]` | +| `configMapKeyRef` | ConfigMap reference: `env: [{name: APP_REGION, valueFrom: {configMapKeyRef: {name: ..., key: ...}}}]` | + +Sensitive outputs are declared as `secretKeyRef` on the ResourceType. Only the `{name, key}` reference transits the control plane; the underlying credential is never serialized to the consumer's `ReleaseBinding.status` or to the rendered `Deployment` manifest. + +### File Bindings + +The `fileBindings` map mounts each output into the consuming container's filesystem. The referenced output must be backed by `secretKeyRef` or `configMapKeyRef`—`value`-kind outputs cannot be file-mounted because there is no data-plane object to mount. + +```yaml +dependencies: + resources: + - ref: my-mtls-creds + fileBindings: + ca-bundle: /etc/ssl/certs/ca-bundle.pem + client-cert: /etc/ssl/certs/client.crt + client-key: /etc/ssl/private/client.key +``` + +The platform synthesizes one Volume per `(resource, output)` pair (deduplicated when the same output is referenced multiple times) and one VolumeMount per declared path. The container reads each file at the declared path; underlying Secret or ConfigMap updates propagate through the standard kubelet projection. + +## Multiple Dependencies + +A Workload can declare up to 50 resource dependencies. Each entry's `ref` must be unique within the Workload, and endpoint and resource dependencies can be declared together: + +```yaml +dependencies: + endpoints: + - component: doclet-collab + name: ws + visibility: project + envBindings: + address: COLLAB_URL + resources: + - ref: doclet-postgres + envBindings: + host: DB_HOST + port: DB_PORT + username: DB_USER + password: DB_PASSWORD + database: DB_NAME + - ref: doclet-nats + envBindings: + url: DOCLET_NATS_URL +``` + +The render gate waits for both endpoint and resource dependencies before proceeding. + +## Complete Example + +A full example: a `doclet-document` Component depending on a Postgres Resource for storage and a NATS Resource for pub/sub. + +The Component, Workload, and matching Resources: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: doclet-document + namespace: default +spec: + owner: + projectName: doclet + autoDeploy: true + componentType: + kind: ClusterComponentType + name: deployment/service +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: doclet-document + namespace: default +spec: + owner: + projectName: doclet + componentName: doclet-document + container: + image: ghcr.io/openchoreo/samples/doclet-document:latest + endpoints: + http: + type: HTTP + port: 8080 + visibility: [project] + dependencies: + resources: + - ref: doclet-postgres + envBindings: + host: DB_HOST + port: DB_PORT + username: DB_USER + password: DB_PASSWORD + database: DB_NAME + - ref: doclet-nats + envBindings: + url: DOCLET_NATS_URL +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-postgres + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ClusterResourceType + name: postgres + parameters: + database: doclet +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-nats + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ClusterResourceType + name: nats +``` + +And the `ResourceReleaseBinding` for the `development` environment (one per Resource per environment, authored by the platform engineer or GitOps tooling): + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: doclet-postgres-development + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-postgres + environment: development + resourceRelease: doclet-postgres-abc12345 # advanced via `occ resource promote` +``` + +After the bindings report `Ready` and the consuming Component is deployed, verify the injected variables from inside the pod: + +```bash +kubectl exec -n -- env | grep -E 'DB_|NATS' +``` + +The output shows the resolved connection details, with the password loaded from a Secret reference: + +```text +DB_HOST=postgres-doclet.openchoreo-dp-doclet-development.svc.cluster.local +DB_PORT=5432 +DB_USER=doclet +DB_NAME=doclet +DB_PASSWORD= +DOCLET_NATS_URL=nats://@nats-doclet.openchoreo-dp-doclet-development.svc.cluster.local:4222 +``` + +## Inspecting Outputs on the Binding + +To inspect the resolved outputs without deploying a consumer, view the `ResourceReleaseBinding.status.outputs` directly: + +```bash +kubectl get resourcereleasebinding doclet-postgres-development -o yaml +``` + +Each entry in `status.outputs[]` carries the output name and one of `value`, `secretKeyRef`, or `configMapKeyRef`. For credential outputs, only the Secret name and key are shown—the actual value never appears here, matching the shape that lands in the consuming pod. + +## Related Resources + +- [Workload](../workload/overview.md) - How to define Workloads +- [Endpoint Dependencies](./endpoints.md) - Consuming endpoints exposed by other components +- [Resource concept](../../concepts/developer-abstractions.md#resource) - Overview of the Resource abstraction +- [Workload API Reference](../../reference/api/application/workload.md) - Full Workload CRD specification diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/deploy-and-promote.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/deploy-and-promote.md new file mode 100644 index 00000000..f10757ed --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/deploy-and-promote.md @@ -0,0 +1,79 @@ +--- +title: Deploy and Promote +description: Deploy components to environments and promote across the deployment pipeline +--- + +# Deploy and Promote + +## Deploy to the First Environment + +### Via Backstage UI + +1. Navigate to your Component in the Backstage console +2. Go to the **Deploy** tab +3. The first environment card shows your deployment status + +For components with `autoDeploy: true`, the deployment happens automatically when the Component and Workload are created. For manual deployment, use the CLI or configure overrides through the environment card settings. + +### Via CLI + +Deploy the latest release to the root (first) environment: + +```bash +occ component deploy my-service --namespace default --project default +``` + +Deploy a specific release: + +```bash +occ component deploy my-service --release my-service-5d7f658d9c +``` + +## Promote to the Next Environment + +Promotion moves a deployment from one environment to the next in the pipeline (e.g., development to staging). + +### Via Backstage UI + +1. On the **Deploy** tab, find the environment card for the deployed environment +2. Click the **Promote** button +3. The deployment promotes to the next environment in the pipeline + +### Via CLI + +```bash +# Promote to staging +occ component deploy my-service --to staging + +# Promote to production +occ component deploy my-service --to production +``` + +## View Deployment Status + +### Via Backstage UI + +The **Deploy** tab shows: + +- Deployment status per environment (Ready, NotReady, Failed) +- Last deployed timestamp +- Container image reference +- Release name +- Endpoint URLs + +Click **View K8s Artifacts** on an environment card to see the full resource tree, including Deployments, Pods, Services, and HTTPRoutes. + +### Via CLI + +```bash +# Check ReleaseBinding status +occ releasebinding list --namespace default --project default --component my-service + +# Check component status +occ component get my-service --namespace default +``` + +## What's Next + +- [Environment Overrides](./environment-overrides.md): customize configuration per environment +- [Logs and Troubleshooting](./logs-and-troubleshooting.md): view runtime logs and manage deployments diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/environment-overrides.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/environment-overrides.md new file mode 100644 index 00000000..2370c645 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/environment-overrides.md @@ -0,0 +1,105 @@ +--- +title: Environment Overrides +description: Customize component configuration per environment using overrides +--- + +# Environment Overrides + +The same ComponentRelease is deployed to all environments, but each environment can have different configuration. Environment overrides let you customize parameters, trait settings, and workload configuration per environment without creating separate releases. + +## Types of Overrides + +| Override Type | What It Configures | Example | +| --------------------------------- | ----------------------------- | ---------------------------------- | +| `componentTypeEnvironmentConfigs` | ComponentType parameters | Replicas, resource limits, port | +| `traitEnvironmentConfigs` | Trait parameters per instance | Alert thresholds, storage class | +| `workloadOverrides` | Workload-level settings | Environment variables, file mounts | + +## Configuring Overrides via Backstage UI + +1. Navigate to your Component's **Deploy** tab +2. Click the **gear icon** on an environment card header +3. The Overrides page shows tabs for: + - **Workload**: edit environment variables, file mounts, and endpoints + - **Component**: edit parameters defined by the ComponentType schema + - **Traits**: edit parameters for each attached trait instance + +## Configuring Overrides via CLI + +Use `--set` with `occ component deploy` to apply overrides during deployment or promotion: + +```bash +# Set replicas for production +occ component deploy my-service --to production \ + --set spec.componentTypeEnvironmentConfigs.replicas=3 + +# Set resource limits +occ component deploy my-service --to production \ + --set spec.componentTypeEnvironmentConfigs.resources.requests.cpu=500m \ + --set spec.componentTypeEnvironmentConfigs.resources.requests.memory=512Mi +``` + +The `--set` flag uses dot-notation paths to target specific fields in the ReleaseBinding spec. + +## Configuring Overrides via YAML + +You can also create or edit a ReleaseBinding directly: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + environment: production + releaseName: my-service-5d7f658d9c + state: Active + componentTypeEnvironmentConfigs: + replicas: 3 + resources: + requests: + cpu: "500m" + memory: "512Mi" + traitEnvironmentConfigs: + high-error-rate: + enabled: true + threshold: 50 +``` + +## Common Override Patterns + +### Different replicas per environment + +```bash +# Development: 1 replica +occ component deploy my-service --set spec.componentTypeEnvironmentConfigs.replicas=1 + +# Production: 3 replicas +occ component deploy my-service --to production \ + --set spec.componentTypeEnvironmentConfigs.replicas=3 +``` + +### Environment-specific environment variables + +Environment variables can be overridden at the workload level: + +```bash +occ component deploy my-service --to production \ + --set spec.workloadOverrides.env.LOG_LEVEL=warn +``` + +### Disable a trait in development + +```bash +occ component deploy my-service \ + --set spec.traitEnvironmentConfigs.high-error-rate.enabled=false +``` + +## What's Next + +- [Logs and Troubleshooting](./logs-and-troubleshooting.md): view runtime logs and manage deployments +- [ReleaseBinding API Reference](../../reference/api/platform/releasebinding.md): full spec for ReleaseBinding overrides diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/logs-and-troubleshooting.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/logs-and-troubleshooting.md new file mode 100644 index 00000000..e486ca2e --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/logs-and-troubleshooting.md @@ -0,0 +1,108 @@ +--- +title: Logs and Troubleshooting +description: View runtime logs and manage deployments in OpenChoreo +--- + +# Logs and Troubleshooting + +## Runtime Logs + +### Via Backstage UI + +1. Navigate to your Component +2. Click the **Logs** tab to search and filter logs by environment, time range, and keywords + +When the observability plane is configured, additional tabs are available: + +- **Metrics**: view metric graphs for your component +- **Alerts**: view triggered alerts + +### Via CLI + +```bash +# Get recent logs +occ component logs my-service --namespace default --project default + +# Follow logs in real-time +occ component logs my-service -f + +# Logs from a specific environment +occ component logs my-service --env production + +# Last 100 lines +occ component logs my-service --tail 100 + +# Logs since a specific time +occ component logs my-service --since 1h +``` + +## Viewing Kubernetes Resources + +### Via Backstage UI + +Click **View K8s Artifacts** on any environment card to see the resource tree: + +- Deployments and ReplicaSets +- Pods (with status and events) +- Services +- HTTPRoutes +- Kubernetes events + +This view helps diagnose issues like pod crashes, image pull errors, or routing problems. + +### Via CLI + +```bash +# Check the underlying deployment +kubectl get deployment -A -l openchoreo.dev/component=my-service + +# Check pod status +kubectl get pods -A -l openchoreo.dev/component=my-service + +# View pod logs directly +kubectl logs -l openchoreo.dev/component=my-service -n + +# Check events +kubectl get events -A --field-selector involvedObject.name=my-service +``` + +## Undeploy and Redeploy + +### Undeploy + +Undeploying removes the running workload from an environment without deleting the ReleaseBinding. This lets you redeploy later without reconfiguring. + +In the Backstage UI, click **Undeploy** on the environment card. + +### Redeploy + +To restore an undeployed component, click **Redeploy** on the environment card. This reactivates the existing ReleaseBinding. + +## Rollback + +To roll back to a previous release, deploy an older ComponentRelease by name: + +```bash +# List available releases +occ componentrelease list --namespace default --project default --component my-service + +# Deploy a specific older release +occ component deploy my-service --release my-service-a1b2c3d4e5 +``` + +This creates a new ReleaseBinding pointing to the older release, effectively rolling back the deployment. + +## Common Issues + +| Symptom | Possible Cause | What to Check | +| ----------------------------- | ---------------------------------------------- | -------------------------------------------------------- | +| Component stuck in "NotReady" | Data plane connectivity | Check ClusterAgent pod logs in the data plane | +| Pods in CrashLoopBackOff | Application error | Check pod logs via Backstage or `kubectl logs` | +| Image pull error | Wrong image reference or missing credentials | Verify container image URL and registry access | +| No endpoints accessible | HTTPRoute not created or gateway misconfigured | Check `kubectl get httproute -A` and gateway pod logs | +| Deployment not appearing | ReleaseBinding not created | Check `occ releasebinding list` and Component conditions | + +## What's Next + +- [Deploy and Promote](./deploy-and-promote.md): deploy and promote across environments +- [Environment Overrides](./environment-overrides.md): customize configuration per environment diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/overview.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/overview.md new file mode 100644 index 00000000..2518ee46 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/deploying-applications/overview.md @@ -0,0 +1,49 @@ +--- +title: Overview +description: Understand how OpenChoreo deploys your components across environments +--- + +# Deploying Applications + +OpenChoreo deploys your components through a chain of resources that separate what you want to deploy from where and how it gets deployed. This model enables reliable rollbacks, environment-specific configuration, and controlled promotion across environments. + +## How Deployment Works + +When you create a Component and Workload, OpenChoreo creates a deployment chain: + +```mermaid +flowchart TD + A["Component + Workload"] --> B["ComponentRelease
(immutable snapshot)"] + B --> C["ReleaseBinding
(per environment)"] + C --> D["Deployment + Service + HTTPRoute
(on data plane)"] +``` + +- **ComponentRelease**: an immutable snapshot that freezes your Component's configuration, including the ComponentType spec, Traits, parameters, and Workload. A new release is only created when something changes. +- **ReleaseBinding**: binds a ComponentRelease to a specific environment (e.g., development, staging, production). This is where environment-specific overrides are applied. +- **Kubernetes resources**: the ReleaseBinding produces the final Deployment, Service, and HTTPRoute resources on the data plane. + +## Deployment Pipeline + +Each Project references a DeploymentPipeline that defines the promotion order between environments. For example, the default pipeline promotes through: + +```text +development → staging → production +``` + +When you deploy a component, it goes to the first environment in the pipeline. You then promote it to subsequent environments either manually or automatically. + +## autoDeploy + +When `autoDeploy: true` is set on a Component, OpenChoreo automatically creates a ReleaseBinding for the first environment in the deployment pipeline whenever a new ComponentRelease is created. This means: + +- Creating a Component with `autoDeploy: true` deploys it to the first environment immediately +- Updating the Workload creates a new release and deploys it automatically +- You still need to promote to subsequent environments manually or via GitOps + +Without `autoDeploy`, you deploy manually using the CLI or Backstage UI. + +## What's Next + +- [Deploy and Promote](./deploy-and-promote.md): deploy to environments and promote across the pipeline +- [Environment Overrides](./environment-overrides.md): configure environment-specific parameters +- [Logs and Troubleshooting](./logs-and-troubleshooting.md): view logs and manage deployments diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-component.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-component.md new file mode 100644 index 00000000..f5432a5c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-component.md @@ -0,0 +1,246 @@ +--- +title: Creating a Component +description: Create and configure components for deployment in OpenChoreo +--- + +# Creating a Component + +A Component is a single deployable unit within a Project. It references a platform-defined ComponentType template that determines how it gets deployed, and optionally includes workflow configuration for building from source code. + +## Choosing a ComponentType + +Before creating a component, check which ComponentTypes are available. ComponentTypes are defined by platform engineers and determine the workload type (Deployment, StatefulSet, CronJob, etc.) and default configuration. + +```bash +# List cluster-scoped ComponentTypes (available to all namespaces) +occ clustercomponenttype list + +# List namespace-scoped ComponentTypes +occ componenttype list --namespace default +``` + +Common built-in ComponentTypes: + +| Component Type Reference | Workload Type | Use Case | +| ---------------------------- | ------------- | -------------------------------------------- | +| `deployment/service` | Deployment | Backend services and APIs | +| `deployment/web-application` | Deployment | Frontend or full-stack web apps | +| `deployment/worker` | Deployment | Background workers without exposed endpoints | +| `cronjob/scheduled-task` | CronJob | Periodic batch jobs | + +The reference format is `{workloadType}/{componentTypeName}`. This is used in the Component's `spec.componentType.name` field. + +## Creating via Backstage UI + +The Backstage UI provides a 3-step wizard for creating components. + +### Step 1: Component Metadata + +- Select your **Namespace** and **Project** +- Enter a **Component Name** (must be a valid Kubernetes name) +- Optionally add a **Display Name** and **Description** + +### Step 2: Build & Deploy + +Choose how your component gets its container image: + +**Build from Source**: OpenChoreo builds your code using a workflow + +- Select a **Workflow** from the available build workflows +- Enter your **Git Repository URL**, **Branch**, and **Application Path** +- Optionally select a **Git Secret** for private repositories + +**Container Image**: Deploy a pre-built image directly + +- Enter the **Container Image** reference (e.g., `ghcr.io/myorg/myapp:v1.0.0`) +- Toggle **Auto Deploy** to deploy automatically + +**External CI**: Use your existing CI system (Jenkins, GitHub Actions, GitLab CI) + +- Select your **CI Platform** +- Enter the platform-specific identifier (job path, repo slug, or project ID) + +### Step 3: Type-Specific Details + +This step is dynamically generated from the selected ComponentType (e.g., "Service Details", "Web Application Details"): + +- **Parameters**: configure values defined by the ComponentType schema (e.g., replicas, port, resource limits) +- **Endpoints**: define HTTP, gRPC, or WebSocket endpoints your service exposes (for deployment workload types) +- **Environment Variables**: set key-value pairs or reference secrets (available for container image deployments) +- **File Mounts**: mount configuration files into the container (available for container image deployments) +- **Traits**: attach reusable cross-cutting concerns from the platform's available traits + +Click **Create** to finish. + +:::note +For "Build from Source" deployments, environment variables and file mounts are configured via a [`workload.yaml` descriptor](../workflows/ci/workload-descriptor.md) in your source repository rather than in the wizard. +::: + +## Creating via YAML + +### Scaffolding with occ CLI + +The `occ component scaffold` command generates a Component YAML from a ComponentType, pre-filling defaults and documenting available fields: + +```bash +# Generate from a ClusterComponentType +occ component scaffold my-service \ + --clustercomponenttype deployment/service \ + --namespace default \ + --project default \ + -o my-service.yaml + +# Include traits +occ component scaffold my-service \ + --clustercomponenttype deployment/service \ + --clustertraits observability-alert-rule \ + -o my-service.yaml + +# Include a workflow for building from source +occ component scaffold my-service \ + --clustercomponenttype deployment/service \ + --clusterworkflow dockerfile-builder \ + -o my-service.yaml + +# Minimal output without comments +occ component scaffold my-service \ + --clustercomponenttype deployment/service \ + --skip-comments --skip-optional +``` + +Edit the generated file to fill in your values, then apply it. + +### From a Pre-built Image + +Create a Component and Workload together: + +```yaml +# component.yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: greeter-service + namespace: default +spec: + owner: + projectName: default + componentType: + kind: ClusterComponentType + name: deployment/service + autoDeploy: true + +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: greeter-service-workload + namespace: default +spec: + owner: + projectName: default + componentName: greeter-service + container: + image: "ghcr.io/openchoreo/samples/greeter-service:latest" + env: + - key: LOG_LEVEL + value: "info" + endpoints: + http: + type: HTTP + port: 9090 + visibility: [external] +``` + +```bash +kubectl apply -f component.yaml +``` + +:::tip +The `componentType.kind` defaults to `ComponentType` (namespace-scoped) if omitted. Since the built-in types are `ClusterComponentType` (cluster-scoped), always specify `kind: ClusterComponentType` explicitly. The same applies to traits (`kind` defaults to `Trait`, so specify `kind: ClusterTrait` for cluster-scoped traits). Workflows default to `ClusterWorkflow`, so omitting `kind` is fine for cluster-scoped workflows. +::: + +### From Source Code + +Create a Component with workflow configuration: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service + namespace: default +spec: + owner: + projectName: default + componentType: + kind: ClusterComponentType + name: deployment/service + autoDeploy: true + autoBuild: true + workflow: + kind: ClusterWorkflow + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/myorg/my-service" + revision: + branch: "main" + appPath: "/" + docker: + context: "." + filePath: "./Dockerfile" +``` + +```bash +kubectl apply -f component.yaml +``` + +The workflow builds the container image and creates a Workload automatically. If `autoBuild` is enabled, subsequent Git pushes trigger new builds via webhooks. + +## Adding Traits + +Traits are reusable extensions that add cross-cutting functionality to your component. Add them to the `traits` array: + +```yaml +spec: + traits: + - kind: ClusterTrait + name: observability-alert-rule + instanceName: high-error-rate + parameters: + enabled: true + condition: "error_count > 100" +``` + +Each trait instance needs a unique `instanceName` within the component. List available traits: + +```bash +occ clustertrait list +occ trait list --namespace default +``` + +## Managing Components + +### List components + +```bash +occ component list --namespace default --project default +``` + +### View component details + +```bash +occ component get greeter-service --namespace default +``` + +### Delete a component + +```bash +occ component delete greeter-service --namespace default +``` + +## What's Next + +- [Define Your Workload](../workload/overview.md): learn more about workload specifications +- [Build Your Code](../workflows/ci/overview.md): configure CI workflows and auto-build +- [Workload Descriptor](../workflows/ci/workload-descriptor.md): customize what your CI build produces diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-project.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-project.md new file mode 100644 index 00000000..02e803b6 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/creating-a-project.md @@ -0,0 +1,100 @@ +--- +title: Creating a Project +description: Set up a project to organize your components in OpenChoreo +--- + +# Creating a Project + +A Project is a logical boundary that groups related components together. Each project is linked to a deployment pipeline that defines how components are promoted across environments (e.g., development, staging, production). + +## What a Project Defines + +A Project resource is intentionally minimal: + +| Field | Description | +| ---------------------------- | --------------------------------------------------------------------------------------------------- | +| `metadata.name` | Unique name within the namespace (must be a valid Kubernetes name) | +| `metadata.namespace` | The namespace this project belongs to | +| `spec.deploymentPipelineRef` | Reference to a DeploymentPipeline that controls environment promotion | +| Annotations | Optional `openchoreo.dev/display-name` and `openchoreo.dev/description` for human-readable metadata | + +## Creating via Backstage UI + +1. Navigate to your namespace in the Backstage console +2. Click **Create Project** +3. Fill in the form: + - **Namespace**: pre-selected from your current context + - **Project Name**: a valid Kubernetes name + - **Display Name**: optional human-readable name + - **Description**: optional description + - **Deployment Pipeline**: select from available pipelines in the namespace (defaults to `default`) +4. Click **Create** + +The project appears immediately in the Backstage catalog. + +## Creating via YAML + +Create a `project.yaml` file: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Project +metadata: + name: online-store + namespace: default + annotations: + openchoreo.dev/display-name: "Online Store" + openchoreo.dev/description: "E-commerce application components" +spec: + deploymentPipelineRef: + kind: DeploymentPipeline + name: default +``` + +Apply it: + +```bash +kubectl apply -f project.yaml +``` + +Or using the occ CLI: + +```bash +occ apply -f project.yaml +``` + +:::tip Default Resources +When OpenChoreo is installed, a `default` project with a `default` deployment pipeline is created automatically. You only need to create additional projects if you want separate deployment pipelines or logical groupings. +::: + +## Managing Projects + +### List projects + +```bash +occ project list --namespace default +``` + +### View project details + +```bash +occ project get online-store --namespace default +``` + +### Delete a project + +```bash +occ project delete online-store --namespace default +``` + +:::warning +Deleting a project also deletes all components within it. +::: + +### Change deployment pipeline + +In the Backstage UI, click the edit icon on the Deployment Pipeline card on the project page to select a different pipeline. + +## What's Next + +- [Creating a Component](./creating-a-component.md): deploy a service, web app, or scheduled task within your project diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/overview.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/overview.md new file mode 100644 index 00000000..664f20fb --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/projects-and-components/overview.md @@ -0,0 +1,101 @@ +--- +title: Overview +description: Understand how Projects and Components organize your applications in OpenChoreo +--- + +# Projects and Components + +OpenChoreo organizes applications using a simple hierarchy: **Namespaces** contain **Projects**, and Projects contain **Components**. As a developer, you create Projects to group related services and Components to define each deployable unit. + +## Resource Hierarchy + +```mermaid +flowchart TD + A["Namespace"] --> B["Project"] + B --> C1["Component"] + B --> C2["Component"] + C1 --> D1["Workload"] + C2 --> D2["Workload"] +``` + +- **Namespace**: your team or organization boundary, managed by platform engineers +- **Project**: a logical grouping of related components that share a deployment pipeline +- **Component**: a single deployable unit (service, web app, scheduled task) that references a platform-defined template +- **Workload**: the runtime specification for a component (container image, endpoints, environment variables, dependencies) + +## ComponentTypes and Traits + +Platform engineers define **ComponentTypes** that serve as templates for how your application gets deployed. When you create a Component, you reference one of these templates by name: + +```yaml +componentType: + kind: ClusterComponentType + name: deployment/service +``` + +The ComponentType determines the workload type (Deployment, StatefulSet, CronJob, etc.), default parameters, and what Kubernetes resources get created. + +You can list available ComponentTypes using: + +```bash +occ clustercomponenttype list +occ componenttype list +``` + +**Traits** are reusable cross-cutting concerns (like observability alerting or OAuth2 proxy) that you can attach to your Component. Each trait instance has a unique name and its own parameters: + +```yaml +traits: + - kind: ClusterTrait + name: observability-alert-rule + instanceName: high-error-rate + parameters: + condition: "error_count > 100" +``` + +## Deployment Patterns + +There are two ways to deploy a component, depending on whether you have a pre-built container image or want OpenChoreo to build from source. + +### From a Pre-built Image + +You provide the container image directly in a Workload resource. OpenChoreo deploys it without any build step. + +```text +Component (references ComponentType) + + +Workload (container image, endpoints, env vars) + ↓ +OpenChoreo deploys to environments +``` + +This pattern is used when: + +- You have an existing CI system (GitHub Actions, GitLab CI, Jenkins) +- You are deploying a third-party or pre-built image +- You want full control over the build process + +### From Source Code + +You configure a workflow on the Component that builds your source code into a container image. OpenChoreo runs the build and creates the Workload automatically. + +```text +Component (references ComponentType + Workflow) + ↓ +WorkflowRun (builds container image) + ↓ +Workload (generated from build output + workload.yaml descriptor) + ↓ +OpenChoreo deploys to environments +``` + +This pattern is used when: + +- You want OpenChoreo to handle your CI pipeline +- You are using Docker, Buildpacks, or other supported build methods +- You want auto-build on Git push + +## What's Next + +- [Creating a Project](./creating-a-project.md): set up a project to organize your components +- [Creating a Component](./creating-a-component.md): deploy your first service or web application diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/auto-build.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/auto-build.md new file mode 100644 index 00000000..4f39c432 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/auto-build.md @@ -0,0 +1,82 @@ +--- +title: Auto-Build +description: Trigger builds automatically when code is pushed to your Git repository +--- + +# Auto-Build + +Auto-build triggers a CI workflow automatically whenever you push code to your Git repository. Instead of manually creating a WorkflowRun for each build, OpenChoreo creates one for you based on the workflow configuration in your Component. + +:::info Platform Engineer Setup Required +Auto-build requires your platform engineer to set up a webhook secret and configure the webhook endpoint. See the [PE Auto Build guide](../../../platform-engineer-guide/workflows/auto-build.mdx) for infrastructure setup. +::: + +## Enable Auto-Build on Your Component + +Add `autoBuild: true` to your Component spec: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: patient-management-service +spec: + owner: + projectName: default + componentType: + kind: ClusterComponentType + name: deployment/service + autoBuild: true + autoDeploy: true + workflow: + kind: ClusterWorkflow + name: ballerina-buildpack-builder + parameters: + repository: + url: "https://github.com/openchoreo/sample-workloads" + revision: + branch: "main" + appPath: "/service-ballerina-patient-management" +``` + +Apply it: + +```bash +occ apply -f component.yaml +``` + +## Key Fields + +| Field | Description | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | +| `autoBuild: true` | Enables webhook-triggered builds. Pushes to the configured branch create a WorkflowRun automatically. | +| `autoDeploy: true` | Automatically deploys the generated Workload after a successful build. | +| `workflow.parameters.repository.revision.branch` | The branch that triggers builds on push. | +| `workflow.parameters.repository.appPath` | Only pushes that change files within this path trigger builds. | + +## What Triggers a Build + +When a push event is received, OpenChoreo matches it to Components by checking: + +1. The **repository URL** matches the Component's `repository.url` +2. The **branch** matches the Component's `repository.revision.branch` +3. The push includes changes within the Component's `appPath` + +If all conditions match, a WorkflowRun is created automatically with the commit SHA from the push event. + +## Verify Auto-Build + +After pushing a change to your repository: + +```bash +# Check if a WorkflowRun was created +occ workflowrun list + +# View build logs +occ workflowrun logs -f +``` + +## See Also + +- [CI Overview](./overview.md) — How CI workflows work, monitoring builds, error conditions +- [Auto Build Setup](../../../platform-engineer-guide/workflows/auto-build.mdx) — Platform engineer guide for webhook infrastructure setup diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/create-secret.png b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/create-secret.png new file mode 100644 index 00000000..805ceaa4 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/create-secret.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/secret-management.png b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/secret-management.png new file mode 100644 index 00000000..0d0a6359 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/secret-management.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/workflow-selection.png b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/workflow-selection.png new file mode 100644 index 00000000..cad5dcaf Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/images/workflow-selection.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/overview.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/overview.md new file mode 100644 index 00000000..951e27b6 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/overview.md @@ -0,0 +1,239 @@ +--- +title: CI Overview +description: Build components using CI workflows in OpenChoreo +--- + +# CI Workflows + +CI workflows build your source code into container images and create Workload CRs that OpenChoreo deploys. They are regular [Workflows](../../../platform-engineer-guide/workflows/overview.md) that your platform engineer has configured for component builds. + +## How It Works + +```mermaid +flowchart TD + A["PE creates CI Workflow
and allows it in ComponentType"] --> B["You create a Component
that references the Workflow"] + B --> C{"OpenChoreo validates
workflow is allowed"} + C -->|Allowed| D["You trigger a build
by creating a WorkflowRun"] + C -->|Not allowed| E["Component enters
WorkflowNotAllowed state"] + D --> F["Workflow clones repo,
builds image, pushes it"] + F --> G{"workload.yaml
in source repo?"} + G -->|Yes| H["Workload CR created with
endpoints and config from descriptor"] + G -->|No| I["Minimal Workload CR created
with just the container image"] +``` + +## Configuring Your Component for CI + +Reference a CI workflow in your Component's `spec.workflow` field: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: greeting-service + namespace: default +spec: + owner: + projectName: default + + componentType: + kind: ClusterComponentType + name: deployment/service + + autoDeploy: true + + workflow: + kind: ClusterWorkflow + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/openchoreo/sample-workloads" + revision: + branch: "main" + appPath: "/service-go-greeter" + docker: + context: "/service-go-greeter" + filePath: "/service-go-greeter/Dockerfile" +``` + +Key fields: + +- **`workflow.kind`** — `ClusterWorkflow` (cluster-scoped) or `Workflow` (namespace-scoped) +- **`workflow.name`** — Name of the CI workflow to use (must be allowed by your ComponentType) +- **`workflow.parameters`** — Build parameters (repository URL, branch, app path, and builder-specific options) +- **`autoDeploy`** — When `true`, the generated Workload is automatically deployed after a successful build + +## Available CI Workflows + +OpenChoreo ships with four default CI workflows. Your platform engineer may have configured additional ones or restricted which are available for your ComponentType. + +| Workflow | Description | Builder-specific parameters | +| ----------------------------- | ------------------------------------------ | ----------------------------------- | +| `dockerfile-builder` | Build with a Dockerfile/Containerfile | `docker.context`, `docker.filePath` | +| `gcp-buildpacks-builder` | Go, Java, Node.js, Python, .NET | `buildEnv` (optional) | +| `paketo-buildpacks-builder` | Java, Node.js, Python, Go, .NET, Ruby, PHP | `buildEnv` (optional) | +| `ballerina-buildpack-builder` | Ballerina applications | `buildEnv` (optional) | + +All workflows share common repository parameters: + +| Parameter | Description | Default | +| ---------------------------- | ---------------------------------- | ---------- | +| `repository.url` | Git repository URL | (required) | +| `repository.revision.branch` | Branch to build | `main` | +| `repository.revision.commit` | Specific commit SHA (optional) | latest | +| `repository.appPath` | Path to application directory | `.` | +| `repository.secretRef` | Secret reference for private repos | (none) | + +## Triggering a Build + +The simplest way to trigger a build is using the `occ` CLI: + +```bash +occ component workflow run greeting-service +``` + +This creates a WorkflowRun using the workflow configured in your Component's `spec.workflow`. + +Alternatively, you can create a WorkflowRun YAML and apply it: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: greeting-service-build-01 + labels: + openchoreo.dev/project: "default" + openchoreo.dev/component: "greeting-service" +spec: + workflow: + kind: ClusterWorkflow + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/openchoreo/sample-workloads" + revision: + branch: "main" + appPath: "/service-go-greeter" + docker: + context: "/service-go-greeter" + filePath: "/service-go-greeter/Dockerfile" +``` + +```bash +occ apply -f workflowrun.yaml +``` + +The `openchoreo.dev/project` and `openchoreo.dev/component` labels link the build to your Component. These labels are required for CI workflows. + +## Monitoring a Build + +```bash +# Get build status +occ workflowrun get greeting-service-build-01 + +# List all workflow runs +occ workflowrun list + +# List workflow runs for a specific component +occ component workflowrun list greeting-service +``` + +### Build Logs + +View live or archived build logs: + +```bash +# View logs for a build +occ workflowrun logs greeting-service-build-01 + +# Follow logs in real-time +occ workflowrun logs greeting-service-build-01 -f + +# View logs for a component's latest build +occ component workflowrun logs greeting-service +``` + +### Build Conditions + +| Condition | Description | +| ------------------- | ------------------------------------ | +| `WorkflowRunning` | Build is currently executing | +| `WorkflowCompleted` | Build completed (success or failure) | +| `WorkflowSucceeded` | Build completed successfully | +| `WorkflowFailed` | Build failed or errored | + +### Build Steps + +The `status.tasks` field shows individual step progress: + +```yaml +status: + tasks: + - name: checkout-source + phase: Succeeded + - name: containerfile-build + phase: Succeeded + - name: publish-image + phase: Succeeded + - name: generate-workload-cr + phase: Running +``` + +Step phases: `Pending`, `Running`, `Succeeded`, `Failed`, `Skipped`, `Error`. + +## External CI + +If your organization uses an external CI platform (e.g., Jenkins, GitHub Actions) instead of OpenChoreo's built-in CI, you can create a Component with **External CI** as the deployment source: + +1. Navigate to **Create** in Backstage +2. Select your component type and fill in **Component Metadata** +3. In the **Build & Deploy** step, under **Deployment Source**, select **"External CI"** +4. Optionally select your **CI Platform** (e.g., Jenkins) to enable build visibility in Backstage, and provide the **Jenkins Job Path** (e.g., `/job/my-org/job/my-service`) +5. Complete the remaining steps and review + +The component is created without a workload. Your CI pipeline will create workloads when builds complete by calling the OpenChoreo Workload API: + +``` +POST /api/v1/namespaces/{namespaceName}/workloads +Authorization: Bearer +Content-Type: application/json +``` + +Your platform engineer sets up the OAuth credentials and Jenkins/CI visibility in Backstage. See the [External CI Integration](../../../platform-engineer-guide/workflows/external-ci.mdx) guide for the full setup. + +## Troubleshooting + +### WorkflowNotAllowed + +Your Component references a workflow that your ComponentType does not permit: + +```yaml +conditions: + - type: Ready + status: False + reason: WorkflowNotAllowed + message: "Workflow 'custom-workflow' is not in ComponentType 'backend' allowedWorkflows" +``` + +Ask your platform engineer to add the workflow to the ComponentType's `allowedWorkflows`, or use a different workflow. + +### WorkflowRun Validation Errors + +When a WorkflowRun is created with component labels, the controller validates it before execution: + +| Validation | Condition Reason | What to check | +| -------------------------- | --------------------------- | ----------------------------------------------------------------------------- | +| Both labels required | `ComponentValidationFailed` | Ensure both `openchoreo.dev/project` and `openchoreo.dev/component` are set | +| Component exists | `ComponentValidationFailed` | Verify the Component exists in the same namespace | +| Project label matches | `ComponentValidationFailed` | Ensure the project label matches the Component's owner project | +| Workflow allowed | `ComponentValidationFailed` | Use a workflow listed in your ComponentType's `allowedWorkflows` | +| Workflow matches component | `ComponentValidationFailed` | WorkflowRun must reference the same workflow as the Component | +| Workflow exists | `WorkflowNotFound` | Verify the ClusterWorkflow or Workflow exists | +| WorkflowPlane available | `WorkflowPlaneNotFound` | Ask your platform engineer to check the WorkflowPlane (retried automatically) | + +`ComponentValidationFailed` conditions are permanent — fix the issue and create a new WorkflowRun. `WorkflowPlaneNotFound` is transient and retried automatically. + +## What's Next + +- [Workload Descriptor](./workload-descriptor.md) — Customize what your build produces with a `workload.yaml` file +- [Auto-Build](./auto-build.md) — Trigger builds automatically on Git push +- [Private Repository](./private-repository.md) — Configure access to private Git repositories diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/private-repository.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/private-repository.md new file mode 100644 index 00000000..f53bca16 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/private-repository.md @@ -0,0 +1,177 @@ +--- +title: Private Git Repository +description: Configure private Git repository access for workflow builds +--- + +# Using Private Git Repositories + +OpenChoreo supports building components from private Git repositories using **basic authentication** or **SSH authentication**. Credentials are securely managed through external secret stores and are never stored in OpenChoreo's control plane. + +## Prerequisites + +Before configuring private repository access, ensure you have: + +- **External Secret Store**: A configured secret store (e.g., Vault, AWS Secrets Manager, OpenBao) +- **ClusterSecretStore**: A ClusterSecretStore resource in the workflow plane that connects to your secret store +- **Git Credentials**: One of the following: + - **For Basic Auth**: Personal access token (PAT) or username/password with repository read access + - **For SSH Auth**: SSH private key registered with your Git provider + +## Authentication Methods + +| Method | Use Case | +| -------------- | -------------------------------------------------------- | +| **Basic Auth** | HTTPS Git URLs (e.g., `https://github.com/org/repo.git`) | +| **SSH Auth** | SSH Git URLs (e.g., `git@github.com:org/repo.git`) | + +## From UI + +The easiest way to configure private repository access is through the OpenChoreo UI. You can create secrets either during component creation or pre-create them for reuse. + +:::note +The UI flows below require the secret management feature to be enabled in the control-plane Helm chart. It is disabled by default. Set `features.secretManagement.enabled=true` in the `openchoreo-control-plane` Helm values to turn it on. The k3d single-cluster install and the quick-start install enable it out of the box. +::: + +### During Component Creation + +1. When creating a component that uses a private repository, select **Create New Git Secret** from the secret reference dropdown: + + + +2. Enter your Git credentials (username/token or SSH key) and click **Create**. + + + +3. The newly created secret will be automatically selected. Use it for component creation. + +### Secret Management Page + +You can also pre-create secrets in the Secret Management page for reuse across multiple components. + +1. Navigate to the Secret Management page, click **Create Secret**, and select **Git Credentials** as the category: + + + +2. When creating a component, select the secret from the dropdown in the secret reference field. + +## From YAML + +For manual configuration, create a `SecretReference` custom resource that points to credentials in your external secret store. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: github-credentials + namespace: default +spec: + targetPlane: + kind: ClusterWorkflowPlane + name: default + template: + type: kubernetes.io/basic-auth + data: + - secretKey: username + remoteRef: + key: secret/git/github-token + property: username + - secretKey: password + remoteRef: + key: secret/git/github-token + property: token + refreshInterval: 1h +``` + +Reference the secret in your component's workflow configuration: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service +spec: + owner: + projectName: my-project + componentType: + kind: ClusterComponentType + name: deployment/service + workflow: + kind: ClusterWorkflow + name: dockerfile-builder + parameters: + repository: + url: https://github.com/myorg/private-repo.git + secretRef: github-credentials + revision: + branch: main + appPath: / + docker: + context: . + filePath: ./Dockerfile +``` + +## How It Works + +```mermaid +flowchart LR + user(["User"]) + + subgraph CP["Control Plane"] + api["OpenChoreo
API Server"] + sr["SecretReference
label: openchoreo.dev/secret-type=git-credentials
template.type: basic-auth
targetPlane: ClusterWorkflowPlane"] + wfrun["WorkflowRun"] + end + + subgraph WP["Workflow Plane"] + subgraph KVNS["ns: openchoreo-kv-<ns>"] + srcSecret["Kubernetes Secret
(source)"] + pushSecret["PushSecret"] + end + + subgraph WFNS["ns: workflows-<ns>"] + extSecret["ExternalSecret"] + runSecret["Kubernetes Secret
(materialized)"] + argo["Argo Workflow
(build step)"] + end + + css["ClusterSecretStore"] + store[("External Secret Store
OpenBao / Vault")] + end + + user -- "1. Create git secret" --> api + api -- "2. Create SecretReference" --> sr + api -- "3. Push K8s Secret + PushSecret" --> KVNS + pushSecret -- "reads" --> srcSecret + pushSecret -- "4. push via" --> css + css --> store + + user -- "5. Trigger build" --> wfrun + wfrun -- "6. Reconciler creates ExternalSecret" --> extSecret + extSecret -- "pulls via" --> css + extSecret -- "7. creates" --> runSecret + runSecret -- "consumed by" --> argo +``` + +When a workflow run is triggered: + +1. **Control Plane**: The OpenChoreo API server stores a `SecretReference` and pushes the source `Kubernetes Secret` together with a `PushSecret` to the target plane's `openchoreo-kv-` namespace. +2. **Workflow Plane (push path)**: `PushSecret` reads the source Kubernetes Secret and pushes its contents to the external secret store through the `ClusterSecretStore`. +3. **Workflow Plane (pull path)**: When the `WorkflowRun` is reconciled, the controller creates an `ExternalSecret` in the `workflows-` namespace. The `ExternalSecret` pulls the secret from the external store via the same `ClusterSecretStore` and materializes a Kubernetes Secret for the build. +4. **Workflow Execution**: Argo Workflow uses the materialized secret for Git authentication. +5. **Cleanup**: The `ExternalSecret` and its materialized Kubernetes Secret are automatically removed when the `WorkflowRun` is deleted. The push-side resources in `openchoreo-kv-` are owned by the `SecretReference` and removed when it is deleted. + +## Additional Resources + +- [Creating Workflows](../../../platform-engineer-guide/workflows/creating-workflows.mdx) — Creating custom workflows with secret support diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/workload-descriptor.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/workload-descriptor.md new file mode 100644 index 00000000..94a38d49 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workflows/ci/workload-descriptor.md @@ -0,0 +1,174 @@ +--- +title: Workload Descriptor +description: Customize what your CI build produces with a workload.yaml file +--- + +# Workload Descriptor + +When a CI workflow builds your code, it produces a [Workload](../../workload/overview.md) CR that OpenChoreo deploys. By default, the build creates a minimal Workload with just the container image. To define endpoints, environment variables, dependencies, and configuration files, add a `workload.yaml` descriptor to your source repository. + +## With vs Without a Descriptor + +| | Without `workload.yaml` | With `workload.yaml` | +| ------------------------- | ----------------------------------------- | ----------------------------------------------------------------- | +| **Container image** | Set from build output | Set from build output | +| **Endpoints** | None | Defined in descriptor | +| **Environment variables** | None | Defined in descriptor | +| **Configuration files** | None | Defined in descriptor | +| **Dependencies** | None | Defined in descriptor | +| **Use case** | Simple services with no exposed endpoints | Services with HTTP/gRPC/WebSocket endpoints, custom configuration | + +## Descriptor Format + +Place a `workload.yaml` file in your application directory (the path specified by `repository.appPath` in your Component's workflow parameters): + +```yaml +# workload.yaml +apiVersion: openchoreo.dev/v1alpha1 + +metadata: + name: reading-list-service + +endpoints: + - name: reading-list-api + visibility: + - external + port: 8080 + type: HTTP + basePath: /api + schemaFile: docs/openapi.yaml + +configurations: + env: + - name: LOG_LEVEL + value: info + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: db-credentials + key: password + files: + - name: app.json + mountPath: /etc/config + value: | + {"feature_flags": {"new_feature": true}} + - name: tls.conf + mountPath: /etc/app + valueFrom: + path: configs/tls.conf + +dependencies: + endpoints: + - component: postgres-db + name: api + visibility: project + envBindings: + host: DB_HOST + port: DB_PORT +``` + +### Fields + +#### `metadata` + +| Field | Required | Description | +| ------ | -------- | ---------------------------------- | +| `name` | Yes | Name for the generated Workload CR | + +#### `endpoints` + +Define the network endpoints your service exposes: + +| Field | Required | Description | +| ------------- | -------- | ------------------------------------------------------------------------------------------ | +| `name` | Yes | Unique name for the endpoint | +| `port` | Yes | Port your application listens on | +| `type` | Yes | `HTTP`, `gRPC`, `GraphQL`, `Websocket`, `TCP`, or `UDP` | +| `visibility` | No | List of visibility levels: `project`, `namespace`, `internal`, `external` | +| `targetPort` | No | Container port to forward to (defaults to `port`) | +| `basePath` | No | Base path prefix for the endpoint | +| `displayName` | No | Human-readable name for the endpoint | +| `schemaFile` | No | Path to schema file (OpenAPI, Protobuf, GraphQL), relative to the `workload.yaml` location | + +#### `configurations` + +##### `configurations.env` + +Environment variables injected into the container. Set either `value` or `valueFrom`, not both. + +| Field | Required | Description | +| ----------- | -------- | ----------------------------------------------------------------- | +| `name` | Yes | Environment variable name | +| `value` | No | Literal value (mutually exclusive with `valueFrom`) | +| `valueFrom` | No | Reference to an external source (mutually exclusive with `value`) | + +`valueFrom` supports: + +| Field | Description | +| ----------------------------- | ----------------------------- | +| `valueFrom.secretKeyRef.name` | Name of the Kubernetes Secret | +| `valueFrom.secretKeyRef.key` | Key within the Secret | + +##### `configurations.files` + +Configuration files mounted into the container. Set exactly one of `value` or `valueFrom`. + +| Field | Required | Description | +| ----------- | -------- | ----------------------------------------------------------------- | +| `name` | Yes | File name (used as the file name within `mountPath`) | +| `mountPath` | Yes | Absolute directory path where the file is mounted | +| `value` | No | Inline file content (mutually exclusive with `valueFrom`) | +| `valueFrom` | No | Reference to an external source (mutually exclusive with `value`) | + +`valueFrom` supports `path` or `secretKeyRef` (not both): + +| Field | Description | +| ----------------------------- | ----------------------------------------------------------------------- | +| `valueFrom.path` | Path to a local file, resolved relative to the `workload.yaml` location | +| `valueFrom.secretKeyRef.name` | Name of the Kubernetes Secret | +| `valueFrom.secretKeyRef.key` | Key within the Secret | + +#### `dependencies` + +Declare dependencies on other components' endpoints. See [Endpoint Dependencies](../../dependencies/endpoints.md) for details. + +##### `dependencies.endpoints` + +| Field | Required | Description | +| ------------- | -------- | ---------------------------------------------------------------- | +| `component` | Yes | Name of the target component | +| `name` | Yes | Name of the endpoint on the target component | +| `visibility` | Yes | Visibility scope (`project` or `namespace`) | +| `project` | No | Target component's project (defaults to same project) | +| `envBindings` | Yes | Maps connection address components to environment variable names | + +`envBindings` fields: + +| Field | Required | Description | +| ---------- | -------- | -------------------------------------------------- | +| `address` | No | Env var name for the full address (host:port/path) | +| `host` | No | Env var name for the host | +| `port` | No | Env var name for the port | +| `basePath` | No | Env var name for the base path | + +## File Placement + +The CI workflow looks for `workload.yaml` at the root of your `appPath`. For example, if your Component specifies `appPath: "/service-go-greeter"`, place the descriptor at: + +``` +your-repo/ + service-go-greeter/ + workload.yaml ← descriptor file + Dockerfile + main.go + openapi.yaml ← referenced by schemaFile + configs/ + tls.conf ← referenced by valueFrom.path +``` + +## See Also + +- [Workload](../../workload/overview.md) — Full Workload CR specification (container, endpoints, dependencies) +- [Endpoint Dependencies](../../dependencies/endpoints.md) — How to declare service dependencies +- [CI Overview](./overview.md) — How CI workflows work +- [Workload API Reference](../../../reference/api/application/workload.md) — Complete Workload CRD specification diff --git a/versioned_docs/version-v1.2.0-rc.2/developer-guide/workload/overview.md b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workload/overview.md new file mode 100644 index 00000000..f2f7eac9 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/developer-guide/workload/overview.md @@ -0,0 +1,172 @@ +--- +title: Overview +description: Learn how to define Workloads in OpenChoreo to configure container runtime, endpoints, and dependencies +--- + +# Workload + +A **Workload** defines the runtime specification for a [Component](../../reference/api/application/component.md) in OpenChoreo. It describes what container image to run, what network endpoints to expose, and what dependencies the component has on other components. The platform uses this specification to generate the appropriate Kubernetes resources, including Deployments, Services, HTTPRoutes, and NetworkPolicies. + +Each component has exactly one Workload that is linked to it through the `owner` field. Workloads can be created manually for pre-built images or generated automatically by build workflows. + +## Structure + +A Workload spec has the following top-level fields: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: my-service-workload + namespace: default +spec: + owner: + projectName: my-project + componentName: my-service + container: + # Container specification + endpoints: + # Network endpoints + dependencies: + # Dependencies on other components +``` + +## Owner + +The `owner` field links the Workload to its Component and Project. This field is **immutable** after creation. + +| Field | Type | Required | Description | +| --------------- | ------ | -------- | --------------------------------------------- | +| `projectName` | string | Yes | Name of the project that owns this workload | +| `componentName` | string | Yes | Name of the component that owns this workload | + +## Container + +The `container` field defines what to run. Only the `image` field is required. + +| Field | Type | Required | Description | +| --------- | -------- | -------- | -------------------------------- | +| `image` | string | Yes | OCI image to run (digest or tag) | +| `command` | []string | No | Container entrypoint | +| `args` | []string | No | Arguments for the entrypoint | +| `env` | []EnvVar | No | Environment variables | +| `files` | []File | No | File configurations and secrets | + +### Environment Variables + +Environment variables can be set as literal values or referenced from secrets: + +```yaml +container: + image: myregistry/my-service:v1.0.0 + env: + - key: LOG_LEVEL + value: info + - key: DB_PASSWORD + valueFrom: + secretKeyRef: + name: db-secrets + key: password +``` + +Each `env` entry must have exactly one of `value` or `valueFrom` set. + +### Files + +Files can be mounted into the container from literal content or secrets: + +```yaml +container: + image: myregistry/my-service:v1.0.0 + files: + - key: config.yaml + mountPath: /etc/config + value: | + server: + port: 8080 + - key: tls.crt + mountPath: /etc/tls + valueFrom: + secretKeyRef: + name: tls-certs + key: certificate +``` + +Each `file` entry requires `key` and `mountPath`, and must have exactly one of `value` or `valueFrom` set. + +## Endpoints + +Endpoints define the network interfaces that the component exposes. They are specified as a map where each key is the endpoint name: + +```yaml +endpoints: + http: + type: HTTP + port: 8080 + visibility: + - external + basePath: /api/v1 + grpc: + type: gRPC + port: 9090 + visibility: + - namespace +``` + +### Endpoint Fields + +| Field | Type | Required | Description | +| ------------- | -------- | -------- | --------------------------------------------------------------------- | +| `type` | string | Yes | Protocol type: `HTTP`, `gRPC`, `GraphQL`, `Websocket`, `TCP`, `UDP` | +| `port` | int32 | Yes | Port number exposed by the endpoint (1-65535) | +| `targetPort` | int32 | No | Container port to forward to (defaults to `port`) | +| `visibility` | []string | No | Additional visibility scopes beyond the implicit `project` visibility | +| `basePath` | string | No | Base path of the API exposed via the endpoint | +| `displayName` | string | No | Human-readable name for the endpoint | +| `schema` | object | No | API schema definition (e.g., OpenAPI spec) | + +### Endpoint Visibility + +Every endpoint automatically gets **project** visibility, meaning it is accessible to other components within the same project and environment. The `visibility` array adds additional scopes: + +| Visibility | Description | +| ----------- | ------------------------------------------------------------------------------- | +| `project` | Accessible within the same project and environment (implicit for all endpoints) | +| `namespace` | Accessible across all projects in the same namespace and environment | +| `internal` | Accessible across all namespaces in the deployment | +| `external` | Accessible from outside the deployment, including public internet | + +Visibility levels control both routing (HTTPRoutes) and network access (NetworkPolicies). For example, an endpoint with `external` visibility gets an HTTPRoute on the external gateway and a NetworkPolicy allowing ingress from non-OpenChoreo namespaces, while `namespace` visibility allows cross-project traffic within the same namespace. + +## Example + +Here is a complete Workload example for a REST service with an external endpoint: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: greeter-service-workload + namespace: default +spec: + owner: + projectName: default + componentName: greeter-service + container: + image: ghcr.io/openchoreo/samples/greeter-service:latest + args: + - --port + - "9090" + endpoints: + http: + type: HTTP + port: 9090 + visibility: + - external +``` + +## Related Resources + +- [Workload API Reference](../../reference/api/application/workload.md) - Full CRD specification +- [Component](../../reference/api/application/component.md) - Components that own workloads +- [Dependencies](../dependencies/endpoints.md) - How to define dependencies between components diff --git a/versioned_docs/version-v1.2.0-rc.2/ecosystem/overview.md b/versioned_docs/version-v1.2.0-rc.2/ecosystem/overview.md new file mode 100644 index 00000000..359769cc --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/ecosystem/overview.md @@ -0,0 +1,34 @@ +--- +title: Ecosystem +description: Extend OpenChoreo with modules, integrations, agents, and more. +sidebar_position: 1 +--- + +# OpenChoreo Ecosystem + +The OpenChoreo Ecosystem provides community-driven extensions that seamlessly integrate with the platform to expand its capabilities. Browse the [Ecosystem Catalog](/ecosystem) to discover available extensions. + +OpenChoreo is designed to be extensible. Rather than bundling every possible integration into the core platform, the ecosystem approach lets you choose the tools that fit your needs, stay current as extensions evolve independently, and contribute back to benefit from the community's work. + +## Extension Types + +| Type | Description | +| ------------------- | --------------------------------------------------------------------------------------------------------------------- | +| **Modules** | First-class platform extensions that plug into OpenChoreo's interfaces. | +| **Integrations** | Integrate with external tools via tutorial-based configuration. | +| **Agents** | AI-powered agents that analyze and perform operational tasks within OpenChoreo. | +| **Skills** | Reusable capabilities that coding agents invoke. | +| **Component Types** | Reusable templates that let platform engineers manage complexity while providing developers with a simpler interface. | +| **Workflows** | Platform engineer-defined templates for component CI builds and other automation tasks. | + +## Contributing + +The ecosystem is open to contributions. Submit your extension to the appropriate repository: + +- [openchoreo/community-modules](https://github.com/openchoreo/community-modules) +- [openchoreo/skills](https://github.com/openchoreo/skills) + +### Get Help + +- [CNCF Slack (#openchoreo)](https://slack.cncf.io/) +- [GitHub Discussions](https://github.com/openchoreo/openchoreo/discussions) diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/cli-installation.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/cli-installation.mdx new file mode 100644 index 00000000..a50fcd86 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/cli-installation.mdx @@ -0,0 +1,203 @@ +--- +title: CLI Installation +description: Install the OpenChoreo CLI (occ) on macOS, Linux, and Windows +--- + +import CodeBlock from "@theme/CodeBlock"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { versions, defaultCredentials } from "../_constants.mdx"; + +# CLI Installation + +The OpenChoreo CLI (`occ`) is the command-line interface for managing OpenChoreo resources, projects, and deployments. + +## Installation + +{versions.dockerTag === 'latest-dev' ? ( + +<> +Download and install the latest development build from GitHub: + + + + + + {`curl -L https://nightly.link/openchoreo/openchoreo/workflows/build-and-test/main/occ.zip -o occ.zip && \\ +unzip occ.zip && \\ +sudo mv darwin/arm64/occ /usr/local/bin/ && \\ +rm -rf occ.zip darwin linux`} + + + + + + + {`curl -L https://nightly.link/openchoreo/openchoreo/workflows/build-and-test/main/occ.zip -o occ.zip && \\ +unzip occ.zip && \\ +sudo mv darwin/amd64/occ /usr/local/bin/ && \\ +rm -rf occ.zip darwin linux`} + + + + + + + {`curl -L https://nightly.link/openchoreo/openchoreo/workflows/build-and-test/main/occ.zip -o occ.zip && \\ +unzip occ.zip && \\ +sudo mv linux/amd64/occ /usr/local/bin/ && \\ +rm -rf occ.zip darwin linux`} + + + + + + + {`curl -L https://nightly.link/openchoreo/openchoreo/workflows/build-and-test/main/occ.zip -o occ.zip && \\ +unzip occ.zip && \\ +sudo mv linux/arm64/occ /usr/local/bin/ && \\ +rm -rf occ.zip darwin linux`} + + + + + +) : ( +<> +Download and install the binary for your platform: + + + + + + {`curl -L https://github.com/openchoreo/openchoreo/releases/download/${versions.dockerTag}/occ_${versions.dockerTag}_darwin_arm64.tar.gz | tar -xz && \\ +sudo mv occ /usr/local/bin/`} + + + + + + + {`curl -L https://github.com/openchoreo/openchoreo/releases/download/${versions.dockerTag}/occ_${versions.dockerTag}_darwin_amd64.tar.gz | tar -xz && \\ +sudo mv occ /usr/local/bin/`} + + + + + + + {`curl -L https://github.com/openchoreo/openchoreo/releases/download/${versions.dockerTag}/occ_${versions.dockerTag}_linux_amd64.tar.gz | tar -xz && \\ +sudo mv occ /usr/local/bin/`} + + + + + + + {`curl -L https://github.com/openchoreo/openchoreo/releases/download/${versions.dockerTag}/occ_${versions.dockerTag}_linux_arm64.tar.gz | tar -xz && \\ +sudo mv occ /usr/local/bin/`} + + + + + +)} + +### Verify Installation + +{`occ version`} + +## Login + +After installing the CLI, configure the OpenChoreo control plane URL and authenticate to start managing resources. + +### Configure Control Plane + +Set the OpenChoreo API server endpoint: + + + {`occ config controlplane update default --url https://api.`} + + +For example, if you followed the [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) guide using `nip.io` domains, the URL uses the `CP_BASE_DOMAIN` variable exported in [Step 3](../getting-started/try-it-out/on-your-environment.mdx#step-3-setup-control-plane): + +```bash +occ config controlplane update default --url https://api.${CP_BASE_DOMAIN} +``` + +For local k3d setups, the URL is `http://api.openchoreo.localhost:8080`. Add the following entries to your `/etc/hosts` file: + +``` +127.0.0.1 api.openchoreo.localhost +127.0.0.1 thunder.openchoreo.localhost +127.0.0.1 observer.openchoreo.localhost +``` + +### Self-Signed TLS Certificates + +If your OpenChoreo setup uses self-signed certificates (the default for the [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) guide), the CLI will fail with certificate verification errors like `x509: certificate is not trusted`. You need to trust the CA certificate on your machine. + +Extract the CA certificate from your cluster: + +```bash +kubectl get secret openchoreo-ca-secret -n cert-manager \ + -o jsonpath='{.data.ca\.crt}' | base64 -d > openchoreo-ca.crt +``` + + + + +```bash +sudo security add-trusted-cert -d -r trustRoot \ + -k /Library/Keychains/System.keychain openchoreo-ca.crt +``` + + + + +```bash +sudo cp openchoreo-ca.crt /usr/local/share/ca-certificates/ +sudo update-ca-certificates +``` + + + + +```powershell +# Run as Administrator +Import-Certificate -FilePath .\openchoreo-ca.crt -CertStoreLocation Cert:\LocalMachine\Root +``` + + + + +### Authenticate + +Login to OpenChoreo using the web browser: + +{`occ login`} + +This opens a browser window for authentication. Use the default credentials: + +| Username | Password | +| ------------------------------------------ | ------------------------------------------ | +| {defaultCredentials.username} | {defaultCredentials.password} | + +### Verify + +After login, confirm you can reach the API and list resources: + +```bash +# List namespaces +occ namespace list + +# List projects +occ project list -n default + +# List components in the default project +occ component list -n default +``` + +## See Also + +- **CLI Reference:** [CLI Reference](../reference/cli-reference.md) diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/deploy-and-explore.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/deploy-and-explore.mdx new file mode 100644 index 00000000..c0808ea5 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/deploy-and-explore.mdx @@ -0,0 +1,144 @@ +--- +title: Deploy and Explore +description: Deploy a sample service and explore the resources OpenChoreo creates automatically +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Deploy and Explore + +This guide walks you through deploying a component on OpenChoreo and exploring what the platform creates behind the scenes. By the end, you'll understand the full resource chain, from the Component you define to the Kubernetes Deployment running your code. + +:::tip Already deployed via Quick Start? +If you followed the [Quick Start Guide](./quick-start-guide.mdx), you've already deployed a sample app. This page revisits the process step by step so you can understand what each resource does. +::: + +## Prerequisites + +- **OpenChoreo installed** on your cluster (see [Local Setup](./try-it-out/on-k3d-locally.mdx) or [Your Own Cluster](./try-it-out/on-your-environment.mdx)) +- **kubectl** configured and pointing at your cluster + +## Deploy the Sample + +We'll deploy the Go Greeter Service from a pre-built container image. The sample YAML contains two key resources: + +- **Component**: declares the application, referencing the `deployment/service` ClusterComponentType +- **Workload**: specifies the container image, ports, environment variables, and an external endpoint + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-image/go-greeter-service/greeter-service.yaml`} + + +Wait for the deployment to be ready: + +```bash +kubectl wait --for=condition=Ready component/greeter-service -n default --timeout=120s +``` + +## Explore What OpenChoreo Created + +When you applied those three resources, OpenChoreo's controllers reconciled them and created a chain of resources automatically. Let's walk through each one. + +### The Resource Chain + +```mermaid +flowchart TD + A["Component + Workload"] -->|controller creates| B["ComponentRelease
(immutable snapshot)"] + B --> C["ReleaseBinding
(environment: development)"] + C -->|rendered and applied
to data plane| D["Deployment + Service + HTTPRoute"] +``` + +### 1. Component + +The Component declares your application and links it to a platform-defined template (ClusterComponentType). For this sample, OpenChoreo automatically creates a release and deploys it to the environments in the deployment pipeline. + +```bash +kubectl get component greeter-service -n default +``` + +Inspect the status to see which ComponentRelease was created: + +```bash +kubectl get component greeter-service -n default -o jsonpath='{.status.latestRelease.name}' +``` + +```text +greeter-service-5d7f658d9c +``` + +The suffix is a hash derived from the release spec, so your value may differ. + +### 2. ComponentRelease + +The ComponentRelease is an **immutable snapshot** that freezes the Component's configuration, including the ComponentType spec, Trait definitions, parameters, and Workload. This enables reliable rollbacks and audit trails. + +```bash +kubectl get componentrelease -n default +``` + +The name (`greeter-service-5d7f658d9c`) includes a hash of the spec, so a new release is only created when something actually changes. + +### 3. ReleaseBinding + +The ReleaseBinding binds a ComponentRelease to a specific environment. It references the release name and the target environment (`development`). This is where environment-specific overrides (like replica counts or resource limits) can be applied. + +```bash +kubectl get releasebinding greeter-service-development -n default +``` + +The name follows the convention `{component}-{environment}`. + +### 4. Underlying Kubernetes Resources + +From the ReleaseBinding, OpenChoreo renders the final Kubernetes manifests and applies them to a data plane namespace: + +- **Deployment**: manages the pod running your container image +- **Service**: provides stable networking for the pod +- **HTTPRoute**: configures the API gateway to route external traffic to your service + +```bash +kubectl get deployment,svc,httproute -A -l openchoreo.dev/component=greeter-service +``` + +Notice these resources live in a data plane namespace (e.g., `dp-default-default-development-*`), not in the `default` namespace where you created your Component. This separation is by design: the control plane manages intent while the data plane runs workloads. + +## Test the Running Service + +Verify the service is accessible through the gateway: + +```bash +curl http://development-default.openchoreoapis.localhost:19080/greeter-service-http/greeter/greet +``` + +```text +Hello, Stranger! +``` + +Try it with a name parameter: + +```bash +curl "http://development-default.openchoreoapis.localhost:19080/greeter-service-http/greeter/greet?name=OpenChoreo" +``` + +```text +Hello, OpenChoreo! +``` + +The URL structure is: `http://{environment}-{namespace}.{gateway-host}/{endpoint-name}/{path}` + +## Summary + +You applied a Component and Workload, and OpenChoreo automatically created the full deployment chain: + +**Component** → **ComponentRelease** (immutable snapshot) → **ReleaseBinding** (binds to environment) → **Deployment + Service + HTTPRoute** (running on data plane) + +To learn more about these abstractions, see [Resource Relationships](../concepts/resource-relationships.md) and [Runtime Model](../concepts/runtime-model.md). + +## Clean Up + +To remove the sample: + + + {`kubectl delete -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-image/go-greeter-service/greeter-service.yaml`} + diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/examples-catalog.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/examples-catalog.mdx new file mode 100644 index 00000000..e8685258 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/examples-catalog.mdx @@ -0,0 +1,271 @@ +--- +title: Examples Catalog +description: Browse sample applications, platform configurations, and workflow examples +--- + +import Link from "@docusaurus/Link"; +import { versions } from "../_constants.mdx"; + +export const GitHubSampleLink = ({ path, children }) => ( + + {children} + +); + +# Examples Catalog + +OpenChoreo empowers developers to build cloud-native applications through practical, real-world examples. This section provides comprehensive tutorials that demonstrate OpenChoreo's capabilities across different use cases and complexity levels. + +## Categories + +We have categorized the samples based on what you might want to do: + +- **[Platform Configuration](#platform-configuration)** - Define and customize foundational platform elements such as namespaces, environments, and deployment pipelines. +- **[Application Deployment](#application-deployment)** - Deploy different types of applications (services, APIs, web apps, tasks) using various programming languages and deployment strategies. + +--- + +## Platform Configuration + +When you set up OpenChoreo, certain default resources are automatically created to help you get started quickly: + +- A default namespace +- A default data plane and workflow plane +- Three default environments (Dev, Staging, Prod) +- A default deployment pipeline connecting these environments +- A default project to organize applications + +OpenChoreo provides abstractions to define: + +- **Namespaces** – Group projects and manage access boundaries. +- **Environments** – Set up Dev, Staging, and Prod runtime contexts. +- **DataPlanes** – Define Kubernetes clusters for application deployments. +- **WorkflowPlanes** – Define dedicated Kubernetes clusters for CI operations. +- **DeploymentPipelines** – Automate application rollouts with promotion workflows. + +For more details on these concepts, refer to the [Concepts](../concepts/platform-abstractions.md) documentation. + +These default configurations provide a quick starting point. Once you have done some exploration you can start creating the necessary artifacts to match the needs of your organization. You can: + +- + Create new environments + + in your organization +- + Create a new deployment pipeline + + that will link these environments + +--- + +## Application Deployment + +OpenChoreo uses a flexible ComponentType architecture where platform engineers define templates and developers create components from these templates. + +### Understanding ComponentTypes + +OpenChoreo provides a **ComponentType** abstraction that allows platform engineers to define reusable application templates with: + +- Workload types (Deployment, StatefulSet, CronJob, Proxy) +- Configurable parameters and environment overrides +- Kubernetes resource templates with CEL expressions + +Developers create **Component** resources that reference these ComponentTypes, providing a clean separation between platform governance and developer intent. + +### Default ComponentTypes + +OpenChoreo ships with three default ComponentTypes out of the box: + +- **`deployment/service`** – Backend services and APIs + - Configurable replicas, port, resources, and image pull policy + - Includes Deployment, Service, and optional HTTPRoute resources + - Supports environment-specific overrides + +- **`deployment/web-application`** – Frontend or full-stack web applications + - Always exposed via HTTPRoute with dedicated subdomain + - Configurable replicas, port, resources, and image pull policy + +- **`cronjob/scheduled-task`** – Time-based batch jobs and background tasks + - Configurable cron schedule, concurrency policy, and resource limits + - Environment-specific schedules for different deployment stages + +### ComponentType Examples + +Learn how to work with ComponentTypes and create custom component definitions: + +- **HTTP Service Component** – Custom ComponentType for HTTP services with routing +- **Web Application Component** – ComponentType optimized for web applications +- **Component with Configurations** – Managing Configs and Secrets with components +- **Component with Embedded Traits** – Platform engineer pre-configured trait instances in ComponentTypes + +### Application Examples by Source Type + +Examples demonstrating how to deploy components using the default ComponentTypes: + +#### Built from Source + +- **Services** – Backend services & APIs built from source code + - + Go Service with Docker + + - Go Service using Docker build + - + Go Service with Buildpacks + + - Go Service using Google Cloud Buildpacks + - + Ballerina Service + + - Ballerina service using Ballerina Buildpack + +- **Web Applications** – Frontend or full-stack applications built from source code + - + React SPA + + - SPA web application + +#### Deployed from Pre-built Images + +- **Pre-built Applications** – Applications deployed from existing container images + - + Go Greeter Service + + - Service deployed from pre-built image + - + React Web App + + - Web application from pre-built image + - + GitHub Issue Reporter + + - Scheduled task with MySQL and email integration + - + Echo WebSocket Service + + - WebSocket endpoint with gateway configuration + +### Complete Application Examples + +- **GCP Microservices Demo** – Complete multi-service application demonstrating: + - Project organization with multiple components + - Service interactions and dependencies + - Coordinated deployment patterns + - Configuration management across services + +- **Component Alerts** – Observability alerting demonstration: + - Alert rules defined as traits + - Email and webhook notification channels + - Incident creation and AI root cause analysis + +### CLI-Driven Deployment + +- **Manual Deploy with occ CLI** – Step-by-step manual build, deploy, and promote workflow using the `occ` CLI with `autoDeploy: false` + +### Generic Workflows + +- **AWS RDS PostgreSQL Provisioning** – Terraform-based AWS RDS PostgreSQL database creation +- **GitHub Stats Report** – Generate GitHub repository statistics reports +- **SCM Repository Creation** – Create repositories in GitHub or AWS CodeCommit + +### MCP / AI Assistant Guides + +- **MCP Guides** – Using OpenChoreo MCP servers with AI assistants: + - + Getting Started with MCP + + - Basic MCP operations + - + Service Deployment via MCP + + - Deploy services using AI assistants + - + AI Assistant Configuration + + - Configure AI assistants for OpenChoreo + +### Supported Languages (via BuildPacks) + +OpenChoreo abstracts the build and deployment process using BuildPacks and Workflow resources, enabling developers to deploy applications written in: + +- **Ballerina** - Patient Management Service +- **Go** - Greeter Service and Reading List +- **Node.js/React** - React Starter +- **Python** - (Additional samples can be added) +- **Ruby** - (Additional samples can be added) +- (More languages can be added as extensions.) + +### Key Features Demonstrated + +- **ComponentType Architecture** – Platform engineer templates and developer components with clean separation of concerns +- **Configuration Management** – Environment-specific configs and secrets using Workload resources +- **Trait Composition** – Reusable traits that extend component functionality +- **Workflow Integration for CI** – Components with integrated Workflow resources for CI/CD automation +- **Generic Workflows** – Platform-defined workflows for infrastructure provisioning and automation +- **Observability Alerts** – Alert rules, notification channels, and incident management +- **AI/MCP Integration** – Using AI assistants to manage OpenChoreo resources + +## Featured Examples + +### Go Greeting Service from Source + +Learn OpenChoreo fundamentals by deploying a simple Go REST service built from source code. This example demonstrates the complete CI/CD workflow from source code to running service. + +**Features:** + +- Source-to-deployment workflow +- Docker-based CI process +- REST API with greeting endpoints +- Gateway integration and testing + +**Try it:** Go Docker Greeter + +### Google Cloud Microservices Demo + +Build a complete e-commerce platform using Google's reference microservices architecture. This comprehensive example demonstrates service-to-service communication, distributed systems patterns, and complex application deployment. + +**Features:** + +- 11 interconnected microservices +- Frontend web application +- Redis cache integration +- Production-ready container images +- Service mesh communication patterns + +**Try it:** GCP Microservices Demo + +### Multi-Environment Deployment Pipeline + +Set up sophisticated deployment pipelines across development, QA, pre-production, and production environments with automated promotion workflows. + +**Features:** + +- Four-stage deployment pipeline +- Environment-to-environment promotion +- Automated rollout workflows +- Production-ready governance + +**Try it:** New Deployment Pipeline + +--- + +## Community Examples + +The OpenChoreo community can contribute additional examples covering: + +- Industry-specific use cases +- Integration with third-party services +- Custom component types +- Advanced deployment patterns +- Custom workflows + +--- + +## Getting Help + +- **Documentation**: Each example includes instruction documentation +- **Community Forums**: Ask questions and share your implementations on Slack +- **GitHub Issues**: Report bugs or request new examples + +Ready to start building? Choose an example that matches your use case, then follow along to see OpenChoreo in action! diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-backstage-ui.png b/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-backstage-ui.png new file mode 100644 index 00000000..8d4a1c57 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-backstage-ui.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-install-status-success.png b/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-install-status-success.png new file mode 100644 index 00000000..ae1c1082 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/getting-started/qsg-install-status-success.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/quick-start-guide.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/quick-start-guide.mdx new file mode 100644 index 00000000..cf3da967 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/quick-start-guide.mdx @@ -0,0 +1,320 @@ +--- +title: Quick Start Guide +description: Try OpenChoreo with just Docker. Quick setup using a pre-configured container to create a local Kubernetes cluster with OpenChoreo and deploy a sample web application. +--- + +import CodeBlock from "@theme/CodeBlock"; +import Link from "@docusaurus/Link"; +import { versions, defaultCredentials } from "../_constants.mdx"; + +# Quick Start Guide + +Follow this guide to quickly set up OpenChoreo in a local environment with Docker. + +The setup uses a preconfigured Dev Container that includes all required dependencies for installation and cleanup. + +
+
⚙️ Prerequisites
+ + Ensure the following before you begin: + + - **Docker** (Engine [26.0+](https://docs.docker.com/engine/release-notes/26.0/) recommended) + - Allocate at least **4 GB RAM** and **2 CPUs**. + - If you plan to install with WorkflowPlane, allocate **8 GB RAM** and **4 CPUs** for optimal performance. + - **5-10** minutes of setup time + + :::note + If you encounter issues with Docker alternatives (Docker Desktop, Rancher Desktop, etc.), report them via + [GitHub](https://github.com/openchoreo/openchoreo/issues). + ::: + + :::tip Apple Silicon Macs + For optimal compatibility and to avoid buildpack build issues, we recommend using [Colima](https://github.com/abiosoft/colima) with VZ and Rosetta support. + + ```bash + colima start --vm-type=vz --vz-rosetta --cpu 4 --memory 8 + ``` + + ::: + +
+ +
+
+
1
+
Start the Dev Container
+
+ Run the following command to start the dev container and open a terminal session within it: + + + {String.raw`docker run --rm -it --name openchoreo-quick-start \ + --pull always \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --network=host \ + ghcr.io/openchoreo/quick-start:`}{versions.dockerTag} + + +
+ +
+
+
2
+
Install OpenChoreo
+
+ + Inside the container, run the installation command: + + + {`./install.sh --version ${versions.dockerTag}`} + + + This command performs the following: + + - Creates a local [k3d](https://k3d.io/) (k3s-in-Docker) cluster + - Installs OpenChoreo and its dependencies using Helm charts + + :::tip + The installation script is idempotent. You can rerun it safely if the process is interrupted. + ::: + + When installation completes successfully, you see a summary of component statuses: + + Installation Success Screenshot + + :::tip + If any components remain in the `pending` state, wait a few minutes and run the following command to check their + status: + + ```bash + ./check-status.sh + ``` + ::: + +
+ +
+
+
3
+
Deploy a Sample Web Application
+
+ + After setting up OpenChoreo in your Docker environment, deploy a sample web application by running: + + ```bash + ./deploy-react-starter.sh + ``` + + When deployment completes, the output includes a message with the application URL: + + ```text + [SUCCESS] React Starter web application is ready! + 🌍 Access the application at: http://react-starter-development-default.openchoreoapis.localhost:19080 + Open this URL in your browser to see the React starter application. + + [INFO] To clean up and delete this application, run: + [INFO] ./deploy-react-starter.sh --clean + ``` + +
+ +
+
+
4
+
Access the Backstage UI
+
+ + Now that your web application is deployed, access the OpenChoreo Backstage UI to explore and manage your components: + + Access the UI at: http://openchoreo.localhost:8080/ + + Default login credentials: + - Username: {defaultCredentials.username} + - Password: {defaultCredentials.password} + + Backstage UI Screenshot + + + Take some time to explore the interface where you can: + - View your deployed components + - Monitor application status + - Access component catalogs + - Manage deployment pipelines + + :::note + To access advanced features like **CI/CD pipelines** (Workflow Plane) and **Observability** (Observability Plane) within the UI, you can enable them by including the following flags during installation: + + {`./install.sh --version ${versions.dockerTag} --with-build --with-observability`} + + ::: + +
+ +
+ + ### Understanding the Setup + + Running the installation and deployment commands initializes OpenChoreo locally and deploys a sample web + application. + The following sections describe what occurs behind the scenes. + + #### 1. The Install Command + + The installation process: + + - Initializes a Dev Container with all required tools. + - Creates a k3d (k3s-in-Docker) cluster in Docker. + - Installs the OpenChoreo IDP and dependencies using Helm charts. + + #### Foundation Resources Created + + The installation automatically provisions the following OpenChoreo abstractions: + + - Namespace (Kubernetes namespace labeled with `openchoreo.dev/control-plane: true`) + - Cluster Data Plane + - Cluster Workflow Plane *(only when installed with `--with-build`)* + - Environments (e.g., Development, Staging, Production) + - [Deployment Pipeline](../reference/api/platform/deployment-pipeline.md) + - Project + - Cluster Component Types (e.g., service, web-application, scheduled-task) + - Cluster Workflows *(only when installed with `--with-build`)* + - Cluster Traits (e.g., observability-alert-rule) + + Cluster-scoped resources like these are automatically visible to all namespaces, so additional namespaces can start deploying without any extra setup. Namespace-scoped variants are available if you need to customize or isolate resources for a specific namespace. + + View these resources using the following commands: + + ```bash + kubectl get namespaces -l openchoreo.dev/control-plane=true + kubectl get clusterdataplanes + kubectl get environments + kubectl get projects + kubectl get clustercomponenttypes + ``` + + View details for a specific resource: + + ```bash + kubectl get project default -oyaml + ``` + + #### 2. Deploy Command + + The deployment script creates: + + - A sample Web Application Component + - The corresponding Deployment resource + + List deployed components: + + ```bash + kubectl get components + ``` + + #### 3. UI Architecture + + The Backstage UI is powered by the OpenChoreo Backstage plugin, providing a unified interface for managing your components and deployments. The authentication and user management is handled by ThunderID, a lightweight identity management platform that secures access to your OpenChoreo environment. + + :::tip + Explore more examples in the Samples directory or in + `/samples` inside the Dev Container. + ::: + + :::important + When running samples in the Dev Container, you don't need to expose the OpenChoreo Gateway manually; it's already + available on port 19080 (HTTP) and port 19443 (HTTPS) of the host machine. + ::: + +
+ +
+ + ## Explore More + + After deploying your first application, try these additional examples to explore more of OpenChoreo's capabilities: + + ### GCP Microservices Demo + + Deploy a complete microservices application with 11 services (frontend, cart, checkout, payment, etc.): + + ```bash + ./deploy-gcp-demo.sh + ``` + + This demonstrates how OpenChoreo handles multi-service applications and service-to-service communication. + + ### Build and Deploy from Source + + Experience the full development workflow by building a container image from source code and deploying it: + + ```bash + ./build-deploy-greeter.sh + ``` + + :::note + This example requires the Workflow Plane. If you didn't install it initially, reinstall with: + + + {`./install.sh --version ${versions.dockerTag} --with-build`} + + ::: + + This demonstrates: + - Building container images from source + - Storing images in the integrated container registry + - Deploying the built image to the Data Plane + + ### Understand What OpenChoreo Created + + Want to understand the resources OpenChoreo created behind the scenes? Follow the [Deploy and Explore](./deploy-and-explore.mdx) guide to walk through the full resource chain. + +
+ +
+
+
5
+
Cleaning up
+
+ + After completing your work, choose one of the following options: + + 1. **Exit and return later**: Exit the Dev Container to resume work later: + ```bash + exit + ``` + 2. **Full cleanup**: Remove all resources and restore a clean environment: + ```bash + ./uninstall.sh + exit + ``` + + This completes the setup and teardown process for OpenChoreo. + +
+ +
+ ## Troubleshooting + + ### Docker Resource Constraints + + If installation fails, confirm Docker has sufficient resources: + + ```bash + docker run --rm alpine:latest sh -c "echo 'Memory:'; free -h; echo; echo 'CPU Cores:'; nproc" + ``` + + Ensure at least **4 GB RAM** and **2 CPU cores** are allocated (or **8 GB RAM** and **4 CPU cores** if using + WorkflowPlane). + +
+ +You have now set up OpenChoreo locally using a preconfigured environment, deployed a sample web application, and learned how to inspect, manage, and clean up the setup. +This environment serves as a reproducible baseline for testing and evaluating OpenChoreo components and workflows. diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally.mdx new file mode 100644 index 00000000..f41732a7 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally.mdx @@ -0,0 +1,971 @@ +--- +title: Run Locally on K3d +description: Run OpenChoreo on K3d locally. Install each plane step-by-step, verify it works, and understand what every piece does. +sidebar_position: 1 +--- + +import CodeBlock from "@theme/CodeBlock"; +import Link from "@docusaurus/Link"; +import { versions, defaultCredentials } from "../../_constants.mdx"; +import { SetupSwitch, SetupOption } from "@site/src/components/SetupSwitch"; + +# Run OpenChoreo on K3d Locally + +This guide runs all four OpenChoreo planes on your machine, in a single k3d cluster. + +OpenChoreo has four planes: + +- **Control Plane** runs the API, console, identity provider, and controllers. +- **Data Plane** runs your workloads and routes traffic to them. +- **Workflow Plane** builds container images from source using Argo Workflows. +- **Observability Plane** collects logs and metrics from the other planes. + +By the end you'll have a working installation on localhost: a web app you can open in your browser, a source-to-image build pipeline, and log collection. + +## Prerequisites + +| Tool | Version | Purpose | +| -------------------------------------------------- | ---------------------- | ------------------------- | +| [Docker](https://docs.docker.com/get-docker/) | v26+ (8 GB RAM, 4 CPU) | Container runtime | +| [k3d](https://k3d.io/stable/#installation) | v5.8+ | Local Kubernetes clusters | +| [kubectl](https://kubernetes.io/docs/tasks/tools/) | v1.33+ | Kubernetes CLI | +| [Helm](https://helm.sh/docs/intro/install/) | v3.12+ | Package manager | + +Verify everything is installed: + +```bash +docker --version +k3d --version +kubectl version --client +helm version --short +``` + +Verify container runtime is running: + +```bash +docker info > /dev/null +``` + +:::tip Apple Silicon Macs +For optimal compatibility and to avoid buildpack build issues, we recommend using [Colima](https://github.com/abiosoft/colima) with VZ and Rosetta support. + +```bash +colima start --vm-type=vz --vz-rosetta --cpu 4 --memory 8 +``` + +::: + +## Install + +Pick how you want to install it: + + + + + +Run the following command. `--with-build` adds the workflow plane and `--with-observability` adds the observability plane. Drop either flag to skip that plane. + + + {`curl -fsSL https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/k3d-install.sh | bash -s -- --version ${versions.dockerTag} --with-build --with-observability`} + + +The script creates the k3d cluster and installs all four planes. Once it finishes, try it out below. + + + + + +Install OpenChoreo by hand, one plane at a time. Work through each step in order. + +## Step 1: Create the Cluster + +:::note[Colima users] +If you are using [Colima](https://github.com/abiosoft/colima) as your container runtime, run `export K3D_FIX_DNS=0` before the cluster create command to avoid DNS resolution issues inside the cluster. +::: + + + {`curl -fsSL https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/config.yaml | k3d cluster create --config=-`} + + +This creates a cluster named `openchoreo`. Your kubectl context is now `k3d-openchoreo`. + +## Step 2: Install Prerequisites + +These are third-party components that OpenChoreo depends on. None of them are OpenChoreo-specific, they are standard Kubernetes building blocks. + +#### Gateway API CRDs + +The [Gateway API](https://gateway-api.sigs.k8s.io/) is the Kubernetes-native way to manage ingress and routing. OpenChoreo uses it to route traffic to workloads in every plane. + +```bash +kubectl apply --server-side \ + -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml +``` + +#### cert-manager + +[cert-manager](https://cert-manager.io/) automates TLS certificate management. OpenChoreo uses it to issue certificates for internal communication between planes and for gateway TLS. + +```bash +helm upgrade --install cert-manager oci://quay.io/jetstack/charts/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --version v1.19.4 \ + --set crds.enabled=true \ + --wait --timeout 180s +``` + +#### External Secrets Operator + +[External Secrets Operator](https://external-secrets.io/) syncs secrets from external providers into Kubernetes. OpenChoreo uses it to pull secrets from a `ClusterSecretStore` into the right namespaces. For alternative backends, see [Secret Management](../../platform-engineer-guide/secret-management.mdx). + +```bash +helm upgrade --install external-secrets oci://ghcr.io/external-secrets/charts/external-secrets \ + --namespace external-secrets \ + --create-namespace \ + --version 2.0.1 \ + --set installCRDs=true \ + --wait --timeout 180s +``` + +#### kgateway + +[kgateway](https://kgateway.dev/) is the Gateway API implementation that actually handles traffic. It watches for `Gateway` and `HTTPRoute` resources across **all namespaces**, so installing it once is enough. Every plane creates its own `Gateway` resource in its own namespace, and this single kgateway controller manages all of them. + +```bash +helm upgrade --install kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \ + --create-namespace --namespace openchoreo-control-plane \ + --version v2.3.1 +``` + +```bash +helm upgrade --install kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \ + --namespace openchoreo-control-plane --create-namespace \ + --version v2.3.1 +``` + +#### OpenBao (Secret Backend) + +OpenChoreo uses [External Secrets Operator](https://external-secrets.io/) to manage secrets. All secrets are stored in a `ClusterSecretStore` named `default` and synced into the right namespaces using `ExternalSecret` resources. For this guide we use [OpenBao](https://openbao.org/) (an open-source Vault fork) as the secret backend. In production you can swap it for any ESO-supported provider by replacing the `default` ClusterSecretStore. + + + {`helm upgrade --install openbao oci://ghcr.io/openbao/charts/openbao \\ + --namespace openbao \\ + --create-namespace \\ + --version 0.25.6 \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-openbao.yaml \\ + --wait --timeout 300s`} + + +The values file runs a postStart script that configures Kubernetes auth, creates reader/writer policies, and seeds the following secrets into the store: + +| Secret | Value | Used By | +| ------------------------------ | ------------------------------ | ------------------------------ | +| `backstage-backend-secret` | `local-dev-backend-secret` | Backstage session signing | +| `backstage-client-secret` | `backstage-portal-secret` | Backstage OAuth with ThunderID | +| `backstage-jenkins-api-key` | `placeholder-not-in-use` | Placeholder | +| `observer-oauth-client-secret` | `openchoreo-observer-secret` | Observer OAuth with ThunderID | +| `rca-oauth-client-secret` | `openchoreo-rca-agent-secret` | SRE Agent OAuth with ThunderID | +| `opensearch-username` | `admin` | OpenSearch access | +| `opensearch-password` | `ThisIsTheOpenSearchPassword1` | OpenSearch access | + +#### Create the ClusterSecretStore + +```bash +kubectl apply -f - < + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/coredns-custom.yaml`} + + +## Step 3: Setup Control Plane + +The control plane is the brain of OpenChoreo. It runs the API server, the web console, the identity provider, and the controllers that reconcile your resources. + +### Install ThunderID (Identity Provider) + +[ThunderID](https://github.com/thunder-id/thunderid) handles authentication and OAuth flows. The values file includes bootstrap scripts that run on first startup and configure the organization, users, groups, and OAuth applications automatically. + + + {`helm upgrade --install thunder oci://ghcr.io/asgardeo/helm-charts/thunder \\ + --namespace thunder \\ + --create-namespace \\ + --version 0.28.0 \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-thunder.yaml`} + + +Wait for ThunderID to be ready: + +```bash +kubectl wait -n thunder \ + --for=condition=available --timeout=300s deployment -l app.kubernetes.io/name=thunder +``` + +#### Backstage Secrets + +The web console (Backstage) needs a backend secret for session signing and an OAuth client secret to authenticate with ThunderID. This pulls values from the `ClusterSecretStore` created earlier: + +```bash +kubectl apply -f - < + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --create-namespace \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/values-cp.yaml`} + + +Wait for all deployments to come up: + +```bash +kubectl wait -n openchoreo-control-plane \ + --for=condition=available --timeout=300s deployment --all +``` + +:::note[Internal API authentication] +On this version, mutual TLS on the Cluster Gateway's **internal API** (port `:8444`) is **enabled by default**, and the chart wires up the internal CA and client certificates automatically — so this single-cluster setup works end to end with no extra steps. If you want to reach `:8444` directly for debugging (for example via `kubectl port-forward`), you'll need a client certificate signed by the internal CA, or you can disable enforcement by appending `--set clusterGateway.internalMtls.enabled=false` to the install command above. See [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for the full trust model. +::: + +#### What Got Installed + +Here is what is now running in and around the control plane: + +- **controller-manager** reconciles OpenChoreo resources (Projects, Components, Environments, etc.) +- **openchoreo-api** is the REST API the console and CLI talk to +- **backstage** is the web console +- **cluster-gateway** accepts WebSocket connections from agents in remote planes +- **gateway** (managed by kgateway) routes external traffic to services + +In the `thunder` namespace: + +- **thunder** handles authentication and OAuth flows + +:::tip[ThunderID Admin Console] +You can browse and modify the bootstrapped identity configuration (users, groups, OAuth applications) in the ThunderID console at [http://thunder.openchoreo.localhost:8080/console](http://thunder.openchoreo.localhost:8080/console) using `admin` / `admin`. For details on what the bootstrap configured, see the [On Your Environment](on-your-environment.mdx) guide. +::: + +## Step 4: Install Default Resources + +OpenChoreo needs some base resources before you can deploy anything: a project, environments, component types, and a deployment pipeline. These define what kinds of things you can build and where they run. + + + {`kubectl label namespace default openchoreo.dev/control-plane=true --overwrite && \\ +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/all.yaml`} + + +**What was created:** + +- **Project**: `default` +- **Environments**: development, staging, production +- **DeploymentPipeline**: default (development -> staging -> production) +- **ClusterComponentTypes**: service, web-application, scheduled-task, worker +- **ClusterWorkflows**: docker, google-cloud-buildpacks, ballerina-buildpack, react +- **ClusterTraits**: observability-alert-rule + +Cluster-scoped resources (ClusterComponentType, ClusterWorkflow, ClusterTrait) are visible to all namespaces automatically, so any additional namespace you create will have access to them right away. + +## Step 5: Setup Data Plane + +The data plane is where your workloads actually run. It has its own gateway for routing traffic, and a cluster-agent that connects back to the control plane to receive deployment instructions. + +#### Namespace and Certificates + +Each plane needs a copy of the cluster-gateway CA certificate so its agent can establish a trusted connection to the control plane. We read it directly from the cert-manager Secret that the control plane installation created. + +```bash +kubectl create namespace openchoreo-data-plane --dry-run=client -o yaml | kubectl apply -f - + +kubectl wait -n openchoreo-control-plane \ + --for=condition=Ready certificate/cluster-gateway-ca --timeout=120s + +CA_CRT=$(kubectl get secret cluster-gateway-ca \ + -n openchoreo-control-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl create configmap cluster-gateway-ca \ + --from-literal=ca.crt="$CA_CRT" \ + -n openchoreo-data-plane --dry-run=client -o yaml | kubectl apply -f - +``` + +### Install the Data Plane + + + {`helm upgrade --install openchoreo-data-plane ${versions.helmSource}/openchoreo-data-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-data-plane \\ + --create-namespace \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/values-dp.yaml`} + + +### Register the Data Plane + +The `ClusterDataPlane` resource tells the control plane about this data plane. It includes the agent's CA certificate (so the control plane trusts its WebSocket connection) and the gateway's public address (so the control plane knows how to route traffic to workloads). As a cluster-scoped resource, it is visible to all namespaces. + +```bash +kubectl wait -n openchoreo-data-plane \ + --for=condition=Ready certificate/cluster-agent-dataplane-tls --timeout=120s + +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-data-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl apply -f - < + {`helm repo add twuni https://twuni.github.io/docker-registry.helm && helm repo update && \\ +helm upgrade --install registry twuni/docker-registry \\ + --namespace openchoreo-workflow-plane \\ + --create-namespace \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/values-registry.yaml`} + + +### Install the Workflow Plane + + + {`helm upgrade --install openchoreo-workflow-plane ${versions.helmSource}/openchoreo-workflow-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-workflow-plane \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/values-wp.yaml`} + + +#### Install Workflow Templates + +Build pipelines are defined as ClusterWorkflowTemplates. Each build workflow (docker, react, etc.) is composed from smaller shared templates: a **checkout step** (controls how source code is cloned), **build coordinator templates** (docker, react, ballerina-buildpack, google-cloud-buildpacks), and a **publish step** (controls where built images get pushed). For k3d, the publish step targets the local registry at `host.k3d.internal:10082`. In a real environment you would point it at ECR, GAR, GHCR, or whatever registry you use. + + + {`kubectl apply \\ + -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/checkout-source.yaml \\ + -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates.yaml \\ + -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/publish-image-k3d.yaml \\ + -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/generate-workload-k3d.yaml`} + + +### Register the Workflow Plane + +```bash +kubectl wait -n openchoreo-workflow-plane \ + --for=condition=Ready certificate/cluster-agent-workflowplane-tls --timeout=120s +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-workflow-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl apply -f - < + {`helm upgrade --install build-cache project-zot/zot \\ + -n openchoreo-workflow-plane --create-namespace \\ + -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/build-cache/values-zot.yaml`} + + +Wait for it to become ready: + +```bash +kubectl -n openchoreo-workflow-plane rollout status statefulset/build-cache +``` + +#### Patch the Build Templates + +Update the in-cluster `ClusterWorkflowTemplate` resources so builds accept cache parameters and mount the mirror config: + + + {`BASE=https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/build-cache/workflow-templates + +for tmpl in containerfile-build paketo-buildpacks-build gcp-buildpacks-build ballerina-buildpack-build; do +kubectl apply -f "$BASE/$tmpl.yaml" +done`} + + + +#### Patch the CI Workflows + +Patch the CI `ClusterWorkflow` resources so component authors can control caching with a structured `cache` parameter. This adds the `cache` schema, passes layer-cache settings to the build templates, and creates a per-run `registries-conf` ConfigMap when mirror caching is enabled: + +```bash +CACHE_DESC="Build cache configuration. mirror.enabled controls upstream image pull-through caching via a mounted registries.conf. layers.mode controls layer cache behavior: disabled, reuse, or rebuild." + +REGISTRIES_CONF='[[registry]] +location = "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100" +insecure = true + +[[registry]] +location = "docker.io" +[[registry.mirror]] +location = "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100/mirror/docker.io" +insecure = true + +[[registry]] +location = "gcr.io" +[[registry.mirror]] +location = "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100/mirror/gcr.io" +insecure = true + +[[registry]] +location = "ghcr.io" +[[registry.mirror]] +location = "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100/mirror/ghcr.io" +insecure = true + +[[registry]] +location = "quay.io" +[[registry.mirror]] +location = "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100/mirror/quay.io" +insecure = true' + +for workflow in dockerfile-builder paketo-buildpacks-builder gcp-buildpacks-builder ballerina-buildpack-builder; do + kubectl get clusterworkflow "$workflow" -o yaml | \ + yq ' + del( + .metadata.creationTimestamp, + .metadata.generation, + .metadata.managedFields, + .metadata.resourceVersion, + .metadata.uid, + .status + ) | + + .spec.parameters.openAPIV3Schema.properties.cache = { + "type": "object", + "default": { + "mirror": {"enabled": true}, + "layers": {"mode": "reuse"} + }, + "description": "'"$CACHE_DESC"'", + "properties": { + "mirror": { + "type": "object", + "default": {"enabled": true}, + "properties": { + "enabled": { + "type": "boolean", + "default": true, + "description": "Pull upstream builder, run, lifecycle, and base images through the workflow-plane cache registry when available" + } + } + }, + "layers": { + "type": "object", + "default": {"mode": "reuse"}, + "properties": { + "mode": { + "type": "string", + "default": "reuse", + "enum": ["disabled", "reuse", "rebuild"], + "description": "Layer cache mode: disabled skips cache, reuse reads and writes cache, rebuild ignores existing cache and writes a fresh cache" + } + } + } + } + } | + + .spec.runTemplate.spec.arguments.parameters |= + [.[] | select(.name != "build-cache" and .name != "cache-layers-mode")] + + [ + {"name": "build-cache", "value": "build-cache.openchoreo-workflow-plane.svc.cluster.local:5100"}, + {"name": "cache-layers-mode", "value": "${parameters.cache.layers.mode}"} + ] | + + .spec.runTemplate.spec.templates[0].steps[1][0].arguments.parameters |= + [.[] | select(.name != "build-cache" and .name != "cache-layers-mode")] + + [ + {"name": "build-cache", "value": "{{workflow.parameters.build-cache}}"}, + {"name": "cache-layers-mode", "value": "{{workflow.parameters.cache-layers-mode}}"} + ] | + + .spec.resources = (.spec.resources // []) | + del(.spec.resources[] | select(.id == "build-registries-conf")) | + .spec.resources += [ + { + "id": "build-registries-conf", + "includeWhen": "${parameters.cache.mirror.enabled}", + "template": { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "name": "${metadata.workflowRunName}-registries-conf", + "namespace": "${metadata.namespace}" + }, + "data": { + "mirrors.conf": "" + } + } + } + ] + ' | \ + REGISTRIES_CONF="$REGISTRIES_CONF" yq ' + (.spec.resources[] | select(.id == "build-registries-conf")).template.data."mirrors.conf" = strenv(REGISTRIES_CONF) | + (.spec.resources[] | select(.id == "build-registries-conf")).template.data."mirrors.conf" style="literal" + ' | kubectl apply -f - + + echo "Patched $workflow" +done +``` + +Once patched, components control caching with a `cache` parameter: + +```yaml +parameters: + cache: + mirror: + enabled: true + layers: + mode: reuse # disabled | reuse | rebuild +``` + +Layer caching supports three modes: + +| Mode | Read cache | Write cache | Use case | +| ---------- | ---------- | ----------- | ---------------------------------------------- | +| `disabled` | No | No | Fully uncached build | +| `reuse` | Yes | Yes | Normal fast builds | +| `rebuild` | No | Yes | Clean build that refreshes the cache for later | + +See the build cache guide for a deeper look at how caching works—image mirroring, layer cache reference paths, and how builds gracefully degrade when the cache is unavailable. + +## Step 7: Setup Observability Plane (Optional) + +OpenChoreo follows a modular architecture. The observability plane consists of system services plus various [observability modules](https://openchoreo.dev/modules/) that you can install to get observability features. +For example, if you require observability logs features, you can install a logs module. +This guide installs the observability plane with OpenSearch-based logs and tracing modules and a Prometheus-based metrics module by default. + +#### Namespace and Certificates + +```bash +kubectl create namespace openchoreo-observability-plane --dry-run=client -o yaml | kubectl apply -f - + +CA_CRT=$(kubectl get secret cluster-gateway-ca \ + -n openchoreo-control-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl create configmap cluster-gateway-ca \ + --from-literal=ca.crt="$CA_CRT" \ + -n openchoreo-observability-plane --dry-run=client -o yaml | kubectl apply -f - +``` + +#### Observability Plane Secrets + +The observability plane requires secrets for OpenSearch access and Observer authentication. This pulls values from the `ClusterSecretStore` created earlier: + +```bash +kubectl apply -f - < /etc/machine-id" +``` + +### Install the Observability Plane + +A functional observability stack consists of the observability plane core services, logs module, traces module, and metrics module. + +#### Install the observability plane core + + + {`helm upgrade --install openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/single-cluster/values-op.yaml \\ + --timeout 25m`} + + +#### Install the OpenSearch-based logs module + +```bash +helm upgrade --install observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" \ + --set adapter.openSearchSecretName="opensearch-admin-credentials" +``` + +#### Install the OpenSearch-based traces module + +```bash +helm upgrade --install observability-traces-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-tracing-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.0 \ + --set openSearch.enabled=false \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" +``` + +#### Install the Prometheus-based metrics module + +```bash +helm upgrade --install observability-metrics-prometheus \ + oci://ghcr.io/openchoreo/helm-charts/observability-metrics-prometheus \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.1 +``` + +#### Enable logs collection in the configured logs module + +```bash +helm upgrade observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --reuse-values \ + --set fluent-bit.enabled=true +``` + +#### Enable kubernetes events collection and exporting to logs module + +```bash +helm upgrade --install observability-events-otel-collector \ + oci://ghcr.io/openchoreo/helm-charts/observability-events-otel-collector \ + --namespace openchoreo-observability-plane \ + --version 0.1.1 \ + -f - <<'EOF' +collector: + extraEnv: + - name: OPENSEARCH_USERNAME + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: username + - name: OPENSEARCH_PASSWORD + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: password +extraExtensions: + basicauth/opensearch: + client_auth: + username: ${env:OPENSEARCH_USERNAME} + password: ${env:OPENSEARCH_PASSWORD} +exporters: + opensearch: + logs_index: "k8s-events" + logs_index_time_format: "yyyy-MM-dd" + http: + endpoint: "https://opensearch:9200" + tls: + insecure_skip_verify: true + auth: + authenticator: basicauth/opensearch +pipelineExporters: + - opensearch +EOF +``` + +### Register the Observability Plane + +```bash +kubectl wait -n openchoreo-observability-plane \ + --for=condition=Ready certificate/cluster-agent-observabilityplane-tls --timeout=120s + +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-observability-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl apply -f - < + + + +## Try it Out + +### Log in to OpenChoreo + +Open [http://openchoreo.localhost:8080](http://openchoreo.localhost:8080) in your browser. + +Log in with the default credentials: + +| Username | Password | +| ------------------------------------------ | ------------------------------------------ | +| {defaultCredentials.username} | {defaultCredentials.password} | + +You should see the OpenChoreo console. The control plane is working. + +### Deploy the React Starter App + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-image/react-starter-web-app/react-starter.yaml`} + + +Wait for the deployment to come up: + +```bash +kubectl wait --for=condition=available deployment \ + -l openchoreo.dev/component=react-starter -A --timeout=120s +``` + +Get the application URL: + +```bash +HOSTNAME=$(kubectl get httproute -A -l openchoreo.dev/component=react-starter \ + -o jsonpath='{.items[0].spec.hostnames[0]}') +echo "http://${HOSTNAME}:19080" +``` + +Open that URL in your browser. You should see the React starter application running. + +The data plane is routing traffic to your workload through the gateway. + +### Build from Source + +:::note[Workflow Plane] +The workflow plane is required to build from source. If you haven't installed it yet, see [Step 6: Setup Workflow Plane (Optional)](./on-k3d-locally.mdx#step-6-setup-workflow-plane-optional). +::: + +Apply a sample component that builds a Go service from source: + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-source/services/go-docker-greeter/greeting-service.yaml`} + + +Watch the build progress: + +```bash +kubectl get workflow -n workflows-default --watch +``` + +You can also open the Argo Workflows UI at [http://localhost:10081](http://localhost:10081) to see the build pipeline visually (this port was mapped when you created the k3d cluster in Step 1). + +After the build completes, wait for the deployment: + +```bash +kubectl wait --for=condition=available deployment \ + -l openchoreo.dev/component=greeting-service -A --timeout=300s +``` + +Resolve the hostname and path, then call the service: + +```bash +HOSTNAME=$(kubectl get httproute -A -l openchoreo.dev/component=greeting-service \ + -o jsonpath='{.items[0].spec.hostnames[0]}') +PATH_PREFIX=$(kubectl get httproute -A -l openchoreo.dev/component=greeting-service \ + -o jsonpath='{.items[0].spec.rules[0].matches[0].path.value}') + +curl "http://${HOSTNAME}:19080${PATH_PREFIX}/greeter/greet" +``` + +OpenChoreo built your code, pushed the image to the local registry, and deployed it to the data plane. + +## Cleanup + +Delete the cluster and everything in it: + +```bash +k3d cluster delete openchoreo +``` + +## Next Steps + +- Follow [Deploy and Explore](../deploy-and-explore.mdx) to understand the resources OpenChoreo creates +- Explore the sample applications +- Read the [Deployment Topology](../../platform-engineer-guide/deployment-topology.mdx) guide for production setups +- Learn about [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for separating planes across clusters diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-observability-plane.sh b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-observability-plane.sh new file mode 100644 index 00000000..60f7a379 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-observability-plane.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set -euo pipefail + +VERSION=$1 +GITHUB_REF=${2:-main} + +step() { + echo "" + echo "==> $1" +} + +step "Installing observability plane core services..." +helm upgrade --install openchoreo-observability-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-observability-plane \ + --version $VERSION \ + --namespace openchoreo-observability-plane \ + --values "https://raw.githubusercontent.com/openchoreo/openchoreo/${GITHUB_REF}/install/k3d/single-cluster/values-op.yaml" \ + --timeout 25m + +step "Installing OpenSearch-based logs module..." +helm upgrade --install observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" + +step "Installing OpenSearch-based traces module..." +helm upgrade --install observability-traces-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-tracing-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.0 \ + --set openSearch.enabled=false \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" + +step "Installing Prometheus-based metrics module..." +helm upgrade --install observability-metrics-prometheus \ + oci://ghcr.io/openchoreo/helm-charts/observability-metrics-prometheus \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.1 + +step "Enabling logs collection in the configured logs module..." +helm upgrade observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --reuse-values \ + --set fluent-bit.enabled=true + +step "Enabling kubernetes events collection and exporting to logs module..." +helm upgrade --install observability-events-otel-collector \ + oci://ghcr.io/openchoreo/helm-charts/observability-events-otel-collector \ + --namespace openchoreo-observability-plane \ + --version 0.1.1 \ + -f - <<'EOF' +collector: + extraEnv: + - name: OPENSEARCH_USERNAME + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: username + - name: OPENSEARCH_PASSWORD + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: password +extraExtensions: + basicauth/opensearch: + client_auth: + username: ${env:OPENSEARCH_USERNAME} + password: ${env:OPENSEARCH_PASSWORD} +exporters: + opensearch: + logs_index: "k8s-events" + logs_index_time_format: "yyyy-MM-dd" + http: + endpoint: "https://opensearch:9200" + tls: + insecure_skip_verify: true + auth: + authenticator: basicauth/opensearch +pipelineExporters: + - opensearch +EOF + +echo "" +echo "==> Observability plane and default modules installed successfully." diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-prerequisites.sh b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-prerequisites.sh new file mode 100755 index 00000000..79cf082d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-k3d-locally/k3d-prerequisites.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + + +step() { + echo "" + echo "==> $1" +} + +step "Installing Gateway API CRDs..." +kubectl apply --server-side \ + -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml + +step "Installing cert-manager..." +helm upgrade --install cert-manager oci://quay.io/jetstack/charts/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --version v1.19.4 \ + --set crds.enabled=true \ + --wait --timeout 180s + +step "Installing External Secrets Operator..." +helm upgrade --install external-secrets oci://ghcr.io/external-secrets/charts/external-secrets \ + --namespace external-secrets \ + --create-namespace \ + --version 2.0.1 \ + --set installCRDs=true \ + --wait --timeout 180s + +step "Installing kgateway CRDs..." +helm upgrade --install kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \ + --create-namespace --namespace openchoreo-control-plane \ + --version v2.3.1 + +step "Installing kgateway..." +helm upgrade --install kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \ + --namespace openchoreo-control-plane --create-namespace \ + --version v2.3.1 + +step "Installing OpenBao..." +helm upgrade --install openbao oci://ghcr.io/openbao/charts/openbao \ + --namespace openbao \ + --create-namespace \ + --version 0.25.6 \ + --values "https://raw.githubusercontent.com/openchoreo/openchoreo/main/install/k3d/common/values-openbao.yaml" \ + --wait --timeout 300s + +step "Creating ClusterSecretStore and ServiceAccount..." +kubectl apply -f - <<'EOF' +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-openbao + namespace: openbao +--- +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: default +spec: + provider: + vault: + server: "http://openbao.openbao.svc:8200" + path: "secret" + version: "v2" + auth: + kubernetes: + mountPath: "kubernetes" + role: "openchoreo-secret-writer-role" + serviceAccountRef: + name: "external-secrets-openbao" + namespace: "openbao" +EOF + +step "Configuring CoreDNS rewrite..." +kubectl apply -f "https://raw.githubusercontent.com/openchoreo/openchoreo/main/install/k3d/common/coredns-custom.yaml" + +echo "" +echo "==> All prerequisites installed successfully." diff --git a/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-your-environment.mdx b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-your-environment.mdx new file mode 100644 index 00000000..7b316e06 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/getting-started/try-it-out/on-your-environment.mdx @@ -0,0 +1,1268 @@ +--- +title: Run in Your Environment +description: Run OpenChoreo on any Kubernetes cluster. Install each plane step-by-step, verify it works, and understand what every piece does. +sidebar_position: 2 +--- + +import CodeBlock from "@theme/CodeBlock"; +import Link from "@docusaurus/Link"; +import { versions, defaultCredentials } from "../../_constants.mdx"; +import AgentSetupBuilder from "@site/src/components/AgentSetupBuilder"; +import { SetupSwitch, SetupOption } from "@site/src/components/SetupSwitch"; + +# Run OpenChoreo in Your Environment + +This guide runs OpenChoreo on any Kubernetes cluster (k3s, GKE, EKS, DOKS, AKS, or self-managed), using a **single-cluster topology** with all planes in one cluster. For split-cluster setups, follow [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx). For clusters without internet access, follow [Air-Gapped Installation](../../platform-engineer-guide/air-gapped-installation.mdx). + +Gateways use HTTPS with self-signed certificates by default; you can swap in certificates from a real CA later. + +OpenChoreo has four planes: + +- **Control Plane** runs the API, console, identity provider, and controllers. +- **Data Plane** runs your workloads and routes traffic to them. +- **Workflow Plane** builds container images from source using Argo Workflows. +- **Observability Plane** collects logs and metrics from the other planes. + +By the end you'll have OpenChoreo running on your cluster over HTTPS, reachable at a console URL through your LoadBalancer, with a web app deployed and, optionally, a source-to-image build pipeline and log collection. + +## Prerequisites + +| Tool | Version | Purpose | +| -------------------------------------------------- | ------- | --------------- | +| [kubectl](https://kubernetes.io/docs/tasks/tools/) | v1.33+ | Kubernetes CLI | +| [Helm](https://helm.sh/docs/intro/install/) | v3.12+ | Package manager | + +Recommended cluster baseline: Kubernetes 1.33+, LoadBalancer support, and a default StorageClass. + +:::warning User namespaces required +OpenChoreo's default build workflows run Argo Workflow pods that opt in to Kubernetes [user namespaces](https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/) by setting `hostUsers: false`. Use **Kubernetes 1.33 or newer**; Kubernetes 1.33 enables user namespaces by default when the node stack supports them. + +Every Linux node that can run Workflow Plane build pods must also provide: + +- **Linux kernel 6.3 or newer** +- **containerd 2.0 or newer** or **CRI-O 1.25 or newer** +- **runc 1.2 or newer** or **crun 1.9 or newer** + +See the [Kubernetes user namespaces guide](https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/) for details. +::: + +Verify everything is installed: + +```bash +kubectl version --client +helm version --short +kubectl get nodes +kubectl auth can-i '*' '*' --all-namespaces +``` + +Verify the node kernel and CRI runtime reported by Kubernetes: + +```bash +kubectl get nodes \ + -o custom-columns=NAME:.metadata.name,KERNEL:.status.nodeInfo.kernelVersion,RUNTIME:.status.nodeInfo.containerRuntimeVersion,KUBELET:.status.nodeInfo.kubeletVersion +``` + +## Install + +Pick how you want to install it: + + + + + +Install OpenChoreo by hand, one plane at a time. Work through each step in order. + +## Step 1: Install Prerequisites + +These are third-party components that OpenChoreo depends on. None of them are OpenChoreo-specific, they are standard Kubernetes building blocks. + +#### Gateway API CRDs + +The [Gateway API](https://gateway-api.sigs.k8s.io/) is the Kubernetes-native way to manage ingress and routing. OpenChoreo uses it to route traffic to workloads in every plane. + +```bash +kubectl apply --server-side \ + -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml +``` + +#### cert-manager + +[cert-manager](https://cert-manager.io/) automates TLS certificate management. OpenChoreo uses it to issue certificates for internal communication between planes and for gateway TLS. + +```bash +helm upgrade --install cert-manager oci://quay.io/jetstack/charts/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --version v1.19.4 \ + --set crds.enabled=true \ + --wait --timeout 180s +``` + +#### External Secrets Operator + +[External Secrets Operator](https://external-secrets.io/) syncs secrets from external providers into Kubernetes. OpenChoreo uses it to pull secrets from a `ClusterSecretStore` into the right namespaces. For alternative backends, see [Secret Management](../../platform-engineer-guide/secret-management.mdx). + +```bash +helm upgrade --install external-secrets oci://ghcr.io/external-secrets/charts/external-secrets \ + --namespace external-secrets \ + --create-namespace \ + --version 2.0.1 \ + --set installCRDs=true \ + --wait --timeout 180s +``` + +#### kgateway + +[kgateway](https://kgateway.dev/) is the Gateway API implementation that actually handles traffic. It watches for `Gateway` and `HTTPRoute` resources across **all namespaces**, so installing it once is enough. Every plane creates its own `Gateway` resource in its own namespace, and this single kgateway controller manages all of them. + +```bash +helm upgrade --install kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \ + --create-namespace --namespace openchoreo-control-plane \ + --version v2.3.1 +``` + +```bash +helm upgrade --install kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \ + --namespace openchoreo-control-plane --create-namespace \ + --version v2.3.1 +``` + +#### OpenBao (Secret Backend) + +OpenChoreo uses [External Secrets Operator](https://external-secrets.io/) to manage secrets. All secrets are stored in a `ClusterSecretStore` named `default` and synced into the right namespaces using `ExternalSecret` resources. This guide uses [OpenBao](https://openbao.org/) (an open-source Vault fork) as the secret backend. You can swap it for any ESO-supported provider by replacing the `default` ClusterSecretStore. See [Secret Management](../../platform-engineer-guide/secret-management.mdx) for details. + + + {`helm upgrade --install openbao oci://ghcr.io/openbao/charts/openbao \\ + --namespace openbao \\ + --create-namespace \\ + --version 0.25.6 \\ + --values https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-openbao.yaml \\ + --wait --timeout 300s`} + + +:::tip[Production] +For production, provide your own values file with `server.dev.enabled=false` and configure proper storage and unsealing. See the [OpenBao Helm chart docs](https://github.com/openbao/openbao-helm). +::: + +The values file runs a postStart script that configures Kubernetes auth, creates reader/writer policies, and seeds the following secrets into the store: + +| Secret | Value | Used By | +| ------------------------------ | --------------------------------------------------- | ------------------------------ | +| `backstage-backend-secret` | `local-dev-backend-secret` | Backstage session signing | +| `backstage-client-secret` | `backstage-portal-secret` | Backstage OAuth with ThunderID | +| `backstage-jenkins-api-key` | `placeholder-not-in-use` | Placeholder | +| `opensearch-username` | `admin` | OpenSearch access | +| `opensearch-password` | `ThisIsTheOpenSearchPassword1` | OpenSearch access | +| `observer-oauth-client-secret` | `openchoreo-observer-resource-reader-client-secret` | Observer OAuth (UID resolver) | + +#### Create the ClusterSecretStore + +```bash +kubectl apply -f - < + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --create-namespace \\ + --values - <<'EOF' +openchoreoApi: + http: + hostnames: + - "api.placeholder.tld" +backstage: + baseUrl: "https://console.placeholder.tld" + secretName: backstage-secrets + http: + hostnames: + - "console.placeholder.tld" +security: + oidc: + issuer: "https://thunder.placeholder.tld" +gateway: + tls: + enabled: false +EOF`} + + +Some pods will crash-loop at this point because ThunderID and Backstage secrets are not configured yet. That is expected. The only thing needed from this step is the Gateway's LoadBalancer address. + +
+EKS only: make the LoadBalancer internet-facing + +```bash +kubectl patch svc gateway-default -n openchoreo-control-plane \ + -p '{"metadata":{"annotations":{"service.beta.kubernetes.io/aws-load-balancer-scheme":"internet-facing"}}}' +``` + +
+ +Wait for the service to get an external address, then resolve it: + +```bash +kubectl get svc gateway-default -n openchoreo-control-plane -w +``` + +```bash +CP_LB_IP=$(kubectl get svc gateway-default -n openchoreo-control-plane -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +if [ -z "$CP_LB_IP" ]; then + CP_LB_HOSTNAME=$(kubectl get svc gateway-default -n openchoreo-control-plane -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + CP_LB_IP=$(dig +short "$CP_LB_HOSTNAME" | head -1) +fi + +export CP_BASE_DOMAIN="openchoreo.${CP_LB_IP//./-}.nip.io" +echo "Control plane base domain: ${CP_BASE_DOMAIN}" +echo " Console: console.${CP_BASE_DOMAIN}" +echo " API: api.${CP_BASE_DOMAIN}" +echo " ThunderID: thunder.${CP_BASE_DOMAIN}" +``` + +If your cluster returns only a hostname and `dig` is not available, use `nslookup` to resolve the IP, or use your own DNS domain instead of `nip.io`. + +#### Create the Control Plane TLS Certificate + +Issue a wildcard certificate covering all control plane subdomains: + +```bash +kubectl apply -f - < + {`curl -fsSL https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-thunder.yaml \\ + | sed "s#http://thunder.openchoreo.localhost:8080#https://thunder.\${CP_BASE_DOMAIN}#g" \\ + | sed "s#thunder.openchoreo.localhost#thunder.\${CP_BASE_DOMAIN}#g" \\ + | sed "s#http://openchoreo.localhost:8080#https://console.\${CP_BASE_DOMAIN}#g" \\ + | sed "s#port: 8080#port: 443#g" \\ + | sed 's#scheme: "http"#scheme: "https"#g' \\ + | helm upgrade --install thunder oci://ghcr.io/asgardeo/helm-charts/thunder \\ + --namespace thunder \\ + --create-namespace \\ + --version 0.28.0 \\ + --values -`} + + +Wait for ThunderID to be ready: + +```bash +kubectl wait -n thunder \ + --for=condition=available --timeout=300s deployment -l app.kubernetes.io/name=thunder +``` + +You can browse and modify the ThunderID configuration at: + +```bash +echo "https://thunder.${CP_BASE_DOMAIN}/console" +``` + +| Username | Password | +| -------- | -------- | +| `admin` | `admin` | + +#### Backstage Secrets + +The web console (Backstage) needs a backend secret for session signing and an OAuth client secret to authenticate with ThunderID: + +```bash +kubectl apply -f - < + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --values - < + +:::note[Internal API authentication] +Mutual TLS on the Cluster Gateway's **internal API** (port `:8444`, which proxies, execs, and streams logs into every connected plane) is **enabled by default** on this version, so no extra configuration is needed here — callers must present a certificate signed by a dedicated internal CA that cert-manager provisions automatically. To turn it off for local experimentation, set `clusterGateway.internalMtls.enabled=false`. See [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for the full trust model. +::: + +Update ThunderID's `HTTPRoute` to use the real domain: + + + {`helm upgrade thunder oci://ghcr.io/asgardeo/helm-charts/thunder \\ + --namespace thunder \\ + --version 0.28.0 \\ + --reuse-values \\ + --set "httproute.hostnames[0]=thunder.\${CP_BASE_DOMAIN}"`} + + +Wait for all deployments to come up: + +```bash +kubectl wait -n openchoreo-control-plane \ + --for=condition=available --timeout=300s deployment --all +``` + +#### Wait for Cluster Gateway CA + +The control plane creates a self-signed CA for internal communication between the cluster-gateway and cluster-agents. Wait for cert-manager to issue it before proceeding. Other planes will copy this CA certificate from the Secret directly. + +```bash +kubectl wait -n openchoreo-control-plane \ + --for=condition=Ready certificate/cluster-gateway-ca --timeout=120s +``` + +Verify HTTPS is working: + +```bash +curl -sk https://thunder.${CP_BASE_DOMAIN}/health/readiness +curl -sk https://api.${CP_BASE_DOMAIN}/health +curl -sk -o /dev/null -w "%{http_code}" https://console.${CP_BASE_DOMAIN}/ +``` + +## Step 4: Install Default Resources + +OpenChoreo needs some base resources before you can deploy anything: a project, environments, component types, and a deployment pipeline. + +Label the default namespace as a control plane namespace first, then apply the resources: + +```bash +kubectl label namespace default openchoreo.dev/control-plane=true --overwrite +``` + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/all.yaml`} + + +## Step 5: Setup Data Plane + +The data plane is where your workloads actually run. It has its own gateway for routing traffic, and a cluster-agent that connects back to the control plane to receive deployment instructions. + +#### Namespace and Certificates + +Each plane needs a copy of the cluster-gateway CA certificate so its agent can establish a trusted connection to the control plane. The CA is stored in the `cluster-gateway-ca` Secret created by cert-manager in the control plane namespace. + +```bash +kubectl create namespace openchoreo-data-plane --dry-run=client -o yaml | kubectl apply -f - + +kubectl get secret cluster-gateway-ca -n openchoreo-control-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d | \ + kubectl create configmap cluster-gateway-ca \ + --from-file=ca.crt=/dev/stdin \ + -n openchoreo-data-plane \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +### Install the Data Plane + + + {`helm upgrade --install openchoreo-data-plane ${versions.helmSource}/openchoreo-data-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-data-plane \\ + --create-namespace \\ + --set gateway.tls.enabled=false`} + + +:::note[Single IP LoadBalancer] +If your LoadBalancer provider assigns only one IP (common with self-hosted Kubernetes deployments), all gateway services will share that IP. Add `--set gateway.httpPort=8080 --set gateway.httpsPort=8443` to assign different ports so the single IP can be reused across planes. Make sure the `http.port` and `https.port` values in the `ClusterDataPlane` registration below match the ports you configured here. +::: + +:::note[Multi-cluster deployments] +When each plane runs in its own cluster, you typically get separate LoadBalancer IPs, so port conflicts are not an issue. However, if you use non-standard ports (e.g., NodePort), set `gateway.httpPort` and `gateway.httpsPort` accordingly and make sure `http.port` / `https.port` in the ClusterDataPlane registration match the externally reachable ports. See [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for the full setup. +::: + +
+EKS only: make the LoadBalancer internet-facing + +```bash +kubectl patch svc gateway-default -n openchoreo-data-plane \ + -p '{"metadata":{"annotations":{"service.beta.kubernetes.io/aws-load-balancer-scheme":"internet-facing"}}}' +``` + +
+ +Get the data plane IP and derive a domain: + +```bash +kubectl get svc gateway-default -n openchoreo-data-plane -w +``` + +```bash +DP_LB_IP=$(kubectl get svc gateway-default -n openchoreo-data-plane -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +if [ -z "$DP_LB_IP" ]; then + DP_LB_HOSTNAME=$(kubectl get svc gateway-default -n openchoreo-data-plane -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + DP_LB_IP=$(dig +short "$DP_LB_HOSTNAME" | head -1) +fi + +export DP_DOMAIN="apps.openchoreo.${DP_LB_IP//./-}.nip.io" +echo "Data plane domain: *.${DP_DOMAIN}" +``` + +#### Create the Data Plane TLS Certificate + +```bash +kubectl apply -f - < + {`helm upgrade openchoreo-data-plane ${versions.helmSource}/openchoreo-data-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-data-plane \\ + --reuse-values \\ + --values - < + +### Register the Data Plane + +The `ClusterDataPlane` resource tells the control plane about this data plane. It includes the agent's CA certificate (so the control plane trusts its WebSocket connection) and the gateway's public address (so the control plane knows how to route traffic to workloads). As a cluster-scoped resource, it is visible to all namespaces. + +:::note[Multi-cluster deployments] +When `clusterAgent.tls.generateCerts=true` is set (as in this guide), the agent creates its own self-signed CA stored in the `cluster-agent-tls` Secret. The `cluster-gateway-ca` Secret copied earlier is only used by the agent to trust the control plane's cluster-gateway server. The ClusterDataPlane registration must reference the agent's own CA so the cluster-gateway can verify incoming agent connections. See [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for details. +::: + +```bash +kubectl wait -n openchoreo-data-plane \ + --for=condition=Ready certificate/cluster-agent-dataplane-tls --timeout=120s + +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-data-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +DP_HTTP_PORT=$(kubectl get gateway gateway-default -n openchoreo-data-plane \ + -o jsonpath='{.spec.listeners[?(@.name=="http")].port}') +DP_HTTPS_PORT=$(kubectl get gateway gateway-default -n openchoreo-data-plane \ + -o jsonpath='{.spec.listeners[?(@.protocol=="HTTPS")].port}') + +kubectl apply -f - <{defaultCredentials.username} | {defaultCredentials.password} | + +You should see the OpenChoreo console. Deploy a sample web app: + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-image/react-starter-web-app/react-starter.yaml`} + + +```bash +kubectl wait --for=condition=available deployment \ + -l openchoreo.dev/component=react-starter -A --timeout=180s + +HOSTNAME=$(kubectl get httproute -A -l openchoreo.dev/component=react-starter \ + -o jsonpath='{.items[0].spec.hostnames[0]}') +DP_HTTPS_PORT=$(kubectl get gateway gateway-default -n openchoreo-data-plane \ + -o jsonpath='{.spec.listeners[?(@.protocol=="HTTPS")].port}') +PORT_SUFFIX=$([ "$DP_HTTPS_PORT" = "443" ] && echo "" || echo ":${DP_HTTPS_PORT}") + +echo "https://${HOSTNAME}${PORT_SUFFIX}" +``` + +Open that URL in your browser (accept the self-signed certificate warning). You should see the React starter application running. + +## Step 6: Setup Workflow Plane (Optional) + +The workflow plane takes source code, builds a container image, pushes it to a registry, and tells the control plane about the new image. It uses Argo Workflows to run build pipelines. + +#### Namespace and Certificates + +Same process as the data plane. Copy the cluster-gateway CA from the cert-manager Secret so the workflow plane's agent can connect to the control plane: + +```bash +kubectl create namespace openchoreo-workflow-plane --dry-run=client -o yaml | kubectl apply -f - + +kubectl get secret cluster-gateway-ca -n openchoreo-control-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d | \ + kubectl create configmap cluster-gateway-ca \ + --from-file=ca.crt=/dev/stdin \ + -n openchoreo-workflow-plane \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +### Install the Workflow Plane + + + {`helm upgrade --install openchoreo-workflow-plane ${versions.helmSource}/openchoreo-workflow-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-workflow-plane \\ + --create-namespace \\ + --set clusterAgent.tls.generateCerts=true`} + + +#### Install Workflow Templates + +Build pipelines are defined as ClusterWorkflowTemplates. Each build workflow (docker, react, etc.) is composed from smaller shared templates, so you can swap out individual pieces without touching the rest. + +Start with the **checkout step**. This controls how source code is cloned. If your repos live behind a corporate proxy or need a custom auth flow, this is the template you would edit. + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/checkout-source.yaml`} + + +Next, install the **build coordinator templates** (docker, react, ballerina-buildpack, google-cloud-buildpacks): + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates.yaml`} + + +Finally, install the **publish step**. This controls where built images get pushed. The default below uses [ttl.sh](https://ttl.sh), an anonymous ephemeral registry where images expire automatically. + +:::note[TTL.sh] +Images on ttl.sh expire after 24 hours. For production, use your cloud provider's registry (ECR, GAR, ACR). See [Container Registry Configuration](../../platform-engineer-guide/container-registry-configuration.mdx). +::: + + + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/publish-image.yaml`} + + +Install the **generate-workload step**. This template creates Workload CRs from build outputs via the API server. The `sed` commands replace the default k3d URLs with your control plane's gateway addresses: + + + {`curl -fsSL https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/workflow-templates/generate-workload.yaml \\ + | sed "s#https://host.k3d.internal:8080/oauth2/token#https://thunder.\${CP_BASE_DOMAIN}/oauth2/token#g" \\ + | sed "s#http://host.k3d.internal:8080#https://api.\${CP_BASE_DOMAIN}#g" \\ + | kubectl apply -f -`} + + +### Register the Workflow Plane + +The workflow plane references the same `default` ClusterSecretStore created in Step 1. + +```bash +kubectl wait -n openchoreo-workflow-plane \ + --for=condition=Ready certificate/cluster-agent-workflowplane-tls --timeout=120s + +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-workflow-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +kubectl apply -f - < + {`kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/from-source/services/go-docker-greeter/greeting-service.yaml`} + + +Watch the build progress: + +```bash +kubectl get workflow -n workflows-default --watch +``` + +After the build completes, wait for the deployment: + +```bash +kubectl wait --for=condition=available deployment \ + -l openchoreo.dev/component=greeting-service -A --timeout=300s +``` + +Resolve the hostname and call the service: + +```bash +HOSTNAME=$(kubectl get httproute -A -l openchoreo.dev/component=greeting-service \ + -o jsonpath='{.items[0].spec.hostnames[0]}') +PATH_PREFIX=$(kubectl get httproute -A -l openchoreo.dev/component=greeting-service \ + -o jsonpath='{.items[0].spec.rules[0].matches[0].path.value}') +DP_HTTPS_PORT=$(kubectl get gateway gateway-default -n openchoreo-data-plane \ + -o jsonpath='{.spec.listeners[?(@.protocol=="HTTPS")].port}') +PORT_SUFFIX=$([ "$DP_HTTPS_PORT" = "443" ] && echo "" || echo ":${DP_HTTPS_PORT}") + +curl -k "https://${HOSTNAME}${PORT_SUFFIX}${PATH_PREFIX}/greeter/greet" +``` + +OpenChoreo built your code, pushed the image to ttl.sh, and deployed it to the data plane. + +:::note[k3s / Rancher Desktop] +On k3s with the Docker runtime, the `generate-workload-cr` build step may fail with `crun: the requested cgroup controller 'pids' is not available`. The image build and push still succeed. Switching Rancher Desktop to the containerd runtime avoids this issue. +::: + +
+Workaround: manually create the Workload CR + +Grab the image URL from the `publish-image` step and create the Workload CR yourself: + +```bash +IMAGE=$(kubectl get workflow greeting-service-build-01 -n workflows-default \ + -o jsonpath='{.status.nodes}' | grep -o '"image":"[^"]*"' | head -1 | cut -d'"' -f4) + +if [ -z "$IMAGE" ]; then + IMAGE=$(kubectl logs -n workflows-default \ + -l workflows.argoproj.io/workflow=greeting-service-build-01 \ + -c main --tail=50 2>/dev/null | grep -o 'ttl.sh[^ ]*' | tail -1) +fi + +echo "Built image: $IMAGE" + +kubectl apply -f - < + +## Step 7: Setup Observability Plane (Optional) + +OpenChoreo follows a modular architecture. The observability plane consists of system services plus various [observability modules](https://openchoreo.dev/modules/) that you can install to get observability features. +For example, if you require observability logs features, you can install a logs module. +This guide installs the observability plane with OpenSearch-based logs and tracing modules and a Prometheus-based metrics module by default. + +#### Namespace and Certificates + +```bash +kubectl create namespace openchoreo-observability-plane --dry-run=client -o yaml | kubectl apply -f - + +kubectl get secret cluster-gateway-ca -n openchoreo-control-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d | \ + kubectl create configmap cluster-gateway-ca \ + --from-file=ca.crt=/dev/stdin \ + -n openchoreo-observability-plane \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +#### Observability Plane Secrets + +The observability plane needs two secrets: + +- **`opensearch-admin-credentials`** — used by the OpenSearch cluster setup job (`username`, `password` keys). +- **`observer-secret`** — injected via `envFrom` into the Observer deployment. Required key: `UID_RESOLVER_OAUTH_CLIENT_SECRET`. + +```bash +kubectl apply -f - < + {`helm upgrade --install openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --create-namespace \\ + --timeout 25m \\ + --values - < + +:::note[Single IP LoadBalancer] +If your LoadBalancer provider assigns only one IP, add `--set gateway.httpPort=9080 --set gateway.httpsPort=9443` to avoid port conflicts with the control plane and data plane gateways. +::: + +#### Install the logs module (OpenSearch) + +```bash +helm upgrade --install observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" \ + --set adapter.openSearchSecretName="opensearch-admin-credentials" +``` + +#### Install the metrics module (Prometheus) + +```bash +helm upgrade --install observability-metrics-prometheus \ + oci://ghcr.io/openchoreo/helm-charts/observability-metrics-prometheus \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.1 +``` + +#### Install the traces module (OpenSearch) + +```bash +helm upgrade --install observability-traces-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-tracing-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.0 \ + --set openSearch.enabled=false \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" +``` + +#### Create the Observability Plane TLS Certificate + +Get the observer gateway IP and create a certificate: + +```bash +OBS_LB_IP=$(kubectl get svc gateway-default -n openchoreo-observability-plane -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +if [ -z "$OBS_LB_IP" ]; then + OBS_LB_HOSTNAME=$(kubectl get svc gateway-default -n openchoreo-observability-plane -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + OBS_LB_IP=$(dig +short "$OBS_LB_HOSTNAME" | head -1) +fi + +export OBS_BASE_DOMAIN="openchoreo.observability.${OBS_LB_IP//./-}.nip.io" +export OBS_DOMAIN="observer.${OBS_BASE_DOMAIN}" +echo "Observer domain: ${OBS_DOMAIN}" +``` + +```bash +kubectl apply -f - < + {`helm upgrade openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --reuse-values \\ + --timeout 10m \\ + --values - < + +### Register the Observability Plane + +```bash +kubectl wait -n openchoreo-observability-plane \ + --for=condition=Ready certificate/cluster-agent-observabilityplane-tls --timeout=120s + +AGENT_CA=$(kubectl get secret cluster-agent-tls \ + -n openchoreo-observability-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +OBS_HTTPS_PORT=$(kubectl get gateway gateway-default -n openchoreo-observability-plane \ + -o jsonpath='{.spec.listeners[?(@.protocol=="HTTPS")].port}') +OBS_PORT_SUFFIX=$([ "$OBS_HTTPS_PORT" = "443" ] && echo "" || echo ":${OBS_HTTPS_PORT}") + +kubectl apply -f - < + {`helm upgrade -n openchoreo-observability-plane observability-logs-opensearch \\ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \\ + --version 0.5.3 \\ + --reuse-values \\ + --set fluent-bit.enabled=true`} + + +#### Enable kubernetes events collection and exporting to logs module + +```bash +helm upgrade --install observability-events-otel-collector \ + oci://ghcr.io/openchoreo/helm-charts/observability-events-otel-collector \ + --namespace openchoreo-observability-plane \ + --version 0.1.1 \ + -f - <<'EOF' +collector: + extraEnv: + - name: OPENSEARCH_USERNAME + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: username + - name: OPENSEARCH_PASSWORD + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: password +extraExtensions: + basicauth/opensearch: + client_auth: + username: ${env:OPENSEARCH_USERNAME} + password: ${env:OPENSEARCH_PASSWORD} +exporters: + opensearch: + logs_index: "k8s-events" + logs_index_time_format: "yyyy-MM-dd" + http: + endpoint: "https://opensearch:9200" + tls: + insecure_skip_verify: true + auth: + authenticator: basicauth/opensearch +pipelineExporters: + - opensearch +EOF +``` + +Verify the observer is reachable: + +```bash +OBS_HTTPS_PORT=$(kubectl get gateway gateway-default -n openchoreo-observability-plane \ + -o jsonpath='{.spec.listeners[?(@.protocol=="HTTPS")].port}') +OBS_PORT_SUFFIX=$([ "$OBS_HTTPS_PORT" = "443" ] && echo "" || echo ":${OBS_HTTPS_PORT}") + +curl -sk "https://${OBS_DOMAIN}${OBS_PORT_SUFFIX}/health" +``` + +:::tip[Self-signed certificates] +The observer runs on a different domain than the console. Your browser needs to accept the self-signed certificate for the observer domain separately. Open the observer URL in your browser and accept the certificate warning, otherwise the console's observability features (logs, metrics, traces) will fail with a certificate error. + +```bash +echo "https://${OBS_DOMAIN}${OBS_PORT_SUFFIX}/health" +``` + +::: + +## Production Configuration + +This guide gets all planes running on a real cluster with self-signed TLS. For production hardening, see: + +- [Deployment Topology](../../platform-engineer-guide/deployment-topology.mdx) +- [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) +- [Secret Management](../../platform-engineer-guide/secret-management.mdx) +- [Container Registry Configuration](../../platform-engineer-guide/container-registry-configuration.mdx) +- [Identity Configuration](../../platform-engineer-guide/identity-configuration.mdx) +- [Control Plane Helm Reference](../../reference/helm/control-plane.mdx) +- [Data Plane Helm Reference](../../reference/helm/data-plane.mdx) +- [Workflow Plane Helm Reference](../../reference/helm/workflow-plane.mdx) +- [Observability Plane Helm Reference](../../reference/helm/observability-plane.mdx) + +## Cleanup + +Delete plane registrations: + +```bash +kubectl delete clusterdataplane default 2>/dev/null +kubectl delete clusterworkflowplane default 2>/dev/null +kubectl delete clusterobservabilityplane default 2>/dev/null +``` + +Uninstall OpenChoreo planes and prerequisites: + +```bash +helm uninstall openchoreo-observability-plane -n openchoreo-observability-plane 2>/dev/null +helm uninstall openchoreo-workflow-plane -n openchoreo-workflow-plane 2>/dev/null +helm uninstall openchoreo-data-plane -n openchoreo-data-plane 2>/dev/null +helm uninstall openchoreo-control-plane -n openchoreo-control-plane 2>/dev/null +helm uninstall thunder -n thunder 2>/dev/null +helm uninstall openbao -n openbao 2>/dev/null +helm uninstall kgateway -n openchoreo-control-plane 2>/dev/null +helm uninstall kgateway-crds 2>/dev/null +helm uninstall external-secrets -n external-secrets 2>/dev/null +helm uninstall cert-manager -n cert-manager 2>/dev/null +``` + +Delete namespaces: + +```bash +kubectl delete namespace \ + openchoreo-control-plane \ + thunder \ + openbao \ + openchoreo-data-plane \ + openchoreo-workflow-plane \ + openchoreo-observability-plane \ + external-secrets \ + cert-manager 2>/dev/null +``` + + + + + +Install the `openchoreo-setup` skill. + +```bash +npx skills add openchoreo/skills --skill openchoreo-setup -g +``` + +Then pick your environment and planes, and copy the prompt into your agent. + + + + + + + +## Next Steps + +- Follow [Deploy and Explore](../deploy-and-explore.mdx) to understand the resources OpenChoreo creates +- Explore the sample applications +- Move to multi-cluster isolation using [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) diff --git a/versioned_docs/version-v1.2.0-rc.2/overview/architecture.mdx b/versioned_docs/version-v1.2.0-rc.2/overview/architecture.mdx new file mode 100644 index 00000000..6ebf814d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/overview/architecture.mdx @@ -0,0 +1,419 @@ +--- +title: Architecture +description: Explore how OpenChoreo is architected across control, data, workflow, and observability planes, and how these components work together to deliver a comprehensive Internal Developer Platform. +--- + +import DeveloperAPIOverviewDiagram from "../resources/developer-api-overview.svg"; +import ArchitectureComponentsDiagram from "../resources/openchoreo-architecture-components.svg"; +import ExpandableImage from "@site/src/components/common/ExpandableImage"; +import PlatformTopologyOverviewDiagram from "../resources/platform-topology-overview.svg"; +import ReleaseTransformationDiagram from "../resources/release-transformation-diagram.svg"; +import CellRuntimeWithScreenshot from "../resources/cell-runtime-with-portal-screenshot.png"; + +# OpenChoreo Architecture + +## Overview + +OpenChoreo is architected as a modular, multi-plane Kubernetes-native system that integrates deeply +with other open-source projects to provide a complete, extensible **Internal Developer Platform (IDP)**. +It uses a domain-and-abstraction-driven, API-first approach as its core design philosophy, +which sets it apart from platforms that are primarily built from disparate tools stitched together with scripts. + +OpenChoreo is designed to provide platform builders a strong foundation to stand up their IDP +with minimal effort, while also offering the flexibility to customize and extend every aspect of +the platform as needed. It achieves this through a clear separation of concerns across multiple +planes, each responsible for specific aspects of the platform's functionality. It also uses a +modular framework that allows external tools to be integrated as first-class experiences in the +platform, rather than just being bolted on. + +The **[Control Plane](#control-plane)** acts as the central orchestrator, transforming and +reconciling the desired state of the platform and developer resources with the other planes, +as declared in its **[Developer API](#developer-api)** and **[Platform API](#platform-api)**. + +The **[Experience Plane](#experience-plane)** provides a uniform, access-controlled interface for both platform and +development teams via the **CLI** (called _occ_) and a Backstage-based **Internal Developer Portal (UI)**. +Both the control plane and the observability plane expose their own **_OpenAPI-v3-based_ API** and **MCP server**, +which together power these experience surfaces. + +The declarative nature of OpenChoreo’s APIs allows it to be operated imperatively via the UI, CLI, and MCPs, +or declaratively with Git as the source of truth for both platform and application state, if desired (native GitOps). + +In summary, + +- **[Data Plane(s)](#data-plane)** provide isolated, observable runtime environments and a gateway + topology for running developer API resources such as projects and components. Optional modules + can be installed to provide additional capabilities such as API management, scale-to-zero and + zero-trust networking. +- **[Workflow Plane(s)](#workflow-plane)** execute workflows such as CI workflows for building and + testing components, GitOps workflows for declaratively managing platform and application state. + It also runs other generic workflows as defined by platform teams, such as resource provisioning tasks. +- **[Observability Plane(s)](#observability-plane)** collect and aggregate distributed container + logs, metrics, and OpenTelemetry-based tracing data across workflow and data planes, providing rich, + domain-centric querying and alerting capabilities. + +_Figure 1_ (below) illustrates the components and interactions of the platform at a high level. + + + +Each plane in OpenChoreo operates as a distinct functional unit, with its own deployment and +upgrade lifecycle, scaling behavior, and security boundaries. The control plane and the data planes +together form the core of the platform, while the workflow and observability planes remain optional +but highly recommended for a complete IDP experience. + +--- + +## Control Plane + +The control plane is a Kubernetes cluster that acts as the _brain_ of OpenChoreo. +It runs a central control loop that continuously monitors the state of the platform and developer +resources. It takes actions to ensure that the desired state (as declared via the Developer and +Platform APIs) is reflected in the actual state across all planes. + +The control plane consists of the following key components: + +- **API Server**: Exposes the OpenChoreo API, which is used by both developers and platform teams + to interact with the system. It serves as the main entry point for all API requests, handling + authentication, authorization, and request validation. The API server is exposed via a Kubernetes + Gateway API, and powers both the OpenAPI-v3-based API and the MCP servers. The API server also hosts + OpenChoreo's **authorization engine**, that provides fine-grained RBAC (Role-Based Access Control), + ABAC (Attribute-Based Access Control) and hierarchical instance-level access control to all + resources created in OpenChoreo. +- **Controller Manager**: A set of Kubernetes controllers that implement the core reconciliation + logic of the platform. These controllers watch for changes to the CRD instances defined in the + Developer and Platform APIs, and take appropriate actions to ensure that the desired state is + achieved across all planes. For example, when a new Component is created, the controllers will + validate the request, resolve any references (e.g., dependencies of components), and trigger the + necessary workflows to build, deploy, and expose the component in the data plane(s) with the + required network policies and observability configurations. +- **Cluster Gateway**: All other planes (data, observability, workflow) establish outbound + connections to the control plane. This system component acts as the hub that allows the API + server and Controller Manager to communicate with other planes (a hub-and-spoke model). + It exposes a Secure WebSocket (_wss_) API that allows bidirectional communication between + other planes via long-lived + connections, authenticated with mTLS (using Cert-Manager). This prevents the Kubernetes API + servers of the data, workflow and observability planes from being exposed to the internet. + +### Experience Plane + +The experience plane is the user-facing layer of OpenChoreo, built for platform teams, development teams and agents +to interact with the IDP based on their respective roles and permissions. + +It includes the following components: + +- OpenAPI-v3-based APIs exposed by the control plane and observability plane +- The CLI (called _occ_) +- The Backstage-based Internal Developer Portal + > OpenChoreo uses an extended fork of Backstage for its UI that supports native Backstage plugins + > and custom plugins built specifically for OpenChoreo's APIs and concepts. +- MCP servers for AI-assisted/driven development and operations (exposed by the control plane and observability plane) + +#### Authentication and Authorization + +OpenChoreo integrates with any OAuth2/OIDC-compatible Identity Provider (IdP) for authentication (_who you are_). +By default, OpenChoreo ships with [ThunderID](https://thunderid.dev/), an open-source identity server to +help you get started. + +[Learn more about configuring your Identity Provider →](../platform-engineer-guide/identity-configuration.mdx) + +OpenChoreo comes built-in with a flexible, declarative **authorization engine** (_that defines what you can do_) +for all interactions based on fine-grained RBAC (Role-Based Access Control), +ABAC (Attribute-Based Access Control) and specific instance-level (namespace, project, +component-level) access controls that can allow or deny actions on resources. It works by mapping +_groups_ provided from your Identity Provider when a user logs in (via the UI, CLI, API and MCP +servers) to extensible _roles_ and _authorization policies_ defined in OpenChoreo. +This authorization engine is powered by [Apache Casbin](https://casbin.apache.org/). + +[Learn more about configuring authorization policies →](../platform-engineer-guide/authorization.md) + +#### AI as a First-Class Platform Construct + +OpenChoreo was designed from the ground up to support AI-assisted/driven development and operations, +and this is reflected in its architecture. Whether your team currently uses AI or not, OpenChoreo +provides a future-proof foundation for integrating AI tools and agents that can interact with the +platform following the same golden paths, guardrails and authorization policies as human users. +It also ships with a set of optional platform agents that can assist with site reliability +engineering, cost control and architecture governance use cases. These agents also serve as references +for how you can build your own. + +[Learn more about working with AI in OpenChoreo →](../ai/overview.mdx) + +### Platform API + +The Platform API is a set of Kubernetes CRDs that allow platform builders to define the structure +and behavior of the platform itself. It provides abstractions for defining organizational boundaries +(Namespaces), Environments, Data Planes, Workflow Planes, Observability Planes, and Deployment +Pipelines that can be used as building blocks to define the overall topology of the platform. +By using the Platform API, platform teams can declaratively configure how the platform should be +structured and how it should operate, without having to write custom code or scripts. + +The Platform API also includes programmable abstractions such as ComponentTypes, Traits and +Workflows that allow platform teams to define reusable templates and golden paths for their +development teams. These abstractions enable platform teams to encapsulate best practices, enforce +organizational standards, and provide a consistent developer experience across the platform. +These concepts together enable OpenChoreo's approach to policy, security and governance by design. + +_Figure 2_ (below) illustrates some of the core concepts of the Platform API and how they relate to each +other. It serves only as a high-level representation of one possible platform topology, but does +not enforce strict limitations on what your platform topology should look like. + + + +[Learn more about the Platform API abstractions and concepts →](../concepts/platform-abstractions.md) + +### Developer API + +The Developer API is a set of Kubernetes CRDs designed to simplify, streamline and reduce the +cognitive burden of application development on Kubernetes for development teams. Instead of exposing +the entire configuration surface of the Kubernetes API, these abstractions provide a more intuitive +and domain-driven way to define projects, their components, and their interactions via endpoints +and dependencies. + +OpenChoreo avoids "black-box" abstractions that completely obscure Kubernetes. Instead, these +provide a way for platform teams to create opinionated, reusable templates that define organizational +best practices and standards as intent-driven interfaces for their development teams. +This **shift-down approach** in OpenChoreo is enabled by programmable Component Types, Traits +and Workflows (that are part of the platform API). + +> _shift-down_ reduces developer cognitive load by offloading complexity to the platform, +> whereas _shift-left_ often increases it. + +Creating **abstractions for developer intent** means enabling self-service for day-to-day tasks as +golden paths in your IDP, shifting away from forcing developers to figure out the "how" of +Kubernetes and ticket-driven operations. + +_e.g.,_ + +- _"creating a component"_, +- _"defining a grouping of components as a project"_, +- _"building, testing and deploying a component"_, +- _"exposing a port of a component with a network visibility level (external/internal/namespace/project)"_, +- _"defining a dependency on another component or an external system"_, +- _"debugging a component in an environment with logs, metrics and traces"_ are all examples of + developer intent that can be abstracted away from the underlying infrastructure operations. + +_Figure 3_ (below) illustrates the relationships between these abstractions. Note that Workflows and WorkflowRuns have +been omitted from the diagram for simplicity, but they are also important abstractions in the Developer API that +allow platform teams to define reusable CI/CD, resource provisioning and other workflows as golden paths for developers. + + + +_Figure 4_ (below) illustrates how a developer-created Component is transformed into +Kubernetes resources in the data plane at runtime, based on the definitions provided in the platform API. + +With OpenChoreo, platform teams retain complete control of what gets deployed on their infrastructure, while developers get a simplified, +intent-driven experience that abstracts away the underlying complexity. + + + +These abstractions also align with the domain-driven design principles, where projects represent +bounded contexts and components represent the individual services or workloads within a domain. + +[Learn more about the Developer API abstractions and concepts →](../concepts/developer-abstractions.md) + +--- + +## Data Plane + +A data plane is a Kubernetes cluster that is responsible for running component workloads, enforcing +network policies, and exposing component endpoints via a structured gateway topology and wiring up +dependencies as instructed by the control plane. By definition, a data plane may span multiple +federated clusters, but in common practice, a data plane will be 1:1 with a Kubernetes cluster. + +Each data plane is registered with the control plane and is authenticated via mutual TLS. +OpenChoreo uses a cluster agent (not an AI agent) that establishes a long-lived, outbound secure +websocket (wss) connection to the control plane's Cluster Gateway, and listens for instructions +or queries. + +An OpenChoreo deployment can have one or more data planes, and these can span clusters in different +geographies and infrastructure providers, depending on the needs of the organization. Environments +(and ClusterEnvironments) define logically isolated runtime environments on a data plane, and a +DeploymentPipeline (or a ClusterDeploymentPipeline) can be used to promote components across these +logically (or physically) separated environments (i.e., a component can be promoted from a +_dev environment on data plane 1_ → _staging on data plane 1_ → _production on data plane 2_ +while applying environment-specific configurations and secrets). + +The control plane creates logically isolated namespaces, projects and environments via Kubernetes +namespaces and network policies in the data planes. It transpiles (converts at the same abstraction +level) resources created by the Developer API using the definitions provided in ComponentTypes and +Traits into Kubernetes API resources (including any custom resources), and offloads that +reconciliation to the data plane cluster's Kubernetes API server. However, this is not a +_fire-and-forget_ model. The control plane continuously monitors the desired state of resources +deployed to the data plane and takes corrective actions as necessary. A data plane can function +even if disconnected from the control plane, but any changes to the desired state will not be +reflected until the connection is restored. + +#### Modules + +Optional modules can be installed in the data plane to provide additional platform capabilities. For example: + +- API management module: provides API management capabilities such as rate limiting, authentication, + and observability for component endpoints, using Traits that plug into the Components. +- Elastic (scale-to-zero) module: automatically scales down component workloads to zero when they + are not in use, and scales them back up when needed based on traffic. +- Guard module: uses the Cilium CNI and eBPF to enforce zero-trust network policies and tap into + kernel-level observability. + +#### Runtime Model + +The runtime model describes how OpenChoreo's abstractions transform into running systems. When +development teams declare projects and components, the platform orchestrates a sophisticated runtime +environment that provides isolation, security, and observability on the data planes. + +At runtime, resources of a project are isolated through **Cells** — secure, isolated, and observable boundaries for all components belonging to a given _namespace-project-environment_ combination. +A Cell becomes the runtime boundary for a group of components with policy enforcement, and observability, aligning +with ideas of **[Cell-Based Architecture](https://github.com/wso2/reference-architecture/blob/master/reference-architecture-cell-based.md)**: +a model where individual teams or domains operate independently within well-defined boundaries, +while still benefiting from shared infrastructure capabilities. + +[Learn more about the runtime model →](../concepts/runtime-model.md) + +#### Gateway Topology + +Another advantage of using the Cell as the runtime boundary is that it allows OpenChoreo to +implement a structured gateway topology for all northbound, southbound, eastbound and westbound +traffic entering or leaving the cell. It simplifies how developers expose their components via a +set of abstractions for direction (ingress, egress) and visibility levels (external, internal, +namespace, project), while giving platform teams control over how those visibilities are mapped to +Kubernetes Gateway instances, standardizing the gateway topology across the platform. + +[Learn more about configuring the gateway topology →](../platform-engineer-guide/api-gateway/topology.md) + + + +Figure 5 (above): A screenshot of a Cell diagram as shown in the OpenChoreo Portal, depicting the gateways and component interactions. + +--- + +## Workflow Plane + +A workflow plane is a Kubernetes cluster that is responsible for executing platform-defined +workflows. At a high level, OpenChoreo has two categories of workflows: **CI workflows** that +provide developer self-service for building, testing and deploying their components, and +**generic workflows**, that cover all other automation use cases in the platform, including +GitOps workflows, resource provisioning workflows, and any custom workflows defined by platform teams. + +Similar to data planes, workflow planes are registered with the control plane and establish an +outbound secure websocket (wss) connection to the Cluster Gateway. The control plane offloads +workflow execution to the workflow plane by sending workflow definitions and execution instructions +via this channel, and continuously monitors the state of workflow executions to take corrective +actions as necessary. + +#### Modules + +The default workflow module for the OpenChoreo Workflow Plane is powered by **Argo Workflows**, +a powerful Kubernetes-native workflow engine. However, OpenChoreo's workflow concepts are designed +to work with any CRD-based workflow/pipeline engine, so you can customize the Workflow Plane to +use an alternative Kubernetes-native (CRD-based) module like Tekton, for example. + +#### Using External CI Systems + +The Workflow Plane is an optional plane. If you already have an existing CI system, such as +GitHub Actions, GitLab CI, or Jenkins, you can continue to use it. When using an external CI +system, OpenChoreo does not control the execution of CI workflows. Instead, builds must be executed +outside the platform, and integrated so that when a new build artifact is created, the control +plane is notified with the relevant metadata (e.g., image and workload CR). + +OpenChoreo provides a set of curated Backstage plugins for its Internal Developer Portal for a few +select external CI systems to make this easier, but you can also choose to build your own UI +integrations using APIs. + +In practice, you could use both external CI and OpenChoreo's workflow plane. A common pattern is +using the Git provider's native system for pre-pull-request-merge checks, and the workflow plane +to create and deploy the final build when the PR is merged. Generic workflows can be used for +GitOps, and also for running post-deployment/pre-promotion workflows such as integration tests. + +--- + +## Observability Plane + +An observability plane is a Kubernetes cluster responsible for providing centralized logs, metrics, +traces, and alerts. It acts as a central data sink, collecting and aggregating observability data +from all other workflow and data planes, as defined by the platform API. By design, workflow and +data planes can use different observability planes if required, and the control plane and the +experience plane can query the correct observability plane for each resource based on the +relationships declared in the platform topology. + +Similar to data and workflow planes, the observability plane establishes an outbound secure +websocket (wss) connection to the control plane when registered, but unlike the other planes, it +also exposes an OpenAPI-v3-based API for querying logs, metrics and traces and its own MCP server. +The control plane uses the websocket channel for reconciling resources in the observability plane +(e.g., ObservabilityAlertRules), but the experience plane and external tools (including AI +assistants/agents) can query observability data directly via the Observer API and MCP Servers, +which are secured with the same authentication and authorization policies as the rest of the platform. + +This design prevents observability data from being proxied through the control plane to end-users, +which can be a concern in larger multi-regional, multi-tenant OpenChoreo deployments where regional +data privacy regulations may apply. + +Observability data collection from other planes is carried out by collection agents configured via +the observability modules. These agents run on each target plane, enrich logs with domain metadata +(such as plane, namespace, project, and component), and forward them to the observability modules +in the observability plane. The observability modules are responsible for receiving this data, and +providing the backends/adapters for OpenChoreo's Observer API that provide a rich, domain-centric +querying experience. + +#### Modules + +By default, the observability plane ships with three modules for logs, metrics, and tracing, but +you can choose to swap these out for your own preferred tools, or even use a single module that +provides all these capabilities. The default modules are: + +- Logs powered by OpenSearch (observability-logs-opensearch) +- Metrics powered by Prometheus (observability-metrics-prometheus) +- Tracing powered by an OpenTelemetry (OTEL) collector with an OpenSearch backend (observability-tracing-opensearch) +- Alerting capabilities built into the logs and metrics modules. + +These modules together support full-text search, structured/unstructured log storage, metrics +storage, tracing storage, configurable retention, and complex queries. + +#### Using External Observability Systems + +The observability plane is optional. If you have an existing observability system, you can choose +to integrate it with OpenChoreo instead of using the default observability plane and modules. This +is a common pattern for organizations that already have a significant investment in an observability +stack such as Datadog, Splunk, New Relic, Grafana Cloud, cloud provider specific solutions, etc. +OpenChoreo's observability plane uses an adapter pattern that can allow a minimal observability +plane to plug into an external system's API, providing the same domain-centric Observer API and +MCPs for querying across the unified experience plane. + +--- + +## Deployment Topologies + +OpenChoreo supports multiple deployment patterns to suit different organizational needs, from local +development to large-scale, multi-cluster production setups. + +- In development or testing setups, all planes can be deployed into a single Kubernetes cluster + using namespace isolation. +- In production environments, each plane is typically deployed in a separate cluster for + scalability, fault tolerance, and security. +- Hybrid topologies are also supported, allowing teams to co-locate certain planes + (e.g., Control + Workflow) for cost or operational efficiency. + +For detailed topology configurations, see the [Deployment Topology](../platform-engineer-guide/deployment-topology.mdx) guide. + +## What's Next + +1. **[Quick Start Guide](../getting-started/quick-start-guide.mdx)** - Experience OpenChoreo locally in a few minutes with just Docker +1. **Try It Out** - [Run Locally](../getting-started/try-it-out/on-k3d-locally.mdx) or [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) +1. **[Concepts](../concepts/developer-abstractions.md)** - Learn more about OpenChoreo's core concepts and abstractions +1. **[Platform Engineer Guide](../platform-engineer-guide/deployment-topology.mdx)** - Learn how to set up in production, configure developer workflows and govern your platform +1. **[Developer Guide](../developer-guide/projects-and-components/overview.md)** - For end-users of the platform: learn how to build, deploy and observe your applications with self-service +1. **[Working with AI](../ai/overview.mdx)** - Learn how to use your AI assistants (_Claude Code, Codex, etc._) with OpenChoreo and set up the built-in platform agents diff --git a/versioned_docs/version-v1.2.0-rc.2/overview/what-is-openchoreo.mdx b/versioned_docs/version-v1.2.0-rc.2/overview/what-is-openchoreo.mdx new file mode 100644 index 00000000..9c1c15d4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/overview/what-is-openchoreo.mdx @@ -0,0 +1,91 @@ +--- +title: What is OpenChoreo +slug: / +description: "Introduction to OpenChoreo: an open-source Internal Developer Platform (IDP) that helps platform teams deliver scalable, self-service developer experiences on Kubernetes." +--- + +import Link from "@docusaurus/Link"; +import ExpandableImage from "@site/src/components/common/ExpandableImage"; +import WhatAreOpenChoreoPlanesImg from "../resources/what-are-openchoreo-planes.svg"; +import WhatIsOpenChoreoImg from "../resources/what-is-openchoreo-overview.svg"; + +## Introduction + +OpenChoreo is a complete, modular, open-source developer platform for Kubernetes that brings together the abstractions platform and application teams actually need, development and architecture guardrails, a Backstage-powered developer portal, application CI/CD, GitOps, and observability, in a single, cohesive platform. + +OpenChoreo orchestrates Kubernetes and other CNCF and open-source projects to give platform teams a strong head start. You can use it as-is, or tailor it to fit your own internal developer platform vision. + + + +## How OpenChoreo works + +OpenChoreo is built on a multi-plane architecture that separates concerns of control, runtime data, workflows and observability. +It uses a unified API surface and a modular architecture to deliver a holistic platform experience that is greater than what any combination of tools could offer on its own. + + + +This multi-plane architecture provides flexible deployment topologies across multiple clusters and cloud providers. It also lets platform builders scale and evolve at their own pace without re-architecting the entire platform as requirements and tools change, which is inevitable when treating an internal developer platform as a product. + +OpenChoreo is designed to be highly extensible when it comes to your choice of platform tooling: you can choose what makes sense for your organization and leave out what doesn't. This is enabled by a module-based architecture that allows other projects and tools to be integrated with OpenChoreo's core APIs and concepts without impacting the unified end-user experience. You can choose to use OpenChoreo's default modules, or swap them out for your own preferred choices from the [modules catalog](/modules), or build your own modules. + +[Learn more about OpenChoreo's architecture →](./architecture.mdx) + +## Why OpenChoreo? + +Many organizations are investing in internal developer platforms to improve developer velocity, reduce cognitive load, enforce organization-wide standards, and lower overall operational complexity. However, designing, building and maintaining a production-grade platform is a difficult task. + +**Teams tasked with building these platforms often face challenges such as:** + +- Managing the complexity and cognitive load of the Kubernetes API and its auxiliary ecosystem to keep developer experience simple and intuitive +- Integrating, maintaining and standardizing CI/CD, observability, security, and policy tools +- Meeting compliance and governance requirements +- Operating reliably across multiple clusters and clouds +- Supporting AI-assisted/driven engineering and operations through the platform +- Managing access controls and multi-tenancy between teams, projects, tools and runtime resources + +**OpenChoreo addresses these challenges by providing an IDP that is usable from day one, including:** + +- A scalable, modular architecture for your internal developer platform +- Platform APIs and abstractions as building blocks +- Programmable developer abstractions and golden paths covering the SDLC +- Integrated, intelligent observability (logs, metrics, traces, and alerts) +- Built-in agents (for site reliability engineering, cost control, and architecture) +- AI-assisted/driven development and operations +- Declarative platform and application state with Kubernetes as the system of record (native GitOps) +- Multi-tenancy and access controls for enterprise teams +- A module catalog to integrate external tools, or build your own + +And unlike many platforms that attempt to hide Kubernetes behind proprietary layers or "black box" abstractions, OpenChoreo keeps Kubernetes visible and operable. This allows infrastructure and platform teams to maintain full control, while still providing their development/application teams with a simplified and intuitive experience through programmable, intent-driven abstractions and golden paths. + +As a guiding principle, OpenChoreo does not obscure Kubernetes; rather, it augments it into a complete developer platform. All platform APIs and programmable developer abstractions are Kubernetes-native and are reconciled by OpenChoreo's controllers in the control plane, delivering a cohesive, integrated platform experience without sacrificing transparency. + +OpenChoreo was originally developed by [WSO2](https://wso2.com), as the successor and next evolution of its SaaS _WSO2 Developer Platform_ (formerly known as _WSO2 Choreo_), bringing years of battle-hardened platform engineering experience and lessons learnt, to the CNCF open-source community. + +## Getting Started + +Ready to try OpenChoreo? Start here: + +1. **[Architecture](./architecture.mdx)** - Learn more about OpenChoreo's multi-plane architecture and how it all works under the hood +2. **[Quick Start Guide](../getting-started/quick-start-guide.mdx)** - Experience OpenChoreo locally in a few minutes with just Docker +3. **Try It Out** - [Run Locally](../getting-started/try-it-out/on-k3d-locally.mdx) or [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) +4. **[Concepts](../concepts/developer-abstractions.md)** - Learn more about OpenChoreo's core concepts and abstractions +5. **[Platform Engineer Guide](../platform-engineer-guide/deployment-topology.mdx)** - Learn how to set up in production, configure developer workflows and govern your platform +6. **[Developer Guide](../developer-guide/projects-and-components/overview.md)** - For end-users of the platform: learn how to build, deploy and observe your applications with self-service +7. **[Working with AI](../ai/overview.mdx)** - Learn how to use your AI assistants (_Claude Code, Codex, etc._) with OpenChoreo and set up the built-in platform agents + +## Roadmap + +See our [Roadmap](https://github.com/orgs/openchoreo/projects/5/views/2) for upcoming features and milestones. + +## Community + +We’d love for you to be part of OpenChoreo’s journey! Whether you’re fixing a bug, improving documentation, or suggesting new features, every contribution counts. + +- [Contributor Guide](https://github.com/openchoreo/openchoreo/blob/main/docs/contributors/contribute.md) – Learn how to get started +- [Report an Issue](https://github.com/openchoreo/openchoreo/issues) or [Start a Discussion](https://github.com/openchoreo/openchoreo/discussions) – Help us improve OpenChoreo +- [Join CNCF Slack (#openchoreo)](https://slack.cncf.io/) – Be part of the community + +We’re excited to have you on board! diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/air-gapped-installation.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/air-gapped-installation.mdx new file mode 100644 index 00000000..80fa7d29 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/air-gapped-installation.mdx @@ -0,0 +1,535 @@ +--- +title: Air-Gapped Installation +description: Install OpenChoreo into an air-gapped Kubernetes cluster, with every container image, Helm chart, and supporting file coming from your own infrastructure. +--- + +import CodeBlock from "@theme/CodeBlock"; +import ExpandableImage from "@site/src/components/common/ExpandableImage"; +import AirGapOverviewDiagram from "./images/air-gapped-installation-overview.svg"; +import { versions } from "../_constants.mdx"; + +# Air-Gapped Installation + +This guide walks you through installing OpenChoreo into a Kubernetes cluster +that has no internet access. + +## Overview + +This guide covers: + +- Installing the **control, data, workflow, and observability planes** with + every container image pulled from your mirror registry. +- Installing the **default observability modules** (logs, tracing, metrics, + and events) offline, and the general pattern for installing any module + offline. + +It does not cover: + +- **Running CI builds.** The workflow plane installs and + connects, but executing builds also needs mirrored base and builder images + and a push registry on the air-gapped side. +- **Running the AI features.** Their images mirror like any other, but they + call an LLM provider directly. Running them on the air-gapped side needs an + OpenAI-compatible model endpoint you host yourself. +- **Setting up your infrastructure.** Your Kubernetes cluster, mirror + registry, and internal DNS are prerequisites. + [Requirements](#requirements) lists what OpenChoreo needs from each. + +## Concepts + + + +### What to mirror + +A connected OpenChoreo installation fetches three kinds of artifacts from the +internet. An air-gapped installation must serve all three locally: + +1. **Container images**: OpenChoreo's own images, its dependencies' images, + and your application images. No chart override rewrites application + images, so put the mirror path in the Workload spec yourself. Your cluster + pulls all of these from the mirror registry every time a pod starts, so + they must live in a registry every node can reach. +2. **Helm charts**: the OpenChoreo plane charts, the dependency charts, and + any module charts, all published as OCI artifacts. Published module charts + vendor their third-party subcharts, so a chart's `.tgz` is self-contained. +3. **Plain files**: the Gateway API CRDs YAML, OpenChoreo's default + resources file, and any other files your install fetches over HTTP. You + carry these in and install from disk. + +### How to fill the mirror + +Start from the image list built in +[Mirror the artifacts](#mirror-the-artifacts). A connected host saves each +image to a tarball, the tarballs cross the gap on your approved transfer +medium, and a host on the air-gapped side pushes them to the registry. + +Tarballs are **single-platform**: the save step must select the architecture +of your cluster nodes. + +## Requirements + +- **A working Kubernetes cluster on the air-gapped side**: its own system + images (pause, CoreDNS, kube-proxy, and similar) are your distribution's + responsibility, so follow its air-gap procedure (for example + [k3s](https://docs.k3s.io/installation/airgap) or + [RKE2](https://docs.rke2.io/install/airgap)) before installing anything. +- **A private OCI registry**: reachable from every cluster node and from the + hosts where you run `helm`. If the registry is plain HTTP or uses a private + CA, configure your nodes' container runtime for it. For registries requiring + authentication, see [Authenticated mirrors](#authenticated-mirrors). +- **Tools**: `kubectl`, `helm`, and an image-copy tool (`crane`, `skopeo`, or + `oras`) on the air-gapped side; `helm` and the same image-copy tool on the + connected side. + +### DNS requirements + +OpenChoreo exposes each plane through its own gateway, and each hostname you +configure in your values files must resolve to the right gateway **from every +place that uses it**. + +| Hostname | Routes to | Must resolve from | +| -------------------------------- | --------------------------- | ---------------------------------------------------------- | +| Console UI hostname | Control plane gateway | Operator browsers | +| API hostname | Control plane gateway | Operator browsers and in-cluster | +| Identity provider (IdP) hostname | Control plane gateway | Operator browsers **and in-cluster** (OIDC token exchange) | +| Observer hostname | Observability plane gateway | **Operator browsers** (logs view) and in-cluster | +| Application domains | Data plane gateway | Wherever your API consumers are | + +Inside the cluster, use your cluster DNS to resolve the same hostnames to the +corresponding gateway `Service`. + +## Mirror the artifacts + +### Build the image list + +Derive the list from the exact chart versions and values you will install, on +a connected machine. The list will automatically reflect the optional components you enable. Download the +OpenBao and Thunder values files first (see [Mirror the files](#mirror-the-files)). + + +{`REG_RE='[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}(:[0-9]+)?/[A-Za-z0-9._/-]+:[A-Za-z0-9._-]+' +set -euo pipefail + +{ +helm template openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ +--version ${versions.helmChart} -f your-cp-values.yaml +helm template openchoreo-data-plane ${versions.helmSource}/openchoreo-data-plane \\ +--version ${versions.helmChart} -f your-dp-values.yaml +helm template openchoreo-workflow-plane ${versions.helmSource}/openchoreo-workflow-plane \\ +--version ${versions.helmChart} -f your-wp-values.yaml +helm template openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ +--version ${versions.helmChart} -f your-op-values.yaml +helm template cert-manager oci://quay.io/jetstack/charts/cert-manager \\ +--version v1.19.4 --set crds.enabled=true +helm template external-secrets oci://ghcr.io/external-secrets/charts/external-secrets \\ +--version 2.0.1 --set installCRDs=true +helm template kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \\ +--version v2.3.1 +helm template openbao oci://ghcr.io/openbao/charts/openbao \\ +--version 0.25.6 -f values-openbao.yaml +helm template thunder oci://ghcr.io/asgardeo/helm-charts/thunder \\ +--version 0.28.0 -f values-thunder.yaml +} | grep -oE "\$REG_RE" | sort -u > images.txt + +# Images spawned at RUNTIME never appear in helm template output. Add them: + +echo "cr.kgateway.dev/kgateway-dev/envoy-wrapper:v2.3.1" >> images.txt`} + + + +Ways the list can come out incomplete: + +- **Extract full references, not `image:` fields.** Some images appear only + in container arguments (cert-manager's ACME solver, Prometheus operator's + config-reloader) — a naive grep misses them. +- **`envoy-wrapper` is mandatory.** The kgateway controller spawns it at + runtime for every Gateway. +- **Template with your real values.** Optional components add images. The + observability plane renders `ghcr.io/openchoreo/finops-agent` only when + `finOpsAgent.enabled` is set, and it is off by default. +- **Watch for bare Docker Hub references.** Some charts reference images + without a registry host (for example `busybox` or + `opensearchproject/opensearch`). The pattern above only matches + host-qualified references, so also check the rendered output for bare + `image:` values and add them as `docker.io/...` entries. +- **Repeat for each module chart you install.** See + [Install modules](#install-modules). + +### Mirror the images + +The registry override values in this guide assume a **strip-the-host** +layout: `quay.io/jetstack/cert-manager-controller` becomes +`REGISTRY/jetstack/cert-manager-controller`. A **path-preserving** layout +(`REGISTRY/quay.io/jetstack/...`, what registry proxy projects produce) also +works — the override values accept a path, for example +`global.imageRegistry=REGISTRY/ghcr.io` — but you must adjust every override +in this guide accordingly. + +Save each image to a tarball on the connected side, move the tarballs across +the gap, then push them to your registry: + +```bash +# Connected side: one tarball per image +mkdir -p images +while IFS= read -r img; do + case "$img" in ''|'#'*) continue ;; esac + crane pull --platform linux/amd64 "$img" "images/$(echo "$img" | tr '/:' '__').tar" +done < images.txt + +# ... move images.txt and images/ across the gap, then on the air-gapped side: +REGISTRY=registry.example.com +while IFS= read -r img; do + case "$img" in ''|'#'*) continue ;; esac + crane push "images/$(echo "$img" | tr '/:' '__').tar" "$REGISTRY/${img#*/}" +done < images.txt +``` + +:::warning Tarballs are single-platform +When using `crane pull`, set the `--platform` to match your **cluster nodes'** architecture. + +Incorrect platform selection produces a tarball that loads successfully but fails to run in the cluster. +::: + +:::note Docker Hub official images +For official Docker Hub images, write the list entry so that the push rule's +result (`REGISTRY/` + everything after the first `/`) matches the reference +the chart renders. If a chart renders the unqualified name (`busybox`), it +pulls `REGISTRY/busybox` from a mirror — so add the image to the list as +`docker.io/busybox:`, which the push rule lands at the registry root. +`crane` resolves `docker.io/` to the official `library/` image when +pulling. Only list an image under `docker.io/library/...` if the chart +renders it that way. +::: + +### Mirror the charts + +Pull every chart as a `.tgz` on the connected side, then either carry the +files across and install from disk, or push them to your registry with +`helm push` and install from `oci://REGISTRY/...`. + + +{`# OpenChoreo plane charts +helm pull ${versions.helmSource}/openchoreo-control-plane --version ${versions.helmChart} +helm pull ${versions.helmSource}/openchoreo-data-plane --version ${versions.helmChart} +helm pull ${versions.helmSource}/openchoreo-workflow-plane --version ${versions.helmChart} +helm pull ${versions.helmSource}/openchoreo-observability-plane --version ${versions.helmChart} + +# Dependencies + +helm pull oci://quay.io/jetstack/charts/cert-manager --version v1.19.4 +helm pull oci://ghcr.io/external-secrets/charts/external-secrets --version 2.0.1 +helm pull oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds --version v2.3.1 +helm pull oci://cr.kgateway.dev/kgateway-dev/charts/kgateway --version v2.3.1 +helm pull oci://ghcr.io/openbao/charts/openbao --version 0.25.6 +helm pull oci://ghcr.io/asgardeo/helm-charts/thunder --version 0.28.0 + +# Default observability modules (optional; see Install modules) + +helm pull ${versions.helmSource}/observability-logs-opensearch --version 0.5.4 +helm pull ${versions.helmSource}/observability-tracing-opensearch --version 0.5.1 +helm pull ${versions.helmSource}/observability-metrics-prometheus --version 0.6.3 +helm pull ${versions.helmSource}/observability-events-otel-collector --version 0.1.2`} + + + +### Mirror the files + +A normal install fetches a small set of plain files over HTTP. Download them +on the connected side and carry them in with your values files: + + +{`# Gateway API CRDs +curl -fLO https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml + +# OpenChoreo default resources + +curl -fLO https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/getting-started/all.yaml + +# Values files referenced by the standard installation guide + +curl -fLO https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-openbao.yaml +curl -fLO https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/install/k3d/common/values-thunder.yaml`} + + + +## Install the prerequisites + +Each dependency is its own Helm release with its **own** registry override +key: OpenChoreo's `global.imageRegistry` does not reach them. The sequence +and namespaces below match the +[standard installation guide](../getting-started/try-it-out/on-your-environment.mdx); +only the registry overrides and the use of local files differ. Steps of the +standard guide not shown here (such as creating the `ClusterSecretStore`) +have no air-gap changes. + +```bash +REGISTRY=registry.example.com +``` + +### Gateway API CRDs + +From the file mirrored earlier: + +```bash +kubectl apply --server-side -f standard-install.yaml +``` + +### cert-manager + +Five full-path repository overrides. Its `image.registry` value alone is not +enough: the default repositories bake `quay.io` into their paths, which would +produce nested registry paths. + +```bash +helm upgrade --install cert-manager ./cert-manager-v1.19.4.tgz \ + --namespace cert-manager --create-namespace \ + --set crds.enabled=true \ + --set image.repository=$REGISTRY/jetstack/cert-manager-controller \ + --set webhook.image.repository=$REGISTRY/jetstack/cert-manager-webhook \ + --set cainjector.image.repository=$REGISTRY/jetstack/cert-manager-cainjector \ + --set acmesolver.image.repository=$REGISTRY/jetstack/cert-manager-acmesolver \ + --set startupapicheck.image.repository=$REGISTRY/jetstack/cert-manager-startupapicheck +``` + +### external-secrets + +One value covers all three of its deployments: + +```bash +helm upgrade --install external-secrets ./external-secrets-2.0.1.tgz \ + --namespace external-secrets --create-namespace \ + --set installCRDs=true \ + --set global.repository=$REGISTRY/external-secrets/external-secrets +``` + +### kgateway + +The CRDs chart contains no images. The main chart's `image.registry` builds +the controller image. The chart also passes it to the controller at runtime, +which is how the proxies it spawns get their `envoy-wrapper` image, so one +value covers both. The value must include the `/kgateway-dev` organization +segment, because the chart's default registry value is +`cr.kgateway.dev/kgateway-dev`: + +```bash +helm upgrade --install kgateway-crds ./kgateway-crds-v2.3.1.tgz \ + --namespace openchoreo-control-plane --create-namespace + +helm upgrade --install kgateway ./kgateway-v2.3.1.tgz \ + --namespace openchoreo-control-plane \ + --set image.registry=$REGISTRY/kgateway-dev +``` + +### OpenBao + +With the values file mirrored earlier: + +```bash +helm upgrade --install openbao ./openbao-0.25.6.tgz \ + --namespace openbao --create-namespace \ + --values values-openbao.yaml \ + --set server.image.registry=$REGISTRY +``` + +### Thunder + +The key is nested under `deployment.`; a top-level `image.registry` is +silently ignored: + +```bash +helm upgrade --install thunder ./thunder-0.28.0.tgz \ + --namespace thunder --create-namespace \ + --values values-thunder.yaml \ + --set deployment.image.registry=$REGISTRY/asgardeo +``` + +## Install the OpenChoreo planes + +All four plane charts accept the same two values: `global.imageRegistry` +rewrites the registry host of every OpenChoreo image in the chart, and +`global.imagePullSecrets` adds pull secrets to every pod (see +[Authenticated mirrors](#authenticated-mirrors)). Install each plane exactly +as in the +[standard installation guide](../getting-started/try-it-out/on-your-environment.mdx) — +same namespaces, same registration steps for `ClusterDataPlane`, +`ClusterWorkflowPlane`, and `ClusterObservabilityPlane` — adding the override +to each install and using your local files where the guide fetches over HTTP. + +### Control plane + + +{`helm upgrade --install openchoreo-control-plane ./openchoreo-control-plane-${versions.helmChart}.tgz \\ + --namespace openchoreo-control-plane --create-namespace \\ + --values your-cp-values.yaml \\ + --set global.imageRegistry=\$REGISTRY + +# Default resources: use the local copy of all.yaml mirrored earlier + +kubectl apply -f all.yaml`} + + + +### Data plane + + + {`helm upgrade --install openchoreo-data-plane ./openchoreo-data-plane-${versions.helmChart}.tgz \\ + --namespace openchoreo-data-plane --create-namespace \\ + --values your-dp-values.yaml \\ + --set global.imageRegistry=\$REGISTRY`} + + +### Workflow plane + +`global.imageRegistry` covers OpenChoreo's own images, but the bundled Argo +Workflows subchart reads no globals and needs its own registry keys. The chart +passes the executor image to the workflow controller as a command-line +argument, and the controller uses it for the workflow pods it spawns at +runtime, so the override covers those too: + + + {`helm upgrade --install openchoreo-workflow-plane ./openchoreo-workflow-plane-${versions.helmChart}.tgz \\ + --namespace openchoreo-workflow-plane --create-namespace \\ + --values your-wp-values.yaml \\ + --set global.imageRegistry=\$REGISTRY \\ + --set argo-workflows.controller.image.registry=\$REGISTRY \\ + --set argo-workflows.executor.image.registry=\$REGISTRY \\ + --set argo-workflows.server.image.registry=\$REGISTRY \\ + --set argo-workflows.crds.full=false`} + + +:::warning `argo-workflows.crds.full=false` is required +At its default (`true`), the subchart installs its CRDs with a pre-install +hook Job that downloads them from GitHub, so the install fails no matter how +completely you mirror. `false` renders the CRDs bundled in the chart instead; +Workflow objects lose their OpenAPI validation schemas and nothing else. To +keep the full schemas, serve the CRD YAMLs from an internal host, set +`argo-workflows.crds.upgradeJob.crdBaseURL`, and mirror the hook's own +image (`registry.k8s.io/kubectl`), overriding it with +`argo-workflows.crds.upgradeJob.image.repository`. +::: + +:::note +Installing the workflow plane gives you a connected, mirror-served plane. +**Executing builds** on the air-gapped side additionally needs mirrored base +and builder images and a push registry there. +::: + +### Observability plane + + + {`helm upgrade --install openchoreo-observability-plane ./openchoreo-observability-plane-${versions.helmChart}.tgz \\ + --namespace openchoreo-observability-plane --create-namespace \\ + --values your-op-values.yaml \\ + --set global.imageRegistry=\$REGISTRY`} + + +When you register the `ClusterObservabilityPlane`, the `observerURL` you set +must satisfy the [DNS requirements](#dns-requirements): operator browsers +query it directly from the runtime logs view, and in-cluster consumers use it +too. + +## Install modules + +Modules are optional add-ons distributed as their own Helm charts. The +pattern for installing **any** module offline: + +1. **Mirror the module chart and its images.** Template the chart with your + values and extend your image list, exactly as in + [Mirror the artifacts](#mirror-the-artifacts). Published module charts + vendor their third-party subcharts, so the `.tgz` is self-contained. +2. **Override the module's own images.** Newer module charts (including the + default observability set below) accept the same `global.imageRegistry` as + the plane charts. Others expose per-image `image.repository` values; check + the chart's values file. +3. **Cover subchart images too.** Helm shares `global.*` values with + subcharts, so setting a global registry key on the module install covers + any subchart that reads one: kube-prometheus-stack and the OpenTelemetry + Collector honor `global.imageRegistry`, and the OpenSearch chart uses + `global.dockerRegistry`. Subcharts without global support (for example + fluent-bit) take per-image keys. +4. **Check the module's documentation for runtime images.** Operators and + controllers spawn these at runtime, so they never appear in + `helm template` output. + +### Default observability modules + +The versions below match [Mirror the charts](#mirror-the-charts). The `--set` +values unrelated to air-gapping (secrets, retention, and similar) come from +each module's own documentation. + +```bash +# Logs store (OpenSearch): both globals — imageRegistry for the module's own +# images, dockerRegistry for the OpenSearch subchart (incl. its init images) +helm upgrade --install observability-logs-opensearch ./observability-logs-opensearch-0.5.4.tgz \ + --namespace openchoreo-observability-plane \ + --set global.imageRegistry=$REGISTRY \ + --set global.dockerRegistry=$REGISTRY \ + --set adapter.openSearchSecretName=opensearch-admin-credentials \ + --set openSearchSetup.openSearchSecretName=opensearch-admin-credentials + +# Tracing: shares the logs module's OpenSearch store +helm upgrade --install observability-traces-opensearch ./observability-tracing-opensearch-0.5.1.tgz \ + --namespace openchoreo-observability-plane \ + --set global.imageRegistry=$REGISTRY \ + --set openSearch.enabled=false \ + --set adapter.openSearchSecretName=opensearch-admin-credentials \ + --set openSearchSetup.openSearchSecretName=opensearch-admin-credentials + +# Metrics: kube-prometheus-stack honors the same global.imageRegistry +helm upgrade --install observability-metrics-prometheus ./observability-metrics-prometheus-0.6.3.tgz \ + --namespace openchoreo-observability-plane \ + --set global.imageRegistry=$REGISTRY + +# Kubernetes events +helm upgrade --install observability-events-otel-collector ./observability-events-otel-collector-0.1.2.tgz \ + --namespace openchoreo-observability-plane \ + --set global.imageRegistry=$REGISTRY +``` + +To enable **log collection**, upgrade the logs release with the collector +turned on. The fluent-bit subchart has no global support, so its main image +takes a per-image key: + +```bash +helm upgrade observability-logs-opensearch ./observability-logs-opensearch-0.5.4.tgz \ + --namespace openchoreo-observability-plane \ + --reuse-values \ + --set fluent-bit.enabled=true \ + --set fluent-bit.image.repository=$REGISTRY/fluent/fluent-bit +``` + +:::tip +`--reuse-values` is safe here because the chart version is unchanged. When +upgrading a module across chart versions, pass your full values instead: +`--reuse-values` carries the old release's computed values over the new +chart's defaults. +::: + +## Authenticated mirrors + +If your mirror requires authentication, create a registry credential secret +in each namespace and reference it per chart. + +```bash +kubectl create secret docker-registry mirror-cred \ + --docker-server=$REGISTRY --docker-username=... --docker-password=... \ + --namespace +``` + +| Chart | Value | +| ----------------------------- | -------------------------------------------------------------------------- | +| OpenChoreo plane charts | `global.imagePullSecrets[0].name=mirror-cred` | +| Workflow plane, Argo subchart | `argo-workflows.images.pullSecrets[0].name=mirror-cred` | +| cert-manager | `global.imagePullSecrets[0].name=mirror-cred` | +| external-secrets | `global.imagePullSecrets[0].name=mirror-cred` | +| kgateway | `imagePullSecrets[0].name=mirror-cred` | +| OpenBao | `global.imagePullSecrets[0].name=mirror-cred` | +| Thunder | `deployment.image.imagePullSecret=mirror-cred` (a single name, not a list) | + +Module charts accept `global.imagePullSecrets` for their own pods, but some +of their subcharts do not inherit it: the logs module also needs +`openSearch.imagePullSecrets[0].name` and`fluent-bit.imagePullSecrets[0].name`, while kube-prometheus-stack does +propagate the global to its pods. Check each module chart's values file for the imagePullSecrets path. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/dataplane.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/dataplane.png new file mode 100644 index 00000000..7b556529 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/dataplane.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/environment.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/environment.png new file mode 100644 index 00000000..b45ac799 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/environment.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/modules.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/modules.md new file mode 100644 index 00000000..72c434f8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/modules.md @@ -0,0 +1,27 @@ +--- +title: Modular Architecture +description: Explore the available API Gateway modules in OpenChoreo and how to configure them for your data plane. +sidebar_position: 1 +--- + +# API Gateway Modules + +OpenChoreo supports any [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/) compliant gateway implementation as a pluggable module for its API Gateway layer. This page covers the available modules and how to configure them. + +## Default Module: kgateway + +The default gateway bundled with OpenChoreo is **[kgateway](https://kgateway.dev/)**, a high-performance, Kubernetes-native gateway built on Envoy Proxy. + +kgateway is enabled by default when installing the OpenChoreo data plane. It provides: + +- **High performance**: Built on Envoy Proxy with low-latency request handling +- **Kubernetes-native**: Fully managed via Kubernetes Gateway API resources +- **Extensible**: Supports traffic policies, header manipulation, and advanced routing rules + +No additional configuration is required to use kgateway - it is pre-configured as part of the standard data plane installation. + +## Using a Different Gateway Module + +OpenChoreo's modular architecture supports swapping in any Kubernetes Gateway API compliant gateway. This includes gateways like Traefik, Cilium Gateway, Kong, Istio, Nginx Gateway Fabric, and others. + +To explore the full list of supported and community tested gateway modules, visit the [OpenChoreo Modules page](/modules). diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/topology.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/topology.md new file mode 100644 index 00000000..db8d1a3d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-gateway/topology.md @@ -0,0 +1,230 @@ +--- +title: Gateway Topology +description: Understand how OpenChoreo provisions and manages API Gateway resources using the Kubernetes Gateway API. +sidebar_position: 2 +--- + +# API Gateway Topology + +OpenChoreo has a well-architected API Gateway topology designed to cater to a wide range of API Gateway use cases. The topology is built on top of three main principles: + +1. **Traffic Direction** — Whether traffic flows into the cluster (Ingress) or out of it (Egress) +2. **Networking Configuration** — Whether the gateway is exposed externally to the internet or internally within the cluster network / VPC +3. **Granularity** — Whether the gateway is shared at the DataPlane level or dedicated to a specific Environment + +These three dimensions can be combined to describe any gateway in an OpenChoreo deployment. + +## Default Gateway + +By default, OpenChoreo installs one gateway at the DataPlane level: + +| Gateway | Traffic Direction | Networking | Granularity | +| ------------------------ | ----------------- | ---------- | ----------- | +| Ingress External Gateway | Ingress | External | DataPlane | + +With this default configuration, APIs and routes deployed across all environments are hosted as unique virtual hosts on the shared DataPlane level gateway. This keeps infrastructure costs low and is well suited for basic use cases where environments do not have strict isolation requirements. + +## Internal Gateway + +By default, the DataPlane gateway is internet-facing (external). For traffic that should not be exposed to the public internet — such as service-to-service communication or traffic restricted to a private VPC subnet — you can add an **internal gateway**. + +An internal gateway can be configured in two ways depending on your environment: + +- **`ClusterIP`** — accessible only within the cluster, suitable for pure in-cluster service-to-service traffic +- **`LoadBalancer`** — accessible within the VPC/private network but not the public internet, suitable when services span multiple nodes or clusters within a private network (using cloud provider annotations such as `service.beta.kubernetes.io/aws-load-balancer-internal: "true"`) + +``` +External Gateway (LoadBalancer) Internal Gateway (ClusterIP or internal LB) +─────────────────────────────── ────────────────────────────────────────── + Accessible from the internet Not accessible from the public internet + ├── dev virtual host ├── dev virtual host + ├── staging virtual host ├── staging virtual host + └── production virtual host └── production virtual host +``` + +:::note +The configuration steps below are based on the default **kgateway** API gateway module. If you are using a different API gateway module, refer to that module's documentation instead. Available gateway modules are listed in the [modules](/modules) page. +::: + +### Configuring an Internal Gateway + +**Step 1: Create GatewayParameters** + +Create a `GatewayParameters` resource to configure the underlying service type. The example below uses `ClusterIP` for in-cluster-only access: + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: GatewayParameters +metadata: + name: internal-gateway-params + namespace: openchoreo-data-plane +spec: + kube: + service: + type: ClusterIP + extraLabels: + gateway: internal +``` + +To use a VPC-internal LoadBalancer instead, set `type: LoadBalancer` and add the appropriate cloud provider annotation. For example, on AWS: + +```yaml +spec: + kube: + service: + type: LoadBalancer + extraAnnotations: + service.beta.kubernetes.io/aws-load-balancer-internal: "true" + extraLabels: + gateway: internal +``` + +**Step 2: Create the Internal Gateway** + +Reference the `GatewayParameters` via the `infrastructure.parametersRef` field: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: gateway-internal + namespace: openchoreo-data-plane + labels: + app.kubernetes.io/component: gateway + app.kubernetes.io/part-of: openchoreo +spec: + gatewayClassName: kgateway + infrastructure: + labels: + openchoreo.dev/system-component: gateway + parametersRef: + name: internal-gateway-params + group: gateway.kgateway.dev + kind: GatewayParameters + listeners: + - name: http + port: 9080 + protocol: HTTP + allowedRoutes: + namespaces: + from: All +``` + +**Step 3: Register on the DataPlane** + +Register the internal gateway on the `DataPlane` resource so OpenChoreo routes internal traffic through it: + +```bash +kubectl patch dataplane default -n default --type merge -p '{ + "spec": { + "gateway": { + "ingress": { + "internal": { + "name": "gateway-internal", + "namespace": "openchoreo-data-plane", + "http": { + "host": "gateway-internal.openchoreo-data-plane", + "listenerName": "http", + "port": 9080 + } + } + } + } + } +}' +``` + +Alternatively, you can update this configuration from the Backstage portal. Navigate to **Catalog** > **Dataplane**, select the relevant Dataplane, go to the **Definition** tab, and update the YAML definition. + + + +For a `ClusterIP` gateway, set `host` to the in-cluster DNS name of the gateway service: `.`. + +For an internal `LoadBalancer` gateway, the host depends on your DNS setup. Your cloud provider will assign a private hostname or IP to the load balancer (for example, an internal ELB DNS name on AWS). You can use that hostname directly, or create a DNS record in your private hosted zone pointing to it. If you use [external-dns](https://github.com/kubernetes-sigs/external-dns), it can manage these records automatically when configured with the appropriate annotation filters for internal services. + +## Environment Gateway + +OpenChoreo supports environment-level gateways for advanced use cases where a dedicated gateway is required for a specific environment — such as a production environment that demands traffic isolation, independent scaling, or separate TLS termination. + +``` +DataPlane Level Gateway Environment Level Gateway +─────────────────────── ───────────────────────── + ├── development traffic └── production traffic + └── staging traffic +``` + +This allows you to start with the cost-efficient default topology and progressively introduce dedicated gateways for environments that require stricter isolation or higher availability guarantees. + +### Configuring an Environment Gateway + +**Step 1: Create the Gateway** + +Create a new `Gateway` resource in the `openchoreo-data-plane` namespace: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: gateway-production + namespace: openchoreo-data-plane + labels: + app.kubernetes.io/component: gateway + app.kubernetes.io/part-of: openchoreo +spec: + gatewayClassName: kgateway + infrastructure: + labels: + openchoreo.dev/system-component: gateway + listeners: + - name: http + port: 19081 + protocol: HTTP + allowedRoutes: + namespaces: + from: All +``` + +:::tip k3d users +If you are running k3d locally, add a port mapping to the load balancer node before creating the gateway: + +```bash +k3d node edit k3d-openchoreo-serverlb --port-add 19081:19081/tcp +``` + +::: + +**Step 2: Register on the Environment** + +Patch the target `Environment` CR to override the gateway for that environment: + +```bash +kubectl patch environment production -n default --type merge -p '{ + "spec": { + "gateway": { + "ingress": { + "external": { + "name": "gateway-production", + "namespace": "openchoreo-data-plane", + "http": { + "host": "openchoreoapis.localhost", + "listenerName": "http", + "port": 19081 + } + } + } + } + } +}' +``` + +Alternatively, you can update this configuration from the Backstage portal. Navigate to **Catalog** > **Environment**, select the relevant Environment, go to the **Definition** tab, and update the YAML definition. + + + +OpenChoreo will then route all APIs and routes belonging to that environment through the dedicated gateway instead of the shared Dataplane level gateway. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-management.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/api-management.mdx new file mode 100644 index 00000000..e69de29b diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization.md new file mode 100644 index 00000000..306f715c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization.md @@ -0,0 +1,688 @@ +--- +title: Authorization Configuration +description: Configure authorization settings, default roles, and subject types for OpenChoreo. +sidebar_position: 5 +--- + +# Authorization Configuration + +OpenChoreo includes a built-in authorization system that controls access to resources based on roles and bindings. This guide covers how to configure authorization settings, customize the default roles and mappings, and manage subject types through Helm values. + +For an overview of how authorization works, see the [Authorization Overview](./authorization/overview.md). + +## Enabling and Disabling Authorization + +Authorization is enabled by default. To disable it (e.g., for development or testing), set the following Helm value: + +```yaml +security: + authz: + enabled: false +``` + +When disabled, all requests are allowed without any policy evaluation. + +:::warning +Disabling authorization removes all access control. Only disable it in development or testing environments. +::: + +## Subject Types + +When creating a role binding, you need to specify **who** the binding applies to. This is done by selecting a subject type (e.g., "User" or "Service Account") and providing an identifier value. Each subject type maps to a specific JWT claim — for example, the "User" type maps to the `groups` claim, so entering `platform-team` as the identifier means the binding matches any JWT token where `groups` contains `platform-team`. + +Subject types control: + +- **What options appear** in the Access Control UI when creating role bindings (the "Select Subject" step in the wizard) +- **Which JWT claim** is used to match the identifier value against incoming tokens +- **How the identifier field is labeled** in the UI (e.g., "User Group" or "Client ID") + +This configuration bridges the gap between your identity provider's JWT token structure and OpenChoreo's authorization system. If your identity provider uses different claims or you need additional subject categories, you can customize this to match. + +### Configuration + +Subject types must be configured in both the control plane and the observability plane Helm charts: + +- **Control plane:** `openchoreoApi.config.security.subjects` in the `openchoreo-control-plane` chart +- **Observability plane:** `observer.security.subjectTypes` in the `openchoreo-observability-plane` chart + +Both configurations must be kept in sync. The control plane configuration is shown below: + +```yaml +openchoreoApi: + config: + security: + subjects: + user: + display_name: "User" + priority: 1 + mechanisms: + jwt: + entitlement: + claim: "groups" + display_name: "User Group" + service_account: + display_name: "Service Account" + priority: 2 + mechanisms: + jwt: + entitlement: + claim: "sub" + display_name: "Client ID" +``` + +In the example above: + +- A binding created with subject type **User** and identifier `platform-team` will match any request where the JWT `groups` claim contains `platform-team` +- A binding created with subject type **Service Account** and identifier `openchoreo-backstage-client` will match any request where the JWT `sub` claim equals `openchoreo-backstage-client` + +### Fields + +| Field | Type | Description | +| ----------------------------------------- | ------- | --------------------------------------------------------------------------------------------- | +| `display_name` | string | Human-readable name shown in the UI | +| `priority` | integer | Subject type matching precedence — lower values are evaluated first during JWT authentication | +| `mechanisms.jwt.entitlement.claim` | string | The JWT claim that this subject type maps to | +| `mechanisms.jwt.entitlement.display_name` | string | Label shown in the UI for the identifier input field | + +### Customizing Subject Configuration + +You can modify any part of the subject configuration — change display names, reorder priorities, update claim mappings, or add entirely new subject types to match your identity provider. For example, if your identity provider issues tokens with a `roles` claim (e.g., `"roles": ["admin", "developer"]`) instead of `groups`, you can update the "User" subject type to map to it: + +```yaml +openchoreoApi: + config: + security: + subjects: + user: + display_name: "User" + priority: 1 + mechanisms: + jwt: + entitlement: + claim: "roles" + display_name: "User Role" + service_account: + display_name: "Service Account" + priority: 2 + mechanisms: + jwt: + entitlement: + claim: "sub" + display_name: "Client ID" +``` + +In this example, the "User" subject type now maps to the `roles` claim instead of `groups`, and the identifier input field in the UI is labeled "User Role" instead of "User Group". When creating a role binding with subject type "User" and identifier `admin`, it will match any JWT token where the `roles` claim contains `admin`. + +## Authorization Cache + +Authorization decisions can be cached to improve performance. By default, caching is disabled. + +```yaml +openchoreoApi: + config: + security: + authorization: + cache: + enabled: false + ttl: "5m" +``` + +| Field | Type | Default | Description | +| --------- | ------- | ------- | ----------------------------------------- | +| `enabled` | boolean | `false` | Enable caching of authorization decisions | +| `ttl` | string | `"5m"` | How long to cache authorization decisions | + +## Policy Resync Interval + +The authorization system maintains an in-memory policy store for fast evaluation. This store is kept in sync with Kubernetes CRDs through real-time watches — whenever a role or binding is created, updated, or deleted, the change is immediately reflected in memory. However, in rare cases (e.g., network disruptions or missed watch events), the in-memory store can drift from the actual CRD state. The resync interval acts as a safety net by periodically performing a full reload of all policies from the CRDs: + +```yaml +openchoreoApi: + config: + security: + authorization: + resync_interval: "10m" +``` + +| Field | Type | Default | Description | +| ----------------- | ------ | ------- | ------------------------------------------------------------------------------------ | +| `resync_interval` | string | `"10m"` | Interval for periodic full resync of authorization policies. Set to `"0"` to disable | + +## Default Roles + +OpenChoreo ships with several default cluster roles that are created automatically during installation. These roles are designed to cover common organizational personas and can be used as-is or as a starting point for customization. + +:::warning +The `backstage-catalog-reader`, `rca-agent` (SRE Agent), `observer-resource-reader`, and `workload-publisher` roles and their bindings are required for internal integrations. Do not remove them unless you know what you are doing. +::: + +### admin + +Full access to all resources across all scopes. Intended for platform administrators. + +```yaml +- name: admin + actions: + - "*" +``` + +### developer + +Access for engineers who build, deploy, and iterate on components. Includes full CRUD on components, workloads, and observability read access, plus read-only access to all cluster- and namespace-scoped platform resources so developers can see the planes and pipelines their projects reference. + +```yaml +- name: developer + actions: + - "clusterdataplane:view" + - "clusterworkflowplane:view" + - "clusterobservabilityplane:view" + - "clustercomponenttype:view" + - "clustertrait:view" + - "clusterworkflow:view" + - "namespace:view" + - "environment:view" + - "deploymentpipeline:view" + - "dataplane:view" + - "workflowplane:view" + - "observabilityplane:view" + - "componenttype:view" + - "trait:view" + - "workflow:view" + - "project:view" + - "component:view" + - "component:create" + - "component:update" + - "component:delete" + - "componentrelease:view" + - "componentrelease:create" + - "releasebinding:view" + - "releasebinding:create" + - "releasebinding:update" + - "workflowrun:view" + - "workflowrun:create" + - "secretreference:view" + - "secretreference:create" + - "secretreference:update" + - "secretreference:delete" + - "workload:view" + - "workload:create" + - "workload:update" + - "workload:delete" + - "logs:view" + - "metrics:view" + - "traces:view" + - "alerts:view" + - "rcareport:view" +``` + +### sre + +Access for operations engineers focused on reliability and incident response. Includes read-only access to components and releases, release binding management, observability and incident management, and read-only access to all cluster- and namespace-scoped platform resources. + +```yaml +- name: sre + actions: + - "clusterdataplane:view" + - "clusterworkflowplane:view" + - "clusterobservabilityplane:view" + - "clustercomponenttype:view" + - "clustertrait:view" + - "clusterworkflow:view" + - "namespace:view" + - "environment:view" + - "deploymentpipeline:view" + - "dataplane:view" + - "workflowplane:view" + - "observabilityplane:view" + - "componenttype:view" + - "trait:view" + - "workflow:view" + - "project:view" + - "component:view" + - "componentrelease:view" + - "componentrelease:create" + - "releasebinding:view" + - "releasebinding:create" + - "releasebinding:update" + - "workflowrun:view" + - "workflowrun:create" + - "workload:view" + - "workload:create" + - "secretreference:view" + - "secretreference:update" + - "logs:view" + - "metrics:view" + - "traces:view" + - "alerts:view" + - "incidents:view" + - "incidents:update" + - "rcareport:view" + - "rcareport:update" +``` + +### platform-engineer + +Access for engineers managing OpenChoreo platform infrastructure. Includes full lifecycle management of environments, data planes, workflow planes, observability planes, deployment pipelines, and cluster-scoped resources. + +```yaml +- name: platform-engineer + actions: + - "namespace:view" + - "namespace:create" + - "namespace:update" + - "namespace:delete" + - "project:view" + - "project:create" + - "project:update" + - "project:delete" + - "component:view" + - "component:create" + - "component:update" + - "component:delete" + - "componentrelease:view" + - "componentrelease:create" + - "releasebinding:view" + - "releasebinding:create" + - "releasebinding:update" + - "releasebinding:delete" + - "environment:view" + - "environment:create" + - "environment:update" + - "environment:delete" + - "dataplane:view" + - "dataplane:create" + - "dataplane:update" + - "dataplane:delete" + - "workflowplane:view" + - "workflowplane:create" + - "workflowplane:update" + - "workflowplane:delete" + - "observabilityplane:view" + - "observabilityplane:create" + - "observabilityplane:update" + - "observabilityplane:delete" + - "componenttype:view" + - "componenttype:create" + - "componenttype:update" + - "componenttype:delete" + - "trait:view" + - "trait:create" + - "trait:update" + - "trait:delete" + - "workflow:view" + - "workflow:create" + - "workflow:update" + - "workflow:delete" + - "workflowrun:view" + - "workflowrun:create" + - "deploymentpipeline:view" + - "deploymentpipeline:create" + - "deploymentpipeline:update" + - "deploymentpipeline:delete" + - "secretreference:view" + - "secretreference:create" + - "secretreference:update" + - "secretreference:delete" + - "workload:view" + - "workload:create" + - "workload:update" + - "workload:delete" + - "logs:view" + - "metrics:view" + - "traces:view" + - "alerts:view" + - "incidents:view" + - "rcareport:view" + - "rcareport:update" + - "observabilityalertsnotificationchannel:view" + - "observabilityalertsnotificationchannel:create" + - "observabilityalertsnotificationchannel:update" + - "observabilityalertsnotificationchannel:delete" + - "clusterdataplane:view" + - "clusterdataplane:create" + - "clusterdataplane:update" + - "clusterdataplane:delete" + - "clusterworkflowplane:view" + - "clusterworkflowplane:create" + - "clusterworkflowplane:update" + - "clusterworkflowplane:delete" + - "clusterobservabilityplane:view" + - "clusterobservabilityplane:create" + - "clusterobservabilityplane:update" + - "clusterobservabilityplane:delete" + - "clustercomponenttype:view" + - "clustercomponenttype:create" + - "clustercomponenttype:update" + - "clustercomponenttype:delete" + - "clustertrait:view" + - "clustertrait:create" + - "clustertrait:update" + - "clustertrait:delete" + - "clusterworkflow:view" + - "clusterworkflow:create" + - "clusterworkflow:update" + - "clusterworkflow:delete" +``` + +### cluster-reader + +Read-only access to cluster-scoped platform resources (data planes, workflow planes, observability planes, component types, traits, and workflows at the cluster level). This is a supplementary role — see [Scoping Roles Below Cluster Level](#scoping-roles-below-cluster-level) for when to use it. + +```yaml +- name: cluster-reader + actions: + - "clusterdataplane:view" + - "clusterworkflowplane:view" + - "clusterobservabilityplane:view" + - "clustercomponenttype:view" + - "clustertrait:view" + - "clusterworkflow:view" +``` + +### namespace-reader + +Read-only access to namespace-scoped platform resources (namespaces, environments, deployment pipelines, planes, component types, traits, and workflows at the namespace level). This is a supplementary role — see [Scoping Roles Below Cluster Level](#scoping-roles-below-cluster-level) for when to use it. + +```yaml +- name: namespace-reader + actions: + - "namespace:view" + - "environment:view" + - "deploymentpipeline:view" + - "dataplane:view" + - "workflowplane:view" + - "observabilityplane:view" + - "componenttype:view" + - "trait:view" + - "workflow:view" + - "secretreference:view" +``` + +### backstage-catalog-reader + +Read-only access to catalog data. Used by the Backstage service account to read resources from the control plane. + +```yaml +- name: backstage-catalog-reader + actions: + - "component:view" + - "componenttype:view" + - "namespace:view" + - "project:view" + - "dataplane:view" + - "environment:view" + - "trait:view" + - "workload:view" + - "workflowplane:view" + - "clusterworkflowplane:view" + - "workflow:view" + - "deploymentpipeline:view" + - "observabilityplane:view" + - "clusterobservabilityplane:view" + - "clusterdataplane:view" + - "clustercomponenttype:view" + - "clustertrait:view" + - "clusterworkflow:view" +``` + +### rca-agent + +Observability and component read access. Used by the SRE Agent service account for root cause analysis, troubleshooting, and debugging. + +```yaml +- name: rca-agent + actions: + - "component:view" + - "project:view" + - "namespace:view" + - "componentrelease:view" + - "releasebinding:view" + - "workflowrun:view" + - "environment:view" + - "workload:view" + - "trait:view" + - "logs:view" + - "metrics:view" + - "alerts:view" + - "incidents:view" + - "incidents:update" + - "traces:view" +``` + +### workload-publisher + +Minimal access for publishing workloads from CI workflows. Used by the workload publisher service account. + +```yaml +- name: workload-publisher + actions: + - "workload:create" + - "workload:update" + - "workflowrun:view" + - "workflowrun:update" +``` + +### observer-resource-reader + +Read-only access to core resources needed for the observability plane. Used by the observer service account to read resource metadata from the control plane. + +```yaml +- name: observer-resource-reader + actions: + - "component:view" + - "project:view" + - "namespace:view" + - "environment:view" +``` + +## Default Role Bindings + +The following default role bindings are created to connect the default roles to their intended subjects. The `admins`, `developers`, `platform-engineers`, and `sres` groups are also pre-created in the default identity provider(ThunderID) with a sample user in each, giving you a quick way to experience the platform with different permission levels. + +| Binding Name | Role | Entitlement | Effect | +| ---------------------------------- | -------------------------- | ------------------------------------------------ | ------ | +| `admin-binding` | `admin` | `groups:admins` | allow | +| `developer-binding` | `developer` | `groups:developers` | allow | +| `platform-engineer-binding` | `platform-engineer` | `groups:platform-engineers` | allow | +| `sre-binding` | `sre` | `groups:sres` | allow | +| `backstage-catalog-reader-binding` | `backstage-catalog-reader` | `sub:openchoreo-backstage-client` | allow | +| `rca-agent-binding` | `rca-agent` | `sub:openchoreo-rca-agent` | allow | +| `workload-publisher-binding` | `workload-publisher` | `sub:openchoreo-workload-publisher-client` | allow | +| `observer-resource-reader-binding` | `observer-resource-reader` | `sub:openchoreo-observer-resource-reader-client` | allow | +| `mcp-tryout-client-binding` | `admin` | `sub:service_mcp_client` | allow | + +## Scoping Roles Below Cluster Level + +OpenChoreo's authorization hierarchy spans four levels: **Cluster → Namespace → Project → Component**. Permissions granted at a higher level cascade down, but permissions granted at a lower level do **not** grant access to resources at a higher level. + +This matters when you assign a role at the namespace or project level: the user will only have access to resources within that scope and will not be able to see cluster-scoped resources such as `ClusterDataPlane`, `ClusterWorkflowPlane`, `ClusterObservabilityPlane`, `ClusterTrait`, and similar resources. These resources live at the cluster level and are not visible through a namespace-scoped binding alone. + +For example, if a user needs `admin` access scoped to the `acme` namespace but also needs to see cluster-level resources, both can be expressed in a single `ClusterAuthzRoleBinding` using per-mapping `scope`: + +```yaml +# Namespace-scoped admin + cluster-wide reader visibility in one CR +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: acme-admins-binding +spec: + entitlement: + claim: groups + value: acme-admins + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: admin + scope: + namespace: acme + - roleRef: + kind: ClusterAuthzRole + name: cluster-reader + effect: allow +``` + +The `admin` mapping is scoped to the `acme` namespace, so it does not grant access to any other namespace. The `cluster-reader` mapping has no scope, so it grants read-only visibility into cluster-level resources (data planes, workflow planes, cluster traits, etc.) cluster-wide — exactly what is needed for the user to see the infrastructure their namespace depends on. + +Similarly, if a user has a project-scoped role, they will also not see namespace-scoped resources (environments, deployment pipelines, namespace-level planes, etc.). In this case, add both `cluster-reader` and `namespace-reader` to the same binding: + +```yaml +# Project-scoped role + namespace and cluster visibility in one CR +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: acme-devs-binding +spec: + entitlement: + claim: groups + value: acme-devs + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: developer + scope: + namespace: acme + project: crm + - roleRef: + kind: ClusterAuthzRole + name: namespace-reader + scope: + namespace: acme + - roleRef: + kind: ClusterAuthzRole + name: cluster-reader + effect: allow +``` + +The `cluster-reader` and `namespace-reader` roles exist precisely for this purpose — use them as supplementary role mappings whenever you assign roles below the cluster level and need cross-scope visibility. + +## Customizing Bootstrap Roles and Bindings + +You can add, modify, or remove the default roles and bindings by overriding the bootstrap configuration in your Helm values. + +### Adding a Custom Role + +Add entries to the `bootstrap.roles` array. Omit `namespace` to create a cluster-scoped role, or specify it to create a namespace-scoped role: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + roles: + # Include the defaults you want to keep + - name: admin + actions: + - "*" + + # Add your custom roles + - name: viewer + description: "Read-only access" + actions: + - "namespace:view" + - "project:view" + - "component:view" +``` + +### Adding a Custom Role Binding + +Add entries to the `bootstrap.mappings` array. Use `kind` to select the binding type and `roleMappings[].scope` to narrow the scope: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + # Include the defaults you want to keep + - name: admin-binding + kind: ClusterAuthzRoleBinding + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: admin + entitlement: + claim: groups + value: admins + effect: allow + + # Add your custom bindings + - name: dev-team-binding + kind: ClusterAuthzRoleBinding + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: developer + scope: + namespace: acme + entitlement: + claim: groups + value: dev-team + effect: allow + + # Namespace-scoped binding with project scope + - name: dev-team-crm-only + kind: AuthzRoleBinding + namespace: acme + roleMappings: + - roleRef: + kind: AuthzRole + name: developer + scope: + project: crm + entitlement: + claim: groups + value: crm-team + effect: allow +``` + +### Bootstrap Mapping Fields + +| Field | Type | Required | Description | +| -------------------------------- | ------ | -------- | ----------------------------------------------------------------------- | +| `name` | string | Yes | Binding name | +| `kind` | string | No | `ClusterAuthzRoleBinding` (default) or `AuthzRoleBinding` | +| `namespace` | string | No | Namespace for the binding. Required when `kind` is `AuthzRoleBinding` | +| `roleMappings[].roleRef.kind` | string | Yes | `ClusterAuthzRole` or `AuthzRole` | +| `roleMappings[].roleRef.name` | string | Yes | Name of the role to bind | +| `roleMappings[].scope.namespace` | string | No | Namespace scope (`ClusterAuthzRoleBinding` only). Omit for cluster-wide | +| `roleMappings[].scope.project` | string | No | Project scope (requires `namespace` for cluster bindings) | +| `roleMappings[].scope.component` | string | No | Component scope (requires `project`) | +| `entitlement.claim` | string | Yes | JWT claim name (e.g., `groups`, `sub`, `email`) | +| `entitlement.value` | string | Yes | JWT claim value to match | +| `effect` | string | Yes | `allow` or `deny` | + +:::important +When you override the `bootstrap.roles` or `bootstrap.mappings` arrays, the entire array is replaced. Make sure to include any default roles or bindings you want to keep. +::: + +## Verification + +After configuring authorization, verify the setup: + +1. **Check that authorization is enabled** in the API logs: + + ```bash + kubectl logs -n openchoreo-control-plane --tail=50 | grep -i authz + ``` + +2. **Verify default roles were created:** + + ```bash + kubectl get clusterauthzroles + ``` + +3. **Verify default bindings were created:** + + ```bash + kubectl get clusterauthzrolebindings + ``` + +4. **Test access** by logging into Backstage and navigating to **Access Control** to confirm roles and bindings appear correctly. + +## See Also + +- [Authorization Overview](./authorization/overview.md) — How authorization works in OpenChoreo +- [Custom Roles and Bindings](./authorization/custom-roles.mdx) — Creating roles and bindings via the UI +- [Identity Provider Configuration](./identity-configuration.mdx) — Configure authentication and identity providers diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/conditions.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/conditions.md new file mode 100644 index 00000000..c4bdeac1 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/conditions.md @@ -0,0 +1,141 @@ +--- +title: Conditions +description: Restrict role grants by request attributes using CEL expressions on AuthzRoleBindings +sidebar_position: 4 +keywords: + - ABAC + - attribute-based access control + - CEL + - common expression language + - policy + - constraints + - conditional access + - environment restriction + - request attributes +--- + +# Conditions + +A role binding answers _who_, _what_, and _where_. **Conditions** add a fourth constraint — _under what circumstances_. This is attribute-based access control (ABAC), layered on top of OpenChoreo's RBAC and expressed through CEL (Common Expression Language) policy. For example, you can grant a developer permission to manage release bindings in the `crm` project, but only when the target environment is `dev` or `staging` — keeping production off-limits. + +Conditions are optional. Omit them and the role mapping behaves like any other RBAC grant — every action the role grants applies within the binding's scope. + +## Condition Structure + +A condition has two parts: a list of **actions** it applies to, and an **expression** that decides whether those actions are permitted. You can attach conditions to a role mapping either in YAML (the `conditions` field on `AuthzRoleBinding` / `ClusterAuthzRoleBinding`) or through the Access Control UI in Backstage. + +| Field | Type | Required | Description | +| ------------ | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | string[] | Yes | Action patterns this condition applies to — the entry's `expression` is attached to each listed action. Supports exact matches and wildcards. | +| `expression` | string | Yes | A CEL expression that must evaluate to `true` for the action to be permitted by this role mapping. | + +Action patterns follow the same wildcard rules used elsewhere in OpenChoreo RBAC: + +- `releasebinding:create` — a single concrete action +- `releasebinding:*` — every action on the `releasebinding` resource +- `*` — every action in the system + +Only entries whose `actions` match the request contribute to the decision. If a mapping has conditions but none target the requested action, the condition check is skipped for that action. + +## Available Attributes + +CEL expressions reference a predefined set of attributes. Each attribute is registered against the specific actions where it is meaningful; a binding that references an attribute on an action that does not support it will be rejected at creation time. + +Currently the following attributes are available — more will be added in future releases: + +| Attribute | Type | Available on | Description | +| ------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `resource.componentType`
[(dual-scoped)](#resource-identifiers-dual-scoped) | string | `component:create`, `component:update`, `component:delete` | ComponentType (or ClusterComponentType) referenced by the component. | +| `resource.environment`
[(dual-scoped)](#resource-identifiers-dual-scoped) | string | `releasebinding:create`, `releasebinding:view`, `releasebinding:update`, `releasebinding:delete`, `resourcereleasebinding:create`, `resourcereleasebinding:view`, `resourcereleasebinding:update`, `resourcereleasebinding:delete`, `logs:view`, `wirelogs:view`, `metrics:view`, `traces:view` | Environment associated with the resource (e.g., `acme/prod`). | +| `resource.resourceType`
[(dual-scoped)](#resource-identifiers-dual-scoped) | string | `resource:create`, `resource:update`, `resource:delete` | ResourceType (or ClusterResourceType) referenced by the resource. | +| `resource.workflow`
[(dual-scoped)](#resource-identifiers-dual-scoped) | string | `workflowrun:create`, `workflowrun:update`, `workflowrun:delete` | Workflow (or ClusterWorkflow) referenced by the workflow run. | + +When a condition lists multiple actions — whether explicitly (`["releasebinding:create", "logs:view"]`) or via a wildcard pattern (`releasebinding:*`) — the expression may only reference attributes registered for **every** action the entry covers. An attribute supported by only some of those actions is not usable in the condition. + +### Resource Identifiers (Dual-Scoped) + +Some resource kinds in OpenChoreo come in two variants — one namespace-scoped, one cluster-scoped (for example, `ComponentType` and `ClusterComponentType`). In conditions, both variants share a single logical attribute — `environment`, `componentType`, `resourceType`, or `workflow`. Conditions don't pick the variant by kind; they pick it by the **shape of the identifier**. + +These dual-scoped attributes carry one of two forms: + +- For the namespace-scoped variant: `{namespace}/{name}` — for example, `acme/prod`. +- For the cluster-scoped variant: just `{name}` — for example, `prod`. + +Match the same form in your CEL expression: `resource.environment == "acme/prod"` targets a namespace-scoped environment named `prod` in `acme`, while `resource.environment == "prod"` targets the cluster-scoped one. The same rule applies to `resource.componentType`, `resource.resourceType`, and `resource.workflow`. + +Which form applies depends on the reference's `kind` in the resource being acted upon. Match the form the resource actually resolves to. When `kind` is omitted, it follows the CRD field's default. + +For resources that exist in only one scope, the resource identifiers simply carry the resource name. + +## How Conditions Affect the Authorization Decision + +For a role mapping to permit a request, four things must all be true: + +1. The subject matches the binding's entitlement. +2. The target resource is within the binding's scope. +3. The role lists the requested action (exactly or via a wildcard). +4. The condition (if any) evaluates to `true`. + +A mapping with no `conditions` skips step four. A mapping with conditions that don't target the request action also skips step four — steps one through three still apply. + +Aggregation across bindings is unchanged. A request is **allowed** only if at least one matching binding has `effect: allow` and no matching binding has `effect: deny`. See [How OpenChoreo RBAC determines access](./overview.md#how-openchoreo-rbac-determines-access) for the full algorithm. + +:::note +If a condition expression cannot be evaluated cleanly at runtime, OpenChoreo treats it as failing closed — see [Fail-Closed Evaluation](./overview.md#fail-closed-evaluation). +::: + +### Multiple Entries on the Same Mapping + +A single role mapping can carry multiple `conditions` entries. Among the entries whose `actions` match the request action, the expressions are combined with **OR** — at least one entry must evaluate to `true` for the role mapping to permit the action: + +```yaml +conditions: + - actions: ["releasebinding:view"] + expression: 'resource.environment == "dev"' + - actions: ["releasebinding:view"] + expression: 'resource.environment == "staging"' +``` + +This binding permits the `releasebinding:view` actions when the target environment is either `dev` or `staging`. Combining alternatives in one entry with CEL's `in` operator (`resource.environment in ["dev", "staging"]`) is equivalent and usually clearer. + +## Examples + +A platform engineer needs to give the `backend-team` group `developer` access — but with three safety rails: release-binding mutations must stay out of production, log access should be limited to `dev` and `staging`, and the team should only be able to create `service` and `cronjob` components. A single role mapping can carry all three rules, one condition per action group: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: backend-team-binding + namespace: acme +spec: + entitlement: + claim: groups + value: backend-team + roleMappings: + - roleRef: + kind: AuthzRole + name: developer + conditions: + - actions: + - releasebinding:create + - releasebinding:update + - releasebinding:delete + expression: 'resource.environment != "acme/prod"' + - actions: + - logs:view + expression: 'resource.environment in ["acme/dev", "acme/staging"]' + - actions: + - component:create + expression: 'resource.componentType in ["service", "cronjob"]' + effect: allow +``` + +Read-only actions on `releasebinding` (e.g., `releasebinding:view`) and every other action in the `developer` role remain unrestricted — only the listed actions are gated. A `component:create` for any type other than the namespace-scoped `service` or `cronjob` (`acme/service`, `acme/cronjob`) fails its condition and is denied. + +## Related Reading + +- [Authorization Overview](./overview.md) — Subjects, scopes, actions, and the full evaluation model +- [Custom Roles and Bindings](./custom-roles.mdx) — Walkthrough of role and binding management in Backstage +- [AuthzRoleBinding API Reference](../../reference/api/platform/authzrolebinding.md) — Field reference for namespace-scoped role bindings +- [ClusterAuthzRoleBinding API Reference](../../reference/api/platform/clusterauthzrolebinding.md) — Field reference for cluster-scoped role bindings diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/custom-roles.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/custom-roles.mdx new file mode 100644 index 00000000..b5ee1979 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/custom-roles.mdx @@ -0,0 +1,185 @@ +--- +title: Custom Roles and Bindings +description: Guide to creating custom authorization roles and role bindings in OpenChoreo +sidebar_position: 3 +--- + +# Custom Roles and Bindings + +This guide walks through creating custom roles and role bindings to control access in your OpenChoreo installation using the Access Control UI in Backstage. + +## Access Control UI + +Navigate to **Settings** in the Backstage left sidebar, then select the **Access Control** tab. The page has three sections in the left sidebar: + +- **Roles** — manage cluster and namespace-scoped roles +- **Role Bindings** — manage bindings that connect subjects to roles +- **Actions** — browse all available actions in the system + +The Roles section has a dropdown to switch between **Cluster Roles** and **Namespace Roles** for managing resources at the appropriate scope. + +Access Control page + +## Creating a Role + +1. Go to **Settings → Access Control → Roles** +2. Use the dropdown to select **Cluster Roles** or **Namespace Roles** depending on the scope you need + - For namespace roles, select the target namespace from the dropdown first +3. Click **New Cluster Role** or **New Namespace Role** +4. In the dialog: + - Optionally select a **quick start template** (Developer, Viewer, or Admin) to pre-fill actions + - Enter a **Role Name** + - Click **Select Actions** to open the action picker — actions are grouped by resource type, and you can select individual actions, all actions for a resource type (e.g., `component:*`), or all actions (`*`) +5. Click **Create** + +Role creation dialog with quick start templates + +## Creating a Role Binding + +Role bindings connect a subject to one or more roles, each with its own scope. The UI uses a step-by-step wizard on a dedicated page to guide you through the process — use the **Next** and **Back** buttons in the header to move between steps. + +1. Go to **Settings → Access Control → Role Bindings** +2. Use the dropdown to select **Cluster Role Bindings** or **Namespace Role Bindings** + - For namespace bindings, select the target namespace from the dropdown first +3. Click **New Cluster Role Binding** or **New Namespace Role Binding** to open the wizard page + +Role Bindings tab + +The wizard walks through the following steps: + +### Step 1: Select Subject + +Choose the subject type (e.g., User or Service Account) and provide an identifier value. Each subject type maps to a specific JWT claim — for example, the "User" type maps to the `groups` claim, so entering `platform-team` as the identifier means the binding matches any request where the `groups` claim contains `platform-team`. + +:::note +The subject types shown in the wizard are dynamic and reflect what is configured in your installation. You can customize the available types, display names, and claim mappings through the Helm values — see [Subject Types](../authorization.md#subject-types). +::: + +Role binding wizard — subject selection step + +### Step 2: Configure Role Mappings + +Add one or more role-scope pairs. Each role mapping combines a role (defining _what_ actions are permitted), a scope (defining _where_ those actions apply), and optional conditions (defining _under what circumstances_ they apply). + +For each mapping: + +1. **Select a role** from the dropdown. For namespace bindings, both namespace roles and cluster roles are available. For cluster bindings, only cluster roles are shown. +2. **Set the scope** to narrow where the role's permissions apply: + - For cluster bindings: optionally select a namespace, then a project, then a component + - For namespace bindings: optionally select a project, then a component + - Omitting scope means the role applies at the widest level (cluster-wide or namespace-wide) +3. **Add conditions** (optional) to gate specific actions on request attributes — see [Conditions (Optional)](#conditions-optional) below. +4. **Confirm** the mapping by clicking the checkmark + +You can add multiple mappings to a single binding. For example, you might grant `developer` access scoped to a specific project alongside `cluster-reader` access with no scope — all in one binding. + +:::tip +The scope you choose determines the effective permissions of the mapping — a user can only perform an action if the role grants that action **and** the target resource falls within the scope. For more details, see [Scope](./overview.md#scope) and [Effective Permissions](./overview.md#effective-permissions). +::: + +Select a role and configure its scope inline. The Conditions section below the role and scope fields lets you attach optional CEL-based restrictions (covered next). Click the checkmark to confirm the mapping. + +Role binding wizard — role mapping step + +Once confirmed, each mapping appears as a row in the table. You can add more mappings, or edit and delete existing ones. + +Role binding wizard — role mapping view + +#### Conditions (Optional) + +Each role mapping can carry one or more **conditions** that gate specific actions on attributes of the request — for example, allowing release-binding mutations only outside production. Conditions are configured inline while editing a role mapping, before you confirm it. + +1. With a role mapping open for editing, locate the **Conditions** section under the role and scope fields. +2. Click **Add condition** to create a new entry. The button is disabled until a role is selected and the role grants at least one action that supports conditions. +3. In the condition card: + - **Actions** — select one or more action patterns this condition applies to. Only actions granted by the role's action list are selectable. + - **Expression** — write a CEL expression that must evaluate to `true` for the listed actions to be permitted. + - **Available attributes** — chips below the Expression field list every attribute valid for your action selection. Click a chip to insert it at the cursor. + +Role binding wizard — condition card in edit mode + +4. Click the **checkmark** to confirm the condition, or **X** to discard it. + +Multiple conditions on the same mapping are combined with **OR** — at least one matching condition must evaluate to `true` for the action to be permitted. A mapping with no conditions, or whose conditions don't target the requested action, behaves as an unrestricted grant for that action. + +:::tip +Available attributes are filtered to those supported by **every** action you've selected. After the first action is picked, the picker hides actions with no overlap, and if the resulting selection has no shared attribute the **Expression** field is disabled until the conflict is removed. For the full attribute model and YAML reference, see [Conditions](./conditions.md). +::: + +### Step 3: Choose Effect and Name + +Select the effect: + +- **Allow** — grant the selected roles' permissions to the subject +- **Deny** — explicitly block these permissions for the subject + +A binding name is auto-suggested based on your selections. You can customize it if needed. The name cannot be changed after creation. + +Role binding wizard — effect and name step + +### Step 4: Review + +Review all your selections before creating the binding. The summary shows the subject, effect, and a table of all role mappings with their scopes. + +Role binding wizard — review step + +## Editing and Deleting + +### Editing + +Click the **edit** (pencil) icon on any role or binding row to open the edit dialog. The name field cannot be changed after creation. + +### Deleting a Role + +Click the **delete** (trash) icon on a role row. If the role has active bindings, you'll see a warning listing the affected bindings and can choose to **Force Delete**, which removes both the role and all its bindings. + +### Deleting a Role Binding + +Click the **delete** icon on a binding row and confirm. + +## Browsing Actions + +The **Actions** tab provides a read-only view of all available actions in the system, grouped by resource type. Use the search field to filter actions by name. This is useful when deciding which actions to include in a role. + +## See Also + +- [Authorization Overview](./overview.md) — Core concepts and how authorization works +- [Authorization CRD References](../../reference/api/platform/authzrole.md) — Detailed field reference for authorization CRDs diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/access-control-page.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/access-control-page.png new file mode 100644 index 00000000..72b0e766 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/access-control-page.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-allow-deny-selection.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-allow-deny-selection.png new file mode 100644 index 00000000..4b6d95e6 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-allow-deny-selection.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-conditions-editing.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-conditions-editing.png new file mode 100644 index 00000000..2c8021ca Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-conditions-editing.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-review-selection.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-review-selection.png new file mode 100644 index 00000000..d5a9a5b6 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-review-selection.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping-view.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping-view.png new file mode 100644 index 00000000..6515db9e Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping-view.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping.png new file mode 100644 index 00000000..8a898d7d Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-role-mapping.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-subject-selection.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-subject-selection.png new file mode 100644 index 00000000..6a9538f7 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-creation-subject-selection.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-tab.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-tab.png new file mode 100644 index 00000000..9d45c6b0 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-binding-tab.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-dialog-with-quick-start-templates.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-dialog-with-quick-start-templates.png new file mode 100644 index 00000000..b7d9799b Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/images/role-dialog-with-quick-start-templates.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/overview.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/overview.md new file mode 100644 index 00000000..ebe04e05 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/authorization/overview.md @@ -0,0 +1,195 @@ +--- +title: Overview +description: Understand how authorization works in OpenChoreo +sidebar_position: 1 +keywords: + - RBAC + - ABAC + - role-based access control + - attribute-based access control + - authorization model + - access control + - CEL + - policy +--- + +# Authorization in OpenChoreo + +OpenChoreo RBAC controls who can perform what actions on which OpenChoreo resources. It is managed declaratively through Kubernetes Custom Resource Definitions alongside your workloads. + +:::note +Authorization can be disabled for testing purposes. When disabled, a passthrough implementation allows all requests without any policy evaluation. +::: + +## What can I do with OpenChoreo RBAC? + +Here are some examples of what you can do with OpenChoreo RBAC: + +- Allow one team to manage components in a single project, while another team has read-only access across the whole namespace. +- Give a developer permission to create and update components in the `crm` project, but not delete them. +- Grant a platform engineer cluster-wide permission to manage data planes, component types, and workflows. +- Allow a service account to view logs and metrics for a specific component, and nothing else. +- Restrict an auditor to read-only access across every namespace in the cluster. + +## How OpenChoreo RBAC works + +You control access in OpenChoreo RBAC by defining **roles** and creating **role bindings**. A role is a named collection of allowed actions. A role binding attaches a role to a subject at a specific scope, answering the question "who can do what, and where?" + +- **Subject** — _who_ is being granted access. +- **Role** — _what_ actions are allowed. +- **Scope** — _where_ in the resource hierarchy the permissions apply. + +The rest of this page walks through each of these in detail, followed by how OpenChoreo evaluates a request against them. + +## Core Concepts + +### Subject + +A **subject** represents the identity making a request. Subjects are identified by **entitlements** — claim-value pairs extracted from the caller's JWT/OIDC token. For example: + +- `groups:platformEngineer` — user belongs to the "platformEngineer" group +- `sub:user-abc-123` — user's unique identifier +- `email:alice@acme.com` — user's email address + +A single user can have multiple entitlements (e.g., belonging to several groups), and each entitlement is evaluated independently during authorization. + +### Action + +An **action** represents an operation that can be performed on a resource. Actions follow the format `resource:verb`. For example: + +- `component:create` — create a new component +- `project:view` — view a project +- `componenttype:create` — create a new component type + +Actions also support wildcards: + +- `component:*` — all operations on components +- `*` — all operations on all resources + +### Resource Hierarchy + +Resources in OpenChoreo form a four-level ownership hierarchy: + +``` +Cluster (everything) + └── Namespace + └── Project + └── Component +``` + +Every resource belongs to a specific point in this hierarchy. For example, a component belongs to a project, which belongs to a namespace. Cluster-scoped resources (like `ClusterAuthzRole` or `ClusterDataPlane`) sit at the top level and are not owned by any namespace. + +### Scope + +**Scope** is the boundary that controls _where_ in the resource hierarchy a role's permissions apply. When a role binding includes a scope, only resources at or below that point in the hierarchy are affected. Resources outside the scope are invisible to that binding, as if it doesn't exist. + +Scope is set via the `scope` field on each role mapping in a binding: + +| Scope level | How to set | What it means | +| ---------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Cluster-wide** | Omit `scope` on a `ClusterAuthzRoleBinding` | Permissions apply to all resources at every level of the hierarchy | +| **Namespace** | `scope.namespace: acme` | Permissions apply to the `acme` namespace and all resources within it — its projects, their components, and any other namespace-scoped resources | +| **Project** | `scope.namespace: acme`, `scope.project: crm` | Permissions apply to the `crm` project and all resources within it | +| **Component** | `scope.namespace: acme`, `scope.project: crm`, `scope.component: backend` | Permissions apply only to the `backend` component and its resources | + +### Effective Permissions + +A role defines _what_ actions are permitted (e.g., `component:view`, `project:create`). Scope defines _where_ those actions take effect. The **effective permissions** of a binding are the intersection of both — a user can only perform an action if the role grants that action **and** the target resource falls within the scope. + +For example, a `developer` role that includes `component:create` and `project:view`: + +- Scoped to `namespace: acme, project: crm` — the user can create components and view the project, but only within the `crm` project. Other projects in `acme` are unaffected. +- Scoped to `namespace: acme` — the user can create components and view projects across all projects in `acme`. +- No scope (cluster-wide) — the user can create components and view projects across the entire cluster. + +Two key properties: + +- **Permissions cascade downward.** Granting `component:view` at the namespace scope allows viewing components in every project within that namespace. +- **Permissions do not cascade upward.** Even if a role includes actions for higher-level resources (e.g., `environment:view`), a binding scoped to a project will **not** grant access to namespace-level or cluster-level resources. If a user needs visibility into those, add supplementary role mappings at the appropriate scope — see [Scoping Roles Below Cluster Level](../authorization.md#scoping-roles-below-cluster-level). + +Each role binding also carries an `effect` field — either `allow` or `deny` (default: `allow`). A `deny` binding is an explicit exception: it revokes access that would otherwise be granted by an `allow` binding at the same or a higher scope. See [How OpenChoreo RBAC determines access](#how-openchoreo-rbac-determines-access) for exactly how allow and deny bindings are combined. + +### Conditions + +A role mapping can optionally carry **conditions** that further narrow when the mapping applies — for example, granting a developer permission to manage release bindings in the `crm` project, but only when the target environment is `dev` or `staging`, keeping production off-limits. + +If `conditions` is omitted, the role mapping behaves as a plain RBAC grant. For the full attribute model, evaluation semantics, and examples, see [Conditions on Role Bindings](./conditions.md). + +## How OpenChoreo RBAC determines access + +When a request arrives, OpenChoreo evaluates it against every role binding the subject matches. For each binding, all of the following must hold for the binding to apply: + +1. **The subject matches.** One of the caller's entitlement values (e.g., `groups:platformEngineer`) equals the binding's subject. +2. **The resource is within scope.** The target resource lies at or below the binding's scope in the resource hierarchy. A binding at `namespace: acme` applies to everything inside `acme`; a `ClusterAuthzRoleBinding` with no scope applies cluster-wide. +3. **The role grants the action.** The role referenced by the binding lists the requested action, either exactly (`component:create`) or via a wildcard (`component:*`, `*`). +4. **Conditions are satisfied.** If the matching role mapping defines `conditions`, at least one entry whose `actions` cover the request action must evaluate to `true`. Mappings without conditions, or mappings whose conditions do not target the request action, satisfy this step automatically. + +A request is **allowed** only if: + +- **at least one** matching binding has `effect: allow`, **and** +- **no** matching binding has `effect: deny`. + +A single matching `deny` is enough to block the request, even when multiple `allow` bindings would otherwise grant it. Deny applies across role kinds — a namespace-scoped `AuthzRoleBinding` with `effect: deny` can block access that a `ClusterAuthzRoleBinding` would otherwise allow. + +Bindings default to `effect: allow`. Set `effect: deny` explicitly only when you need to create a targeted exception to a broader allow — for example, granting `developer` access across the `acme` namespace but denying it on the `secret` project within it. + +### Fail-Closed Evaluation + +OpenChoreo evaluates authorization **fail-closed**: if any part of a binding cannot be evaluated cleanly — including malformed condition expressions or other corrupted policy state — `allow` bindings do not grant access and `deny` bindings still deny. A misconfiguration can never silently widen access; the conservative outcome wins. CRDs are validated by admission webhooks at create/update time, so most issues are caught before they ever reach evaluation. + +## Authorization CRDs + +OpenChoreo uses four CRDs to manage authorization. **Roles** define what actions are permitted, and **role bindings** connect subjects to those roles with a specific scope and effect. + +| CRD | Scope | Purpose | +| -------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------- | +| [**ClusterAuthzRole**](../../reference/api/platform/clusterauthzrole.md) | Cluster | Define a set of allowed actions, available across all namespaces | +| [**AuthzRole**](../../reference/api/platform/authzrole.md) | Namespace | Define actions scoped to a single namespace | +| [**ClusterAuthzRoleBinding**](../../reference/api/platform/clusterauthzrolebinding.md) | Cluster | Bind an entitlement to one or more cluster roles, optionally scoped to a namespace, project, or component | +| [**AuthzRoleBinding**](../../reference/api/platform/authzrolebinding.md) | Namespace | Bind an entitlement to one or more roles within a specific namespace | + +For detailed field descriptions and YAML examples, see the [Authorization API Reference](../../reference/api/platform/authzrole.md). + +## Available Actions + +The following actions are defined in the system: + +| Resource | Actions | +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Namespace | `namespace:view`, `namespace:create`, `namespace:update`, `namespace:delete` | +| Project | `project:view`, `project:create`, `project:update`, `project:delete` | +| Component | `component:view`, `component:create`, `component:update`, `component:delete`, `component:exec` | +| Resource | `resource:view`, `resource:create`, `resource:update`, `resource:delete` | +| Component Release | `componentrelease:view`, `componentrelease:create`, `componentrelease:delete` | +| Resource Release | `resourcerelease:view`, `resourcerelease:create`, `resourcerelease:delete` | +| Release Binding | `releasebinding:view`, `releasebinding:create`, `releasebinding:update`, `releasebinding:delete` | +| Resource Release Binding | `resourcereleasebinding:view`, `resourcereleasebinding:create`, `resourcereleasebinding:update`, `resourcereleasebinding:delete` | +| Component Type | `componenttype:view`, `componenttype:create`, `componenttype:update`, `componenttype:delete` | +| Cluster Component Type | `clustercomponenttype:view`, `clustercomponenttype:create`, `clustercomponenttype:update`, `clustercomponenttype:delete` | +| Resource Type | `resourcetype:view`, `resourcetype:create`, `resourcetype:update`, `resourcetype:delete` | +| Cluster Resource Type | `clusterresourcetype:view`, `clusterresourcetype:create`, `clusterresourcetype:update`, `clusterresourcetype:delete` | +| Workflow | `workflow:view`, `workflow:create`, `workflow:update`, `workflow:delete` | +| Workflow Run | `workflowrun:view`, `workflowrun:create`, `workflowrun:update`, `workflowrun:delete` | +| Cluster Workflow | `clusterworkflow:view`, `clusterworkflow:create`, `clusterworkflow:update`, `clusterworkflow:delete` | +| Trait | `trait:view`, `trait:create`, `trait:update`, `trait:delete` | +| Cluster Trait | `clustertrait:view`, `clustertrait:create`, `clustertrait:update`, `clustertrait:delete` | +| Environment | `environment:view`, `environment:create`, `environment:update`, `environment:delete` | +| Data Plane | `dataplane:view`, `dataplane:create`, `dataplane:update`, `dataplane:delete` | +| Cluster Data Plane | `clusterdataplane:view`, `clusterdataplane:create`, `clusterdataplane:update`, `clusterdataplane:delete` | +| Workflow Plane | `workflowplane:view`, `workflowplane:create`, `workflowplane:update`, `workflowplane:delete` | +| Cluster Workflow Plane | `clusterworkflowplane:view`, `clusterworkflowplane:create`, `clusterworkflowplane:update`, `clusterworkflowplane:delete` | +| Observability Plane | `observabilityplane:view`, `observabilityplane:create`, `observabilityplane:update`, `observabilityplane:delete` | +| Cluster Observability Plane | `clusterobservabilityplane:view`, `clusterobservabilityplane:create`, `clusterobservabilityplane:update`, `clusterobservabilityplane:delete` | +| Deployment Pipeline | `deploymentpipeline:view`, `deploymentpipeline:create`, `deploymentpipeline:update`, `deploymentpipeline:delete` | +| Observability Alert Notification Channel | `observabilityalertsnotificationchannel:view`, `observabilityalertsnotificationchannel:create`, `observabilityalertsnotificationchannel:update`, `observabilityalertsnotificationchannel:delete` | +| Secret Reference | `secretreference:view`, `secretreference:create`, `secretreference:update`, `secretreference:delete` | +| Secret | `secret:view`, `secret:create`, `secret:update`, `secret:delete` | +| Workload | `workload:view`, `workload:create`, `workload:update`, `workload:delete` | +| ClusterAuthzRole | `clusterauthzrole:view`, `clusterauthzrole:create`, `clusterauthzrole:update`, `clusterauthzrole:delete` | +| AuthzRole | `authzrole:view`, `authzrole:create`, `authzrole:update`, `authzrole:delete` | +| ClusterAuthzRoleBinding | `clusterauthzrolebinding:view`, `clusterauthzrolebinding:create`, `clusterauthzrolebinding:update`, `clusterauthzrolebinding:delete` | +| AuthzRoleBinding | `authzrolebinding:view`, `authzrolebinding:create`, `authzrolebinding:update`, `authzrolebinding:delete` | +| Observability | `logs:view`, `wirelogs:view`, `metrics:view`, `traces:view`, `alerts:view` | +| Incidents | `incidents:view`, `incidents:update` | +| RCA Report | `rcareport:view`, `rcareport:update` | +| FinOps Report | `finopsreport:view`, `finopsreport:update` | diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-configuration.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-configuration.mdx new file mode 100644 index 00000000..12061ced --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-configuration.mdx @@ -0,0 +1,799 @@ +--- +title: Backstage Configuration +description: Customize and configure Backstage, OpenChoreo's developer portal. +sidebar_position: 4 +--- + +import CodeBlock from "@theme/CodeBlock"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { versions } from "../_constants.mdx"; + +# Backstage Configuration + +OpenChoreo uses [Backstage](https://backstage.io/) as its developer portal, providing a unified interface for managing organizations, projects, components, and deployments. This guide covers configuration options for customizing Backstage in your OpenChoreo deployment. + +Backstage configuration is done via Helm values in the Control Plane chart. + +## Core Configuration + +**Console/UI URL:** + +```yaml +backstage: + baseUrl: "https://console.example.com" + http: + hostnames: + - console.example.com +``` + +`backstage.baseUrl` sets the URL used for OAuth redirects and internal link generation. `backstage.http.hostnames` configures the Gateway API `HTTPRoute` that routes traffic to Backstage. + +**OpenChoreo API URL:** + +```yaml +openchoreoApi: + http: + hostnames: + - api.example.com + config: + server: + publicUrl: "https://api.example.com" +``` + +## Authentication and Authorization + +By default, OpenChoreo configures ThunderID as the identity provider for Backstage with a pre-configured OAuth client for testing purposes. If you want to integrate an external identity provider instead, follow the steps below to configure both authentication and authorization for the new client. + +### Authentication + +Backstage uses **two separate OAuth 2.0 clients**: + +| Client | Grant type | Purpose | +| ------------------ | -------------------- | ------------------------------------------ | +| **Sign-in client** | `authorization_code` | User login via browser | +| **Service client** | `client_credentials` | Background tasks — catalog sync, API calls | + +You can register them as a single OAuth client that supports both grant types, or as two distinct clients. Using two distinct clients is recommended for production as it lets you apply least-privilege scopes to each and rotate them independently. + +**OAuth Client Requirements:** + +For the **sign-in client**: + +1. **Grant Types**: `authorization_code` +2. **Token Format**: JWT tokens (not opaque tokens) +3. **Redirect URLs**: Add the Backstage callback URL: + - `:///api/auth/openchoreo-auth/handler/frame` +4. **User Claims**: Configure the access token to include: + - `family_name`, `given_name`, `email`, `groups` + +For the **service client**: + +1. **Grant Types**: `client_credentials` +2. **Token Format**: JWT tokens + +**Helm Configuration:** + +Add both client secrets to the Backstage credentials Secret. If you are using a single shared client, set both `client-secret` and `service-client-secret` to the same value: + +```bash +kubectl create secret generic backstage-secrets \ + -n openchoreo-control-plane \ + --from-literal=backend-secret="your-32-character-secret-here" \ + --from-literal=client-secret="your-sign-in-client-secret" \ + --from-literal=service-client-secret="your-service-client-secret" \ + --from-literal=jenkins-api-key="not-used" \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +```yaml +backstage: + secretName: "backstage-secrets" + auth: + # Sign-in client (authorization_code flow) + clientId: "your-sign-in-client-id" + redirectUrls: + - ":///api/auth/openchoreo-auth/handler/frame" + oidcScope: "openid profile email" + # Service client (client_credentials flow — background tasks) + serviceClientId: "your-service-client-id" + serviceClientSecretKey: "service-client-secret" + scope: "" +``` + +:::note +If `serviceClientId` is not set, it falls back to `clientId`. If `serviceClientSecretKey` is not set, it falls back to `client-secret`. This means existing single-client deployments require no changes. +::: + +**Scope Configuration:** + +| Field | Description | Default | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `backstage.auth.oidcScope` | Space-separated scopes requested during user login via the `authorization_code` flow (sign-in client) | `"openid profile email"` | +| `backstage.auth.scope` | Space-separated scopes requested when the service client fetches tokens via `client_credentials`. Leave empty to use the IdP default, or set explicitly when required by your IdP (e.g. `"api://client-id/.default"` for Azure AD). | `""` | + +See [Identity Provider Configuration](./identity-configuration.mdx) for detailed setup instructions. + +### Authorization + +With authorization enabled by default, Backstage uses the `client_credentials` grant (via the service client) to authenticate with the OpenChoreo API as a service account. The API matches the `sub` claim in the issued JWT to identify the caller, so the service client must be granted the `backstage-catalog-reader` role via a bootstrap authorization mapping. + +Add the following to your values override file, replacing `your-service-client-id` with the value of `backstage.auth.serviceClientId` (or `backstage.auth.clientId` if you are using a single shared client): + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: backstage-catalog-reader-binding + kind: ClusterAuthzRoleBinding + system: true + roleMappings: + - roleRef: + name: backstage-catalog-reader + kind: ClusterAuthzRole + entitlement: + claim: sub + value: "your-service-client-id" + effect: allow +``` + +## Feature Flags + +```yaml +backstage: + features: + workflows: + enabled: true # Requires Workflow Plane + observability: + enabled: true # Requires Observability Plane + auth: + redirectFlow: + enabled: true # Silently redirect to IDP instead of showing sign-in popup + assistant: + enabled: false # "Ask Perch" chat drawer; requires perch-agent deployment + perchAgentUrl: "" # Defaults to in-cluster perch-agent Service + +# Top-level (not under backstage.features) — toggles both the API server and Backstage UI +features: + secretManagement: + enabled: false # Enable the Secret management API and Backstage UI +``` + +| Flag | Description | Default | +| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `backstage.features.workflows.enabled` | Show Workflows tab and overview card. Requires Workflow Plane. | `true` | +| `backstage.features.observability.enabled` | Show Metrics, Traces, Runtime Logs tabs and runtime health card. Requires Observability Plane. | `true` | +| `backstage.features.auth.redirectFlow.enabled` | Silently redirect to the IdP instead of showing the Backstage sign-in popup. | `true` | +| `backstage.features.assistant.enabled` | Enable the "Ask Perch" chat affordance. Requires the perch-agent service to be deployed. | `false` | +| `backstage.features.assistant.perchAgentUrl` | Upstream URL for the perch-agent. Leave empty to default to the in-cluster Service in the release namespace. | `""` | +| `features.secretManagement.enabled` | Enable the Secret management API on the API server and the corresponding UI in Backstage. **Top-level** — not under `backstage.features`. | `false` | + +## Catalog Sync + +OpenChoreo entities are synced to the Backstage catalog through two mechanisms: + +- **Event-driven sync**: A control-plane component watches OpenChoreo Kubernetes resources and posts change notifications to Backstage. Backstage applies a delta update to the catalog within seconds. +- **Periodic full sync**: A scheduled task in Backstage re-fetches all OpenChoreo state and applies a full update. This catches anything missed by the event path. + +Both are enabled by default. If the event-driven sync is disabled, the periodic full sync becomes the only sync mechanism. + +```yaml +backstage: + catalogSync: + frequency: 300 # Periodic full sync interval in seconds + +# Top-level — controls both the event-forwarder deployment and Backstage's +# event subscription. When false, Backstage runs in poll-only mode. +eventForwarder: + enabled: true +``` + +| Parameter | Description | Default | +| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `backstage.catalogSync.frequency` | Seconds between periodic full syncs. Lower the value when `eventForwarder.enabled` is `false`. | `300` | +| `eventForwarder.enabled` | Enables the event-forwarder component **and** the Backstage event subscription (via `OPENCHOREO_EVENTS_ENABLED`). Top-level, not under `backstage`. | `true` | + +The Backstage container's `OPENCHOREO_EVENTS_ENABLED` env var is wired directly from `eventForwarder.enabled` — there is no separate `backstage.events.enabled` chart value. See the [Helm chart reference](../reference/helm/control-plane.mdx) for full `eventForwarder.*` configuration. + +## Resource Configuration + +```yaml +backstage: + replicas: 1 + resources: + limits: + cpu: 2000m + memory: 2Gi + requests: + cpu: 200m + memory: 256Mi + + autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 3 +``` + +## Environment Variables + +The chart sets two groups of environment variables on the Backstage container: + +### Default Variables (`backstage.env`) + +These are the base variables defined in the chart. They can be overridden in a values file, but avoid using `--set backstage.env[0].name=...` on the command line — Helm's sparse array handling can corrupt the list. + +```yaml +backstage: + env: + - name: NODE_ENV + value: production + - name: LOG_LEVEL + value: info + - name: PORT + value: "7007" +``` + +### Extra Variables (`backstage.extraEnv`) + +To add custom environment variables without touching the defaults, use `backstage.extraEnv`. It is appended after `backstage.env` in the container spec, so if you use the same key, the last value wins. + +```yaml +backstage: + extraEnv: + - name: CUSTOM_VAR + value: "my-value" + - name: LOG_LEVEL # overrides the default "info" + value: debug +``` + +### All Environment Variables + +The chart sets the following environment variables on the Backstage container. Variables marked "from Secret" are read from the Secret referenced by `backstage.secretName`. + +| Variable | Description | Source | +| --------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| `NODE_ENV` | Node.js environment | `backstage.env` (default: `production`) | +| `LOG_LEVEL` | Logging verbosity | `backstage.env` (default: `info`) | +| `PORT` | HTTP server port | `backstage.env` (default: `7007`) | +| `BACKSTAGE_BASE_URL` | Public URL for OAuth redirects and links | `backstage.baseUrl` | +| `OPENCHOREO_API_URL` | Internal OpenChoreo API endpoint | `backstage.openchoreoApi.url` (auto-configured) | +| `BACKEND_SECRET` | Session encryption key | from Secret (`backend-secret`) | +| `OPENCHOREO_AUTH_CLIENT_ID` | Sign-in client ID (authorization_code flow) | `backstage.auth.clientId` | +| `OPENCHOREO_AUTH_CLIENT_SECRET` | Sign-in client secret | from Secret (`client-secret`) | +| `OPENCHOREO_SERVICE_CLIENT_ID` | Service client ID (client_credentials flow — background tasks) | `backstage.auth.serviceClientId` (falls back to `clientId`) | +| `OPENCHOREO_SERVICE_CLIENT_SECRET` | Service client secret | from Secret (key `backstage.auth.serviceClientSecretKey`, default: `client-secret`) | +| `OPENCHOREO_AUTH_METADATA_URL` | OIDC discovery URL (omitted when unset) | `security.oidc.wellKnownEndpoint` | +| `OPENCHOREO_AUTH_AUTHORIZATION_URL` | OAuth authorization endpoint | `security.oidc.authorizationUrl` | +| `OPENCHOREO_AUTH_TOKEN_URL` | OAuth token endpoint (shared by both clients) | `security.oidc.tokenUrl` | +| `OPENCHOREO_AUTH_OIDC_SCOPE` | OIDC scopes for the sign-in client | `backstage.auth.oidcScope` (default: `openid profile email`) | +| `OPENCHOREO_AUTH_SCOPE` | Scopes for the service client's client_credentials token request | `backstage.auth.scope` (default: `""`) | +| `OPENCHOREO_FEATURES_AUTH_ENABLED` | Enable authentication | `security.enabled` | +| `OPENCHOREO_FEATURES_AUTHZ_ENABLED` | Enable authorization | `security.authz.enabled` | +| `OPENCHOREO_FEATURES_AUTH_REDIRECT_FLOW_ENABLED` | Silent redirect vs sign-in popup | `backstage.features.auth.redirectFlow.enabled` | +| `OPENCHOREO_FEATURES_WORKFLOWS_ENABLED` | Show Workflows UI | `backstage.features.workflows.enabled` | +| `OPENCHOREO_FEATURES_OBSERVABILITY_ENABLED` | Show Metrics/Traces/Logs UI | `backstage.features.observability.enabled` | +| `OPENCHOREO_FEATURES_ASSISTANT_ENABLED` | Enable the "Ask Perch" chat affordance | `backstage.features.assistant.enabled` | +| `OPENCHOREO_PERCH_AGENT_URL` | Upstream URL for the perch-agent (in-cluster fallback applied) | `backstage.features.assistant.perchAgentUrl` | +| `OPENCHOREO_FEATURES_SECRET_MANAGEMENT_ENABLED` | Enable the Secret management UI | `features.secretManagement.enabled` (top-level) | +| `OPENCHOREO_EVENTS_ENABLED` | Enable event-driven catalog sync | `eventForwarder.enabled` (top-level) | +| `OPENCHOREO_CATALOG_SYNC_FREQUENCY` | Periodic full-sync interval (seconds) | `backstage.catalogSync.frequency` | +| `JENKINS_BASE_URL` | Jenkins server base URL (consumed when Jenkins integration is enabled) | `backstage.externalCI.jenkins.baseUrl` | +| `JENKINS_USERNAME` | Jenkins username for API authentication | `backstage.externalCI.jenkins.username` | +| `JENKINS_API_KEY` | Jenkins API key | from Secret (`jenkins-api-key`) | +| `GITHUB_HOST` | GitHub host for the Actions integration (`github.com` or a GHES host) | `backstage.externalCI.githubActions.host` | +| `GITHUB_API_BASE_URL` | GitHub API base URL (set for GHES, e.g. `https://ghe.example.com/api/v3`) | `backstage.externalCI.githubActions.apiBaseUrl` | +| `GITHUB_TOKEN` | GitHub backend token (catalog, scaffolder, TechDocs — _not_ the Actions card) | from Secret (`github-actions-token`, optional) | +| `AUTH_GITHUB_CLIENT_ID` | GitHub OAuth App client ID for per-user sign-in (powers the Actions card) | `backstage.externalCI.githubActions.oauth.clientId` | +| `AUTH_GITHUB_CLIENT_SECRET` | GitHub OAuth App client secret | from Secret (`github-oauth-client-secret`, optional) | +| `DATABASE_CLIENT` | Database driver (`better-sqlite3` or `pg`) | `backstage.database.type` | +| `SQLITE_STORAGE_DIR` | SQLite database directory (when using SQLite) | `backstage.database.sqlite.mountPath` | +| `POSTGRES_HOST` / `_PORT` / `_USER` / `_PASSWORD` / `_DB` | PostgreSQL connection fields (when `database.type=postgresql`) | from Secret (`postgres-host`, `postgres-port`, `postgres-user`, `postgres-password`, `postgres-db`) | +| `PGSSLMODE` | Set to `require` when PostgreSQL SSL is enabled | `backstage.database.postgresql.ssl` (conditional) | + +## HTTP Routing Configuration + +OpenChoreo uses the [Gateway API](https://gateway-api.sigs.k8s.io/) for traffic routing (not Kubernetes Ingress). The chart creates `HTTPRoute` resources that route traffic through a shared `Gateway` managed by kgateway. + +```yaml +backstage: + http: + enabled: true + hostnames: + - console.example.com +``` + +TLS is configured at the gateway level, not per-HTTPRoute. See the gateway configuration section in the Helm chart values. + +## Service Configuration + +```yaml +backstage: + service: + type: ClusterIP + port: 7007 +``` + +## OpenChoreo API Integration + +Backstage communicates with the OpenChoreo API for backend operations: + +```yaml +backstage: + openchoreoApi: + url: "" # Auto-configured to internal service URL +``` + +The API URL defaults to `http://openchoreo-api.{namespace}.svc.cluster.local:8080/api/v1`. + +## External CI Integration + +OpenChoreo Backstage ships with two external CI integrations — **Jenkins** and **GitHub Actions** — both wired through `backstage.externalCI.*`. For the end-to-end walkthroughs (OAuth setup, component annotations, what you see in the portal), see [External CI Integration](./workflows/external-ci.mdx). This section is the configuration reference. + +### Jenkins + +The chart wires Jenkins integration into Backstage via `backstage.externalCI.jenkins.*`. The `JENKINS_BASE_URL`, `JENKINS_USERNAME`, and `JENKINS_API_KEY` env vars are always set on the container; the `jenkins-api-key` Secret key is required even when Jenkins is not in use (use a placeholder value). + +```yaml +backstage: + externalCI: + jenkins: + enabled: false # Toggle Jenkins integration on/off + baseUrl: "https://jenkins.example.com" + username: "jenkins-user" +``` + +| Parameter | Description | Default | +| --------------------------------------- | --------------------------------------- | ------------------------------- | +| `backstage.externalCI.jenkins.enabled` | Toggle Jenkins integration | `false` | +| `backstage.externalCI.jenkins.baseUrl` | Jenkins server base URL | `"https://jenkins.example.com"` | +| `backstage.externalCI.jenkins.username` | Jenkins username for API authentication | `"jenkins-user"` | + +The Jenkins API token is read from the `jenkins-api-key` key in `backstage.secretName`. + +### GitHub Actions + +The chart wires GitHub Actions integration into Backstage via `backstage.externalCI.githubActions.*`. Once enabled, the Component page surfaces a **CI/CD** tab showing recent `workflow_run` data for any Component annotated with `github.com/project-slug`. + +```yaml +backstage: + externalCI: + githubActions: + enabled: false # Toggle GitHub Actions integration on/off + host: "github.com" # GHES: set to your instance host, e.g. ghe.example.com + apiBaseUrl: "" # GHES: set to e.g. https://ghe.example.com/api/v3 + oauth: + clientId: "" # GitHub OAuth App client ID (powers per-user sign-in) +``` + +| Parameter | Description | Default | +| --------------------------------------------------- | ------------------------------------------------------------------------------ | -------------- | +| `backstage.externalCI.githubActions.enabled` | Toggle GitHub Actions integration | `false` | +| `backstage.externalCI.githubActions.host` | GitHub host (`github.com` or a GHES host) | `"github.com"` | +| `backstage.externalCI.githubActions.apiBaseUrl` | GitHub API base URL (required for GHES, e.g. `https://ghe.example.com/api/v3`) | `""` | +| `backstage.externalCI.githubActions.oauth.clientId` | GitHub OAuth App client ID for the per-user sign-in the Actions card uses | `""` | + +:::info Two GitHub credentials are involved +The GitHub Actions card authenticates **each portal user** through a GitHub **OAuth App** (`oauth.clientId` plus the `github-oauth-client-secret` Secret key) — this is what lets a user see runs for repositories they can access. The optional `github-actions-token` Secret key is a separate **backend** token used by catalog ingestion, the scaffolder, and TechDocs — it is _not_ what the Actions card reads. See the [GitHub Actions walkthrough](./workflows/external-ci.mdx#step-5-enable-github-actions-visibility-in-backstage) for the full setup. +::: + +## Operator Extensions + +The chart exposes several extension points so platform engineers can inject custom Backstage configuration without building a custom container image. + +```yaml +backstage: + # Arbitrary Backstage app-config YAML rendered into a ConfigMap and + # appended as `--config app-config.extra.yaml`. Preferred for operator + # overlays (auth providers, integrations, custom theme, etc.). + appConfig: {} + + # Additional CLI args appended after the built-in --config flags. + extraArgs: [] + + # Extra volumes and mounts merged into the pod spec. + extraVolumes: [] + extraVolumeMounts: [] + + # Chart-managed TLS toggle. When false (the default), the chart + # automatically mounts an `app-config.csp.yaml` to prevent + # upgrade-insecure-requests. Set to true when terminating TLS at the + # Backstage Service itself (rare — TLS is normally terminated at the + # Gateway). + tls: + enabled: false +``` + +:::warning +`backstage.appConfig` is rendered into a plaintext `ConfigMap`. Do not put secrets here — reference them through `backstage.extraEnv` with `secretKeyRef` instead. +::: + +## Backstage Secret + +Backstage credentials are loaded from a Kubernetes Secret referenced by `backstage.secretName`. + +:::warning +`backstage.secretName` is **required** when `backstage.enabled=true`. The chart fails the install with a placeholder-hostname validation error if `secretName` is empty. +::: + +Required keys: + +- `backend-secret`: Backstage session encryption key +- `client-secret`: Sign-in client secret (authorization_code flow) +- `jenkins-api-key`: Jenkins integration API key (use a placeholder if not using Jenkins) + +Optional keys: + +- `service-client-secret`: Service client secret (client_credentials flow). Required only when using a dedicated service client (`backstage.auth.serviceClientSecretKey: "service-client-secret"`). When not present, the service client falls back to `client-secret`. +- `github-oauth-client-secret`: GitHub OAuth App client secret. Required only when the GitHub Actions card is enabled (`backstage.externalCI.githubActions.oauth.clientId` set) — see the [GitHub Actions walkthrough](./workflows/external-ci.mdx#step-5-enable-github-actions-visibility-in-backstage). +- `github-actions-token`: GitHub backend token for catalog ingestion, the scaffolder, and TechDocs. Declared `optional: true` on the Deployment, so the pod still starts without it. _Not_ the credential the GitHub Actions card uses to read runs. + +When `backstage.database.type=postgresql`, the same Secret must also include: + +- `postgres-host` +- `postgres-port` +- `postgres-user` +- `postgres-password` +- `postgres-db` + +:::note[External Secrets Operator] +If you are using External Secrets Operator (ESO) to manage `backstage-secrets` (as in the default k3d setup), do not use `kubectl create secret` directly — ESO will overwrite your changes on its next sync. Instead, add the PostgreSQL credentials to your secret store (e.g., OpenBao, AWS Secrets Manager) and update the `ExternalSecret` resource to include the additional keys. +::: + +```yaml +backstage: + secretName: "backstage-secrets" +``` + +## Database Configuration + +Backstage requires a database to store catalog entities, user settings, and plugin data. OpenChoreo supports two database backends: + +| Backend | Use Case | Persistence | Scalability | +| ---------------- | --------------------------- | -------------------------- | ------------------- | +| SQLite (default) | Development, single-replica | Optional (emptyDir or PVC) | Single replica only | +| PostgreSQL | Production, multi-replica | External database | Horizontal scaling | + +### Default Configuration (SQLite) + +By default, Backstage uses SQLite with an `emptyDir` volume, which means data is lost when the pod restarts: + +```yaml +backstage: + database: + type: sqlite + sqlite: + persistence: + enabled: false # Uses emptyDir (data lost on restart) +``` + +### SQLite with Persistence + +For development environments where you want data to persist across restarts but don't need horizontal scaling: + +```yaml +backstage: + database: + type: sqlite + sqlite: + mountPath: /app/.config/backstage + persistence: + enabled: true + size: 1Gi + storageClassName: "" # Uses default storage class + accessMode: ReadWriteOnce +``` + +:::warning +SQLite locks the database file, preventing multiple Backstage replicas from running simultaneously. For high-availability deployments, use PostgreSQL. +::: + +### PostgreSQL for Production + +For production deployments requiring high availability and data durability, configure an external PostgreSQL database. + +#### Prerequisites + +1. **Provision a PostgreSQL Database**: Use a managed service (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) or a self-hosted PostgreSQL instance +2. **Create a Database**: Create a database for Backstage (e.g., `backstage`) +3. **Create a Database User**: Create a user with full access to the database + +Backstage automatically creates per-plugin databases (e.g., `backstage_plugin_catalog`, `backstage_plugin_auth`) using the provided credentials. + +#### Helm Configuration + + + + +For managed PostgreSQL services or external databases: + + + {`kubectl create secret generic backstage-secrets \\ + -n openchoreo-control-plane \\ + --from-literal=backend-secret="your-32-character-secret-here" \\ + --from-literal=client-secret="your-client-secret" \\ + --from-literal=jenkins-api-key="not-used" \\ + --from-literal=postgres-host="postgres.example.com" \\ + --from-literal=postgres-port="5432" \\ + --from-literal=postgres-user="backstage" \\ + --from-literal=postgres-password="your-secure-password" \\ + --from-literal=postgres-db="backstage" \\ + --dry-run=client -o yaml | kubectl apply -f - && \\ +helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set backstage.secretName="backstage-secrets" \\ + --set backstage.database.type=postgresql \\ + --set backstage.database.postgresql.ssl=true`} + + +:::tip +Set `backstage.database.postgresql.ssl=true` when connecting to managed PostgreSQL services (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) that enforce SSL connections. +::: + + + + +For PostgreSQL running within the same Kubernetes cluster: + + + {`kubectl create secret generic backstage-secrets \\ + -n openchoreo-control-plane \\ + --from-literal=backend-secret="your-32-character-secret-here" \\ + --from-literal=client-secret="your-client-secret" \\ + --from-literal=jenkins-api-key="not-used" \\ + --from-literal=postgres-host="postgres.your-namespace.svc.cluster.local" \\ + --from-literal=postgres-port="5432" \\ + --from-literal=postgres-user="backstage" \\ + --from-literal=postgres-password="your-secure-password" \\ + --from-literal=postgres-db="backstage" \\ + --dry-run=client -o yaml | kubectl apply -f - && \\ +helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set backstage.secretName="backstage-secrets" \\ + --set backstage.database.type=postgresql \\ + --set backstage.database.postgresql.ssl=true`} + + + + + +Using a values file for better secret management: + +```yaml +# backstage-db-values.yaml +backstage: + secretName: "backstage-secrets" + database: + type: postgresql + postgresql: + ssl: true +``` + + + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + -f backstage-db-values.yaml`} + + + + + +#### PostgreSQL Configuration Reference + +| Parameter | Description | Default | +| ----------------------------------- | -------------------------------------------------------------- | -------- | +| `backstage.database.type` | Database backend (`sqlite` or `postgresql`) | `sqlite` | +| `backstage.database.postgresql.ssl` | Enable SSL for PostgreSQL connections (sets PGSSLMODE=require) | `false` | +| `backstage.secretName` | Secret containing Backstage and PostgreSQL credentials | `""` | + +PostgreSQL connection fields are read from Secret keys (`postgres-host`, `postgres-port`, `postgres-user`, `postgres-password`, `postgres-db`) referenced by `backstage.secretName`. + +#### Verifying PostgreSQL Connection + +After deploying with PostgreSQL, verify the connection: + +```bash +# Check Backstage pod is running +kubectl get pods -n openchoreo-control-plane -l app.kubernetes.io/component=backstage + +# Verify database environment variables are set to PostgreSQL +kubectl get deployment backstage -n openchoreo-control-plane \ + -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \ + | grep -E "DATABASE|POSTGRES" + +# Check logs for database connection errors +kubectl logs -n openchoreo-control-plane deployment/backstage | head -50 +``` + +If PostgreSQL is configured correctly, Backstage will create per-plugin databases automatically: + +```bash +# List databases created by Backstage (run against your PostgreSQL instance) +psql -U backstage -d backstage -c "\l" | grep backstage_plugin +``` + +Expected output shows databases like `backstage_plugin_catalog`, `backstage_plugin_auth`, etc. + +## Health Checks + +Backstage health checks are pre-configured: + +| Check | Endpoint | Default | +| --------- | -------------- | ------- | +| Liveness | `/healthcheck` | Enabled | +| Readiness | `/healthcheck` | Enabled | + +## Example Configurations + + + + +```yaml +backstage: + enabled: true + replicas: 1 + baseUrl: "http://openchoreo.localhost:8080" + http: + hostnames: + - openchoreo.localhost + resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + features: + workflows: + enabled: true + observability: + enabled: true +``` + + + + +```yaml +backstage: + enabled: true + replicas: 2 + baseUrl: "https://console.example.com" + secretName: "backstage-secrets" + http: + hostnames: + - console.example.com + + # PostgreSQL for production (required for multi-replica) + database: + type: postgresql + postgresql: + ssl: true + + resources: + limits: + cpu: 2000m + memory: 2Gi + requests: + cpu: 500m + memory: 512Mi + + autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 5 + targetCPUUtilizationPercentage: 70 + + features: + workflows: + enabled: true + observability: + enabled: true +``` + + + + +For headless deployments where only the API is needed: + +```yaml +backstage: + enabled: false + +# Security can also be disabled for development +security: + enabled: false +``` + + + + +## Troubleshooting + +### Backstage Not Loading + +Check pod status and logs: + +```bash +kubectl get pods -n openchoreo-control-plane -l app.kubernetes.io/component=backstage +kubectl logs -n openchoreo-control-plane deployment/backstage +``` + +### Authentication Issues + +Verify OAuth configuration by checking the deployment spec (the Backstage image is distroless, so `exec` commands like `env` are not available): + +```bash +# Check Backstage auth-related environment variables +kubectl get deployment backstage -n openchoreo-control-plane \ + -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \ + | grep -E "AUTH|THUNDER" + +# Check ThunderID is running +kubectl get pods -n thunder -l app.kubernetes.io/name=thunder +``` + +### API Connection Errors + +Verify OpenChoreo API is accessible: + +```bash +# Check API pod +kubectl get pods -n openchoreo-control-plane -l app.kubernetes.io/component=api-server + +# Check API logs for errors +kubectl logs -n openchoreo-control-plane deployment/openchoreo-api --tail=20 +``` + +### Database Connection Issues + +If Backstage fails to start with database errors: + +**For SQLite errors:** + +```bash +# Check for SQLite-specific errors in logs +kubectl logs -n openchoreo-control-plane deployment/backstage | grep -i "sqlite\|database" + +# Check the volume type (emptyDir vs PVC) +kubectl get deployment backstage -n openchoreo-control-plane \ + -o jsonpath='{.spec.template.spec.volumes}' | python3 -m json.tool +``` + +**For PostgreSQL errors:** + +```bash +# Verify PostgreSQL environment variables are configured +kubectl get deployment backstage -n openchoreo-control-plane \ + -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \ + | grep -E "DATABASE|POSTGRES" + +# Check for connection errors in logs +kubectl logs -n openchoreo-control-plane deployment/backstage | grep -i "postgres\|connection\|ECONNREFUSED" + +# Verify the secret has all required postgres keys +kubectl get secret backstage-secrets -n openchoreo-control-plane \ + -o jsonpath='{.data}' | python3 -c "import json,sys; print('\n'.join(sorted(json.load(sys.stdin).keys())))" +``` + +**Common issues:** + +| Error | Cause | Solution | +| -------------------------------------- | ------------------------ | ---------------------------------------------------------------------------- | +| `ECONNREFUSED` | PostgreSQL not reachable | Verify hostname, port, and network policies | +| `password authentication failed` | Invalid credentials | Check `postgres-password` in the Secret referenced by `backstage.secretName` | +| `database does not exist` | Missing database | Create the database on PostgreSQL server | +| `connection.filename is not supported` | Outdated Backstage image | Upgrade to latest control plane chart | + +## Next Steps + +- [Identity Provider Configuration](./identity-configuration.mdx): Configure an external IdP +- [Deployment Topology](./deployment-topology.mdx): Set up organizations and environments +- [Helm Charts Reference](../reference/helm/control-plane.mdx): Complete Backstage configuration options diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-ownership.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-ownership.mdx new file mode 100644 index 00000000..e4df0571 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-ownership.mdx @@ -0,0 +1,117 @@ +--- +title: Backstage Entity Ownership +description: Assign owners to Projects and Components in the OpenChoreo portal using the backstage.io/owner annotation. +sidebar_position: 5 +--- + +# Backstage Entity Ownership + +OpenChoreo does not yet have a native ownership concept on its resources. Until first-class ownership lands in OpenChoreo, you can assign owners to **Projects** and **Components** by adding a `backstage.io/owner` annotation on the corresponding custom resources. The portal reads this annotation during catalog sync and writes it to the `spec.owner` field of the resulting catalog entity. + +This is primarily useful if you extend the OpenChoreo portal with additional Backstage plugins that depend on ownership metadata — for example, "My Components" / "Owned Entities" views, ownership-based permission policies, or third-party plugins that filter by owner. The built-in OpenChoreo portal views do not themselves depend on this annotation, but setting it ensures ownership is populated correctly for any plugin you bring alongside. + +No OpenChoreo backend, CRD, or API changes are required — `backstage.io/owner` is a regular Kubernetes annotation already exposed through the OpenChoreo API. + +## How resolution works + +The portal resolves an owner for each Project and Component using a fixed precedence chain: + +| Entity | Resolution order | +| ----------- | ----------------------------------------------------------------- | +| `Project` | project annotation → `defaultOwner` | +| `Component` | component annotation → parent project annotation → `defaultOwner` | + +A Project's ownership annotation therefore propagates to every Component inside it, which is the common case when a single team owns a whole project. An individual Component can override this by setting its own annotation. + +Empty or whitespace-only annotation values are treated as unset and fall through to the next tier. Ownership changes are picked up on the next catalog sync cycle (~30 seconds) — no portal restart or redeploy is needed. + +All other entity types surfaced by the portal continue to use the configured `defaultOwner` until OpenChoreo gains a native ownership model. + +:::note +APIs exposed in the portal are derived internally from their parent Component's endpoints and automatically inherit that Component's resolved owner. You do not need to annotate them separately. +::: + +## Annotation format + +The annotation value must be a valid portal entity reference, in the form `:/`. The most common forms are: + +- `group:default/platform-team` — owned by a group +- `user:default/jane.doe` — owned by an individual user + +:::note +The referenced group or user must exist in the portal (typically populated from your IdP or an org-data location) for ownership-based views and permission checks to resolve correctly. If it does not, the entity will still display the literal owner string, but "My Components" filtering will not match. +::: + +## Annotating a project + +Annotating a Project once propagates ownership to every Component in it. + +```bash +kubectl annotate project my-project \ + backstage.io/owner=group:default/my-team +``` + +Equivalent declarative form in the `Project` manifest: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Project +metadata: + name: my-project + annotations: + backstage.io/owner: group:default/my-team +spec: + deploymentPipelineRef: + kind: DeploymentPipeline + name: default-pipeline +``` + +## Overriding for a single component + +When a specific Component within a Project belongs to a different team — for example, a shared library maintained by a platform team inside an application project — annotate the Component directly. The component-level annotation always wins over the project-level one. + +```bash +kubectl annotate component shared-lib \ + backstage.io/owner=group:default/platform-team +``` + +Equivalent declarative form: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: shared-lib + annotations: + backstage.io/owner: group:default/platform-team +spec: + componentType: + kind: ComponentType + name: Service + owner: + projectName: my-project +``` + +## Default owner fallback + +If neither the Component nor its parent Project carries a `backstage.io/owner` annotation, the portal falls back to the configured `defaultOwner`. This is also the owner applied to all other portal entities (anything that isn't a Project or Component). See [Backstage Configuration](./backstage-configuration.mdx) for how to deploy and configure the portal. + +## Verifying ownership + +After annotating a resource, wait for the next sync cycle (~30s) and check the entity in the portal — the **Owner** field on the Project or Component page should reflect the new value. + +To confirm the annotation is set on the cluster side: + +```bash +kubectl get project my-project \ + -o jsonpath='{.metadata.annotations.backstage\.io/owner}' +``` + +```bash +kubectl get component shared-lib \ + -o jsonpath='{.metadata.annotations.backstage\.io/owner}' +``` + +:::tip +If the Owner field in the portal still shows the default value after waiting, double-check that the annotation key is exactly `backstage.io/owner` (lowercase, with the dot) and that the value is a well-formed entity reference like `group:default/`. +::: diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/catalog-sync.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/catalog-sync.mdx new file mode 100644 index 00000000..a3e0a53c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/catalog-sync.mdx @@ -0,0 +1,101 @@ +--- +title: Catalog sync +description: How OpenChoreo entities are mirrored into the Backstage software catalog. +sidebar_position: 3 +--- + +# Catalog sync + +Once installed, the **`@openchoreo/backstage-plugin-catalog-backend-module`** registers an entity provider that polls the OpenChoreo Platform API on a schedule and writes the result into your Backstage catalog. + +## What gets synced + +| OpenChoreo resource | Backstage entity | Notes | +| ----------------------------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Namespace | `Domain` | One per OpenChoreo namespace. | +| Project | `System` | `spec.domain` references the parent namespace. | +| Component | `Component` | `spec.system` references the parent project. `spec.type` is the OpenChoreo component type (e.g. `deployment/service`). | +| API definition | `API` | Linked to its owning component. | +| Environment | custom kind `environment` | Listed under each namespace. | +| ComponentType / Trait / Workflow | custom kinds | Used by the scaffolder templates. | +| ClusterComponentType / ClusterTrait / ClusterWorkflow | cluster-scoped custom kinds | | +| DataPlane / WorkflowPlane / ObservabilityPlane | infrastructure entities | Visible in the platform overview. | + +The full set of relations is defined in `@openchoreo/backstage-plugin-common` — `RELATION_DEPLOYS_TO`, `RELATION_USES_PIPELINE`, `RELATION_HOSTED_ON`, etc. The catalog graph picks them up automatically once the entity provider is active. + +## Tuning the sync schedule + +```yaml title="app-config.yaml" +openchoreo: + schedule: + frequency: 30 # seconds between catalog provider runs (default: 30) + timeout: 120 # seconds before a single run is considered hung (default: 120) +``` + +Both fields are plain integers (seconds). They are _not_ the Backstage `HumanDuration` shape — passing `{ minutes: 1 }` produces a startup error. + +## Catalog rules + +Backstage's catalog rejects entity kinds that are not in `catalog.rules.allow`. Add `Domain` (and `Group`, `User` if you sync identities later) to the allow list: + +```yaml title="app-config.yaml" +catalog: + rules: + - allow: [Component, System, Domain, API, Resource, Location, Group, User] +``` + +## Default ownership + +Each synced entity gets `spec.owner = group:default/${openchoreo.defaultOwner}`. The default value is `openchoreo-users`. Override it if you sync your own users/groups separately: + +```yaml +openchoreo: + defaultOwner: platform-team +``` + +## Inspecting synced entities + +```bash +# All Domain entities +curl http://localhost:7007/api/catalog/entities?filter=kind=domain \ + -H "Authorization: Bearer ${BACKSTAGE_TOKEN}" | jq + +# Components in a given system +curl 'http://localhost:7007/api/catalog/entities?filter=kind=component,spec.system=url-shortener' \ + -H "Authorization: Bearer ${BACKSTAGE_TOKEN}" | jq +``` + +## How the sync authenticates to OpenChoreo + +The entity provider runs as a background task — there's no end-user request to attach a token to. It uses an OAuth2 **client credentials** flow against the OpenChoreo identity provider: + +```yaml +openchoreo: + auth: + clientId: openchoreo-backstage-client + clientSecret: backstage-portal-secret + tokenUrl: http://thunder.openchoreo.localhost:8080/oauth2/token +``` + +The catalog provider only fetches a token when **`openchoreo.features.auth.enabled: true`**. If that flag is `false`, the provider skips authentication and the OpenChoreo API rejects the calls with `MISSING_TOKEN`. As the install guide explains in its [cluster-mirroring callout](./installing-into-existing-backstage.mdx#configure-app-config), this flag must match how your OpenChoreo cluster was deployed — if the cluster runs in auth-off mode the API itself accepts unauthenticated calls and the provider works without credentials. + +## Common issues + +**`Failed to fetch namespaces: 401 Unauthorized - missing or invalid authentication token`** + +Either `openchoreo.features.auth.enabled` is `false`, or the `clientId` / `clientSecret` / `tokenUrl` are wrong, or the IDP is not reachable. Check the token endpoint with: + +```bash +curl -X POST -d 'grant_type=client_credentials' \ + -d "client_id=${OPENCHOREO_CLIENT_ID}" \ + -d "client_secret=${OPENCHOREO_CLIENT_SECRET}" \ + ${OPENCHOREO_TOKEN_URL} +``` + +**Entities fail to appear despite a successful run** + +Check `catalog.rules`. If `Domain` is not in the allow list, the catalog drops every namespace silently. + +**Sync runs every 30s and floods logs** + +Tune `openchoreo.schedule.frequency` upward for production. The default 30s is fine on `k3d`. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/compatibility-matrix.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/compatibility-matrix.mdx new file mode 100644 index 00000000..dc908ad9 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/compatibility-matrix.mdx @@ -0,0 +1,97 @@ +--- +title: Compatibility matrix +description: Tested combinations of OpenChoreo plugins with Backstage releases. +sidebar_position: 7 +--- + +# Compatibility matrix + +The OpenChoreo plugin set is tested against a specific Backstage release line. Installing into a Backstage app on a different line typically requires pinning every `@backstage/*` package; see [Troubleshooting](./troubleshooting.mdx). + +## Tested combination + +| Component | Version | +| ---------------------- | ------------ | +| Backstage release line | **1.51.0** | +| Node.js | 20.x or 22.x | +| Yarn | 4.13.x | +| `@backstage/cli` | 0.36.x | +| OpenChoreo plugin set | `1.2.x` | + +## Required `resolutions` + +Add the following to your workspace root `package.json`. The MUI pin keeps `material-ui-popup-state` from resolving to a nested MUI 5.13.x that lacks the `/version` subpath (which Rspack fails to compile against). The React pins keep types consistent across the dep graph. + +```json title="package.json" +{ + "resolutions": { + "@types/react": "^18", + "@types/react-dom": "^18", + "@mui/material": "^5.18.0" + } +} +``` + +That is the minimum. After running `yarn backstage-cli versions:bump --release 1.51.0` you do **not** need to copy a full `@backstage/*` resolutions block — `versions:bump` writes caret ranges to every `package.json` in your workspace and the lockfile pins them. Reach for explicit `@backstage/*` resolutions only when you hit a transitive-drift error at startup; the previous (1.1.x) install guide carried a 70-entry block because 1.1.x plugins were validated against a single point release. + +## Aligning your existing app + +If your Backstage app is on a different release line, run: + +```bash +yarn backstage-cli versions:bump --release 1.51.0 +yarn install +``` + +…before adding the OpenChoreo packages. + +## Plugin packages + +All plugins ship with both a default (legacy) export and a `/alpha` export for use with the [New Frontend System (NFS)](./installing-into-existing-backstage.mdx). The default export remains the entry point for hosts on the legacy frontend; `/alpha` exports a `createFrontendPlugin` instance for use in `createApp({ features: [...] })`. + +### Core (required) + +Installed and wired by [section 4 of the install guide](./installing-into-existing-backstage.mdx#core). + +| Package | Role | `/alpha` | Notes | +| -------------------------------------------------------------------------- | ----------------------- | -------- | ---------------------------------------------- | +| `@openchoreo/backstage-plugin` | `frontend-plugin` | ✓ | Cell, Deploy, Definition tabs; overview cards. | +| `@openchoreo/backstage-plugin-react` | `web-library` | — | Shared React hooks (permission hooks, etc.). | +| `@openchoreo/backstage-design-system` | `web-library` | — | MUI v4 theme + form widgets. | +| `@openchoreo/backstage-plugin-common` | `common-library` | — | Constants, types, relation refs. | +| `@openchoreo/backstage-plugin-backend` | `backend-plugin` | — | Powers `/api/openchoreo/*`. | +| `@openchoreo/backstage-plugin-catalog-backend-module` | `backend-plugin-module` | — | Catalog entity provider + service factories. | +| `@openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy` | `backend-plugin-module` | — | Permission policy. | +| `@openchoreo/backstage-plugin-scaffolder-backend-module` | `backend-plugin-module` | — | Scaffolder actions. | +| `@openchoreo/backstage-plugin-auth-backend-module-openchoreo-auth` | `backend-plugin-module` | — | OpenChoreo OIDC sign-in. | +| `@openchoreo/openchoreo-client-node` | `node-library` | — | Generated typed API client. | +| `@openchoreo/openchoreo-auth` | `node-library` | — | Token service + IDP middleware. | + +### Optional tab packs + +Installed and wired by [sections 5–7 of the install guide](./installing-into-existing-backstage.mdx#5-add-observability-tabs-optional). Each frontend/backend pair is installed together. + +| Package | Role | `/alpha` | Tabs delivered | +| --------------------------------------------------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------- | +| `@openchoreo/backstage-plugin-openchoreo-observability` | `frontend-plugin` | ✓ | Component → Logs/Events/Metrics/Alerts/Wirelogs, System → Logs/Traces/Incidents/RCA/Cost. | +| `@openchoreo/backstage-plugin-openchoreo-observability-backend` | `backend-plugin` | — | Backend + `/resolve-urls` for the observability tabs. | +| `@openchoreo/backstage-plugin-openchoreo-ci` | `frontend-plugin` | ✓ | Component → Build. | +| `@openchoreo/backstage-plugin-openchoreo-ci-backend` | `backend-plugin` | — | Backend for the Build tab. | +| `@openchoreo/backstage-plugin-openchoreo-workflows` | `frontend-plugin` | ✓ | Standalone `/workflows` page + Runs tab on Workflow/ClusterWorkflow. | +| `@openchoreo/backstage-plugin-openchoreo-workflows-backend` | `backend-plugin` | — | Backend for the workflows page. | + +### Also published + +These packages live in the `@openchoreo` scope and ship on the same release cadence as the rest, but the canonical install guide does not wire them. They exist for downstream tools and special-case installs. + +| Package | Use | +| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `@openchoreo/openapi-client-generator-node` | Build-time generator for the typed OpenChoreo API clients. Consumed by plugin authors, not Backstage runtime. | +| `@openchoreo/backstage-plugin-platform-engineer-core` | Platform-engineer home/dashboard surface used by the in-tree portal. Not part of the canonical install. Ships an `/alpha` entry point. | +| `@openchoreo/backstage-plugin-platform-engineer-core-backend` | Backend for the above. | +| `@openchoreo/backstage-plugin-thunder-idp-client-node` | TypeScript client for the ThunderID IDP user/group API. Used by `catalog-backend-module-openchoreo-users` below. | +| `@openchoreo/backstage-plugin-catalog-backend-module-openchoreo-users` | Syncs ThunderID users/groups into the Backstage catalog. Install only if your OpenChoreo cluster uses ThunderID as its IDP and you want user/group entities in Backstage. | + +## Reporting compatibility issues + +If you successfully install on a different Backstage release line, file an issue at [openchoreo/backstage-plugins](https://github.com/openchoreo/backstage-plugins/issues) — we will add the combination to this matrix. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/entity-views.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/entity-views.mdx new file mode 100644 index 00000000..d7806974 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/entity-views.mdx @@ -0,0 +1,208 @@ +--- +title: Entity views +description: OpenChoreo cards and tabs on your catalog entity pages. +sidebar_position: 5 +--- + +# Entity views + +OpenChoreo ships entity-page tabs for **Domain**, **System**, and **Component** entities. They mirror what the in-tree OpenChoreo portal shows, so a user navigating from the OpenChoreo UI into your Backstage instance sees the same tabs they're used to. + +:::tip Under NFS, tabs auto-mount + +If you followed the [install guide Section 4 — Core](./installing-into-existing-backstage.mdx#core) on the default NFS scaffold, every tab in the table below is contributed by the plugin's `/alpha` export as an `EntityContentBlueprint` extension and mounts automatically on the correct entity kind. **You do not need to edit `EntityPage.tsx`** (the NFS scaffold does not even create one). The [wiring example](#legacy-wiring) further down applies only to legacy hosts. + +::: + +## Tab catalog + +Every tab below ships in one of three "tab packs". Install only the packs whose tabs you want; tabs whose pack is not installed simply won't appear in the layout. + +| Kind | Tab | Component / Path | Package | Notes | +| -------------------------- | ------------- | ------------------------------------------------ | ------------------------------------------------------- | ----------------------------------------------------------------------- | +| Domain | Overview | (built-in) | `@openchoreo/backstage-plugin` | Cards: `NamespaceProjectsCard`, `NamespaceResourcesCard`. | +| Domain | Definition | `ResourceDefinitionTab` (`/definition`) | `@openchoreo/backstage-plugin` | Raw OpenChoreo resource manifest. | +| System | Overview | (built-in) | `@openchoreo/backstage-plugin` | Cards: `ProjectComponentsCard`, `DeploymentPipelineCard`. | +| System | Definition | `ResourceDefinitionTab` (`/definition`) | `@openchoreo/backstage-plugin` | | +| System | Cell Diagram | `CellDiagram` (`/cell-diagram`) | `@openchoreo/backstage-plugin` | Project-level architecture view. | +| System | Logs | `ObservabilityProjectRuntimeLogs` (`/logs`) | `@openchoreo/backstage-plugin-openchoreo-observability` | Project-scoped runtime logs. | +| System | Traces | `ObservabilityTraces` (`/traces`) | `@openchoreo/backstage-plugin-openchoreo-observability` | | +| System | Incidents | `ObservabilityProjectIncidents` (`/incidents`) | `@openchoreo/backstage-plugin-openchoreo-observability` | | +| System | RCA Reports | `ObservabilityRCA` (`/rca-reports`) | `@openchoreo/backstage-plugin-openchoreo-observability` | Root-cause analysis agent reports. | +| System | Cost Analysis | `ObservabilityCostAnalysis` (`/cost-analysis`) | `@openchoreo/backstage-plugin-openchoreo-observability` | FinOps agent reports. | +| Component | Overview | (built-in) | `@openchoreo/backstage-plugin` | Cards: `DeploymentStatusCard`, `RuntimeHealthCard`, Deployments widget. | +| Component | Definition | `ResourceDefinitionTab` (`/definition`) | `@openchoreo/backstage-plugin` | | +| Component | Build | `Workflows` (`/workflows`) | `@openchoreo/backstage-plugin-openchoreo-ci` | Workflow runs / triggers. | +| Component | Deploy | `Environments` (`/environments`) | `@openchoreo/backstage-plugin` | Per-environment runtime status. | +| Component | Logs | `ObservabilityRuntimeLogs` (`/runtime-logs`) | `@openchoreo/backstage-plugin-openchoreo-observability` | Component-scoped runtime logs. | +| Component | Events | `ObservabilityRuntimeEvents` (`/runtime-events`) | `@openchoreo/backstage-plugin-openchoreo-observability` | Component-scoped runtime events. | +| Component | Metrics | `ObservabilityMetrics` (`/metrics`) | `@openchoreo/backstage-plugin-openchoreo-observability` | | +| Component | Alerts | `ObservabilityAlerts` (`/alerts`) | `@openchoreo/backstage-plugin-openchoreo-observability` | | +| Component | Wirelogs | `ObservabilityWirelogs` (`/wirelogs`) | `@openchoreo/backstage-plugin-openchoreo-observability` | Service-mesh wire-level logs. | +| Workflow / ClusterWorkflow | Runs | `WorkflowRuns` (`/runs`) | `@openchoreo/backstage-plugin-openchoreo-workflows` | Only for `spec.type === 'Generic'`. | + +Each `openchoreo-observability` / `openchoreo-ci` / `openchoreo-workflows` frontend package has a matching backend package (`-backend` suffix) — install both. The frontend talks to the backend at a Backstage discovery endpoint; the backend talks to OpenChoreo at `${openchoreo.baseUrl}` and `/resolve-urls` for observability. + +## Cards on the Overview tab + +`@openchoreo/backstage-plugin`'s `/alpha` export contributes a wide set of `EntityCardBlueprint` extensions: + +- **Domain** Overview: `NamespaceProjectsCard`, `NamespaceResourcesCard`. +- **System** Overview: `ProjectComponentsCard`, `DeploymentPipelineCard`, `CellTopologyCard`. +- **Component** Overview: `DeploymentStatusCard`, `RuntimeHealthCard`, Deployments widget linking to the Deploy tab. +- **Environment / DataPlane / WorkflowPlane / ObservabilityPlane / DeploymentPipeline** Overview: kind-specific status and configuration cards (30+ in total covering every OpenChoreo platform kind). + +Under NFS the cards auto-mount into the default Overview Grid alongside the upstream About / Links / Labels cards. Under the legacy install you compose them by hand in your `EntityPage.tsx`. + +## What the views actually render + +`` issues authenticated calls to `${openchoreo.baseUrl}` via the Backstage backend proxy at `/api/openchoreo/*`. It reads the entity's annotations to determine which OpenChoreo project and component to query. Components synced by the catalog provider already have these annotations — for components imported from your own `catalog-info.yaml`, the tab renders an "OpenChoreo metadata not found" empty state. + +`` does the same against `${openchoreo.baseUrl}/projects/{name}/cell-diagram` for the project the system corresponds to. + +Observability tabs first call the observability backend's `/resolve-urls` endpoint to discover the per-environment Observer/RCA/FinOps URLs, then call those services directly with the IDP token attached (header `x-openchoreo-direct: true` to bypass any intermediate proxies). + +The Build tab (`Workflows`) calls the CI backend, which proxies to OpenChoreo's workflow API. + +## Hiding or moving tabs under NFS {#nfs-customization} + +If you want to suppress a tab on a specific kind, or move it to a different path, override the contributed `EntityContentBlueprint` extension. Each tab is registered with a stable extension ID — find the ID in the plugin's `alpha.tsx` (e.g. `componentDeployEntityContent`) and override its `attachTo` or `disabled` in your `customAppModule`: + +```tsx +import { openchoreoPluginAlphaBase } from "@openchoreo/backstage-plugin/alpha"; + +const customised = openchoreoPluginAlphaBase.withOverrides({ + extensions: [ + openchoreoPluginAlphaBase + .getExtension("entity-content:openchoreo/component-deploy") + .override({ + // hide on a specific kind, or change the route, etc. + disabled: true, + }), + ], +}); +``` + +Then add `customised` to `createApp({ features: [...] })` **instead of** `openchoreoPluginAlpha`. + +## Legacy wiring example {#legacy-wiring} + +For hosts on the legacy frontend system (see [install guide Section 9](./installing-into-existing-backstage.mdx#9-legacy-frontend-system-fallback)), tabs must be mounted by hand in `packages/app/src/components/catalog/EntityPage.tsx`: + +```tsx title="packages/app/src/components/catalog/EntityPage.tsx (legacy)" +import { + Environments, + CellDiagram, + ResourceDefinitionTab, +} from '@openchoreo/backstage-plugin'; +import { Workflows } from '@openchoreo/backstage-plugin-openchoreo-ci'; +import { + ObservabilityMetrics, + ObservabilityAlerts, + ObservabilityRuntimeLogs, + ObservabilityRuntimeEvents, + ObservabilityWirelogs, + ObservabilityProjectRuntimeLogs, + ObservabilityTraces, + ObservabilityProjectIncidents, + ObservabilityRCA, + ObservabilityCostAnalysis, +} from '@openchoreo/backstage-plugin-openchoreo-observability'; + +// componentEntityPage / defaultEntityPage: + + + + + + + + + + + + + + + + + + + + + + + + + +// systemPage: + + + + + + + + + + + + + + + + + + + + + + +// domainPage: + + + +``` + +OpenChoreo synced components have type strings like `deployment/web-application` and `deployment/service`. The default `componentPage` `EntitySwitch` only routes `service`/`website` to the page that includes Environments — add the Environments route to `defaultEntityPage` too if you want it on every component kind. + +## Other extensions you can opt into + +The `@openchoreo/backstage-plugin` package re-exports more components than the install guide wires. These are not part of the canonical install but are available for hosts that want richer overview cards or standalone pages: + +| Export | Use | +| ------------------------------ | --------------------------------------------------------------------------- | +| `RuntimeHealthCard` | Smaller component-level health card for the **Overview** tab. | +| `DeploymentStatusCard` | Per-environment deployment status, for the Overview tab. | +| `DeploymentPipelineCard` | Deployment pipeline summary on a `Component` overview. | +| `EnvironmentStatusSummaryCard` | Aggregated environment status on an Environment entity page. | +| `AccessControlContent` | Standalone Access Control page (only useful when authz is enabled). | +| `GitSecretsContent` | Git secret management page (only useful when secret-management is enabled). | + +These ship in the same `@openchoreo/backstage-plugin` package — no extra installation step. + +## Hiding tabs when annotations are missing (legacy) + +For legacy hosts that want a tab to only appear on entities the OpenChoreo provider synced, gate it on the `openchoreo.io/component-name` annotation: + +```tsx +import { isOpenChoreoComponent } from "@openchoreo/backstage-plugin-common"; + + + +; +``` + +(`isOpenChoreoComponent` checks for the standard OpenChoreo annotations; see `@openchoreo/backstage-plugin-common` for the full list.) + +## Frontend dependencies + +The plugin uses **MUI v4** (`@material-ui/core@4.12.x`), matching Backstage's current default. If your host app has migrated to MUI v5, you must keep both: do not remove `@material-ui/core@4.x` from your dependencies. Note that the install guide pins `@mui/material` (v5) via `resolutions` to fix a `material-ui-popup-state` transitive resolution issue — see [Section 2 of the install guide](./installing-into-existing-backstage.mdx#2-pin-backstage-versions). + +`@material-ui/lab@4.0.0-alpha.61` is required for some sub-components — add it to your app workspace if you do not already depend on it. + +The observability pack pulls `recharts`, `@material-ui/pickers`, and `@date-io/date-fns` transitively; the CI pack pulls `@rjsf/*` for dynamic workflow-parameter forms. Both are pinned by the packages themselves. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx new file mode 100644 index 00000000..138ab5fe --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx @@ -0,0 +1,925 @@ +--- +title: Installing into an existing Backstage app +description: Step-by-step installation of OpenChoreo plugins into your Backstage workspace. +sidebar_position: 3 +--- + +# Installing into an existing Backstage app + +This guide walks through installing the OpenChoreo plugin set into a Backstage app you already own. + +Two install paths are supported: + +- **New Frontend System (NFS)** — the default scaffold from `npx @backstage/create-app@latest`. Plugins are added as features to `createApp({ features: [...] })`, and every OpenChoreo entity tab and overview card auto-mounts. **No `EntityPage.tsx` edits.** This is the path you should follow unless you have a reason not to. +- **Legacy frontend system** — for hosts scaffolded with `--legacy`, or older apps where you have heavy `EntityPage.tsx` customization you want to keep. See [Section 9 — Legacy frontend system (fallback)](#9-legacy-frontend-system-fallback). + +The guide is **organized by feature**. Sections 1–3 are setup. Section 4 (**Core**) is the only mandatory install — after finishing it you have a working OpenChoreo-aware Backstage with Domain/System/Component pages and the **Cell**, **Deploy**, and **Definition** tabs rendering real data. Sections 5–7 each add one optional tab pack on top of Core; you can install any subset independently. + +:::info + +OpenChoreo plugins are published to **GitHub Packages** under the [`@openchoreo`](https://github.com/orgs/openchoreo/packages?repo_name=backstage-plugins) scope. You install them with `yarn add` once your package manager is authenticated against `https://npm.pkg.github.com` — see [Authenticate to GitHub Packages](#authenticate-to-github-packages) below. + +::: + +:::tip Tracking the upcoming 1.2.0 release + +The install commands on this page reference `@openchoreo/@^1.2.0`, which will be the GA dist-tag of the next plugin release. While `1.2.0` is still under active development, install via the `next` dist-tag to get the latest prerelease today: + +```bash +yarn workspace app add @openchoreo/backstage-plugin@next +``` + +Once `1.2.0` GA is announced, swap `@next` for `@^1.2.0` to pin to the stable release. + +::: + +## 1. Prerequisites + +- A Backstage workspace on the [supported Backstage version](./compatibility-matrix.mdx). This guide pins to **Backstage `1.51.0`**. +- The workspace must be scaffolded with the **default NFS scaffold**: `npx @backstage/create-app@latest`. (Do NOT pass `--legacy`. If you must stay on legacy, see [Section 9](#9-legacy-frontend-system-fallback).) +- Node.js **20 or 22**, Yarn **4.13.x** (the current `create-app` scaffold ships Yarn 4.13.0 in `.yarn/releases/`). +- Access to a running OpenChoreo control plane (local `k3d` or a deployed cluster). +- OAuth client credentials for the OpenChoreo Identity Provider (used by the catalog sync and user sign-in). On `k3d` the helm chart pre-seeds these; for a deployed cluster see [Identity configuration](../identity-configuration.mdx). + +:::tip Backstage version + +`create-app@latest` will likely give you Backstage `1.52.x` or newer at the time you read this. After scaffolding, run `yarn backstage-cli versions:bump --release 1.51.0` (covered in [Section 2](#2-pin-backstage-versions)) to align with the tested combination. + +::: + +## 2. Pin Backstage versions + +Add the following resolutions to your workspace `package.json`. They lock every `@backstage/*` package to the version line that the OpenChoreo plugins are tested against, and pin `@mui/material` to a version that satisfies all transitive consumers (without this `@mui/material` pin, `material-ui-popup-state` resolves to a nested copy of MUI 5.13.x that lacks the `/version` subpath and Rspack fails to compile). + +```json title="package.json" +{ + "resolutions": { + "@types/react": "^18", + "@types/react-dom": "^18", + "@mui/material": "^5.18.0" + } +} +``` + +For the full pinned set see the [compatibility matrix](./compatibility-matrix.mdx). + +If your existing app is at a different Backstage release line, run: + +```bash +yarn backstage-cli versions:bump --release 1.51.0 +yarn install +``` + +…to align before adding the OpenChoreo packages. + +## 3. Authenticate to GitHub Packages {#authenticate-to-github-packages} + +GitHub Packages requires authentication even for `read:packages`-only operations. Create a [classic Personal Access Token](https://github.com/settings/tokens/new) with the `read:packages` scope, then wire it into your package manager. + +**Yarn 4 (Berry)** — the current `create-app` scaffold's `.yarnrc.yml` enables a 3-day [npm minimum-age gate](https://yarnpkg.com/configuration/yarnrc#npmMinimalAgeGate) that blocks newly published packages. Update `.yarnrc.yml` to both add the `@openchoreo` scope auth **and** pre-approve the scope so fresh OpenChoreo releases install immediately: + +```yaml title=".yarnrc.yml" +nodeLinker: node-modules +npmMinimalAgeGate: 3d +npmPreapprovedPackages: + - "@backstage/*" + - "@openchoreo/*" + +yarnPath: .yarn/releases/yarn-4.13.0.cjs + +npmScopes: + openchoreo: + npmRegistryServer: "https://npm.pkg.github.com" + npmAlwaysAuth: true + npmAuthToken: "${GITHUB_PACKAGES_TOKEN}" +``` + +…then `export GITHUB_PACKAGES_TOKEN=` before running `yarn install`. Berry expands the `${...}` placeholder from the environment so the token never lands in the repo. + +In **CI**, GitHub Actions can use the auto-issued `GITHUB_TOKEN` instead of a PAT, provided the workflow has `permissions: { packages: read }` and the running repo is in (or a fork of) an org the package is published from. + +--- + +## 4. Core install {#core} + +Required. Delivers OpenChoreo sign-in, catalog sync (Domain/System/Component entities), and the **Cell**, **Deploy**, and **Definition** tabs on every entity page. + +After this section, a user signs in via the OpenChoreo IDP, lands in the catalog, and clicks into an entity to see live Cell/Deploy/Definition data. Sections 5–7 build on this foundation; do them in any order. + +:::tip Why sign-in is part of Core + +The Deploy and Cell tabs read from OpenChoreo APIs that require a **user IDP token** (not the Backstage identity token). That token only exists after the user signs in via the OpenChoreo IDP. The catalog _provider_ uses client-credentials and doesn't need user sign-in, but the _tabs_ on those entities do. So sign-in lives in Core, not in an opt-in section. + +If your OpenChoreo cluster runs with `features.auth.enabled: false` (no IDP), the same wiring still works — `DynamicSignInPage` (below) falls through to guest sign-in. See the [cluster-mirroring warning](#configure-app-config) in section 4.4. + +::: + +### 4.1 Install packages + +In your **app** workspace: + +```bash +yarn workspace app add \ + @openchoreo/backstage-design-system@^1.2.0 \ + @openchoreo/backstage-plugin-common@^1.2.0 \ + @openchoreo/backstage-plugin-react@^1.2.0 \ + @openchoreo/backstage-plugin@^1.2.0 \ + @material-ui/lab@4.0.0-alpha.61 +``` + +In your **backend** workspace: + +```bash +yarn workspace backend add \ + @openchoreo/openchoreo-client-node@^1.2.0 \ + @openchoreo/openchoreo-auth@^1.2.0 \ + @openchoreo/backstage-plugin-common@^1.2.0 \ + @openchoreo/backstage-plugin-catalog-backend-module@^1.2.0 \ + @openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy@^1.2.0 \ + @openchoreo/backstage-plugin-scaffolder-backend-module@^1.2.0 \ + @openchoreo/backstage-plugin-backend@^1.2.0 \ + @openchoreo/backstage-plugin-auth-backend-module-openchoreo-auth@^1.2.0 +``` + +:::tip Pinning all `@openchoreo/*` to the same minor + +The packages above are linked together by the OpenChoreo release process — they always release with matching versions. Pinning them all to the same `^x.y.0` caret keeps your install on one consistent release line. If you want to track the cutting edge, swap `^1.2.0` for the `next` dist-tag: `yarn workspace app add @openchoreo/backstage-plugin@next` (etc.). Prereleases are published under `next`; stable releases are under `latest`. + +::: + +### 4.2 Wire the backend + +The NFS scaffold's `packages/backend/src/index.ts` already wires `scaffolder`, `search`, `techdocs`, `kubernetes`, `notifications`, `signals`, and `mcp-actions` for you. **Add the OpenChoreo modules on top — don't replace the file.** + +Edit `packages/backend/src/index.ts`: + +```ts title="packages/backend/src/index.ts" +import { createBackend } from "@backstage/backend-defaults"; +import { rootHttpRouterServiceFactory } from "@backstage/backend-defaults/rootHttpRouter"; +import { + immediateCatalogServiceFactory, + annotationStoreFactory, +} from "@openchoreo/backstage-plugin-catalog-backend-module"; +import { createIdpTokenHeaderMiddleware } from "@openchoreo/openchoreo-auth"; +import { OpenChoreoAuthModule } from "@openchoreo/backstage-plugin-auth-backend-module-openchoreo-auth"; + +const backend = createBackend(); + +// OpenChoreo service factories. +// AnnotationStore is shared between the catalog module and openchoreo-backend. +// ImmediateCatalogService lets scaffolder actions register entities synchronously. +backend.add(immediateCatalogServiceFactory); +backend.add(annotationStoreFactory); + +// IDP token middleware: reads x-openchoreo-token from frontend requests and +// stashes it in AsyncLocalStorage. The permission policy and tab backends +// pull from that context to authorize the signed-in user against OpenChoreo. +// MUST be added before applyDefaults() so the context exists when downstream +// handlers run. +backend.add( + rootHttpRouterServiceFactory({ + configure: ({ app, applyDefaults, middleware }) => { + app.use(middleware.helmet()); + app.use(middleware.cors()); + app.use(middleware.compression()); + app.use(createIdpTokenHeaderMiddleware()); + applyDefaults(); + }, + }), +); + +// ... keep all the existing scaffold backend.add(...) lines ... + +// Sign-in: register OpenChoreo as an OIDC provider. +backend.add(OpenChoreoAuthModule); + +// Replace the scaffold's `@backstage/plugin-permission-backend-module-allow-all-policy` +// with the OpenChoreo permission policy. The OpenChoreo policy delegates +// `openchoreo.*` permissions to the OpenChoreo authorization service and +// falls back to ALLOW for everything else, so it is composable with +// other host-app policies. +backend.add( + import("@openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy"), +); + +// IMPORTANT: register catalog-backend-module BEFORE openchoreo-backend. +// openchoreo-backend depends on the AnnotationStore initialized by the catalog module. +backend.add(import("@openchoreo/backstage-plugin-catalog-backend-module")); +backend.add(import("@openchoreo/backstage-plugin-backend")); +backend.add(import("@openchoreo/backstage-plugin-scaffolder-backend-module")); + +backend.start(); +``` + +If your existing `index.ts` registers `@backstage/plugin-permission-backend-module-allow-all-policy`, remove that line — only one permission policy can be active at a time. + +### 4.3 Wire the frontend + +Three sub-steps, all in `packages/app/src/`. Compared to the legacy install, **you do not edit `EntityPage.tsx`** — every Core OpenChoreo tab (Cell, Deploy, Definition) and overview card is contributed automatically by the plugin's `/alpha` export. + +#### 4.3.1 Add the OpenChoreo plugin to `createApp` {#register-plugin} + +A fresh NFS scaffold's `packages/app/src/App.tsx` is roughly: + +```tsx title="packages/app/src/App.tsx" +import { createApp } from "@backstage/frontend-defaults"; +import catalogPlugin from "@backstage/plugin-catalog/alpha"; +import { navModule } from "./modules/nav"; + +export default createApp({ + features: [catalogPlugin, navModule], +}); +``` + +Add the OpenChoreo plugin to the `features` array: + +```tsx title="packages/app/src/App.tsx" +import { createApp } from "@backstage/frontend-defaults"; +import catalogPlugin from "@backstage/plugin-catalog/alpha"; +import openchoreoPluginAlpha from "@openchoreo/backstage-plugin/alpha"; +import { navModule } from "./modules/nav"; +import { customAppModule } from "./customAppModule"; + +export default createApp({ + features: [ + catalogPlugin, + openchoreoPluginAlpha, + navModule, + customAppModule, // see 4.3.2 below + ], +}); +``` + +That single import gives you the **Cell**, **Deploy**, and **Definition** entity tabs (auto-mounted on Domain / System / Component pages by kind) and the OpenChoreo overview cards (Project Contents, Deployment Pipeline, Deployments widget, etc.). + +#### 4.3.2 Author the `customAppModule` {#custom-app-module} + +Create `packages/app/src/customAppModule.tsx`. It bundles three things into one frontend module: + +- A `SignInPageBlueprint` extension that toggles between OpenChoreo OIDC sign-in and guest sign-in based on `openchoreo.features.auth.enabled`. +- An `ApiBlueprint` extension that registers `OpenChoreoFetchApi` against `fetchApiRef` so every tab data fetch carries the `x-openchoreo-token` header. +- An `ApiBlueprint` extension that registers `OpenChoreoPermissionApi` against `permissionApiRef` so the Deploy tab's env-scoped permission checks include the IDP token. + +The `OpenChoreoFetchApi` and `OpenChoreoPermissionApi` classes are the same as the legacy install — they are not shipped by the OpenChoreo plugins; you copy them into your app. + +```tsx title="packages/app/src/customAppModule.tsx" +import { + ApiBlueprint, + configApiRef, + createFrontendModule, + discoveryApiRef, + fetchApiRef, + identityApiRef, + oauthRequestApiRef, + useApi, +} from "@backstage/frontend-plugin-api"; +import { SignInPageBlueprint } from "@backstage/plugin-app-react"; +import { permissionApiRef } from "@backstage/plugin-permission-react"; +import { SignInPage } from "@backstage/core-components"; +import { OAuth2 } from "@backstage/core-app-api"; +import { + ApiRef, + BackstageIdentityApi, + createApiRef, + OAuthApi, + ProfileInfoApi, + SessionApi, +} from "@backstage/core-plugin-api"; +import { AuthorizeResult } from "@backstage/plugin-permission-common"; +import type { Config } from "@backstage/config"; +import type { DiscoveryApi, IdentityApi } from "@backstage/core-plugin-api"; +import type { FetchApi } from "@backstage/frontend-plugin-api"; + +const OPENCHOREO_TOKEN_HEADER = "x-openchoreo-token"; +const DIRECT_MODE_HEADER = "x-openchoreo-direct"; + +export const openChoreoAuthApiRef: ApiRef< + OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi +> = createApiRef({ + id: "auth.openchoreo-auth", +}); + +class OpenChoreoFetchApi implements FetchApi { + private readonly authEnabled: boolean; + + constructor( + private readonly identityApi: IdentityApi, + private readonly oauthApi: OAuthApi, + configApi: Config, + ) { + this.authEnabled = + configApi.getOptionalBoolean("openchoreo.features.auth.enabled") ?? true; + this.fetch = this.fetch.bind(this); + } + + async fetch(input: RequestInfo | URL, init?: RequestInit): Promise { + const headers = new Headers(init?.headers); + const isDirect = headers.has(DIRECT_MODE_HEADER); + if (isDirect) headers.delete(DIRECT_MODE_HEADER); + + if (isDirect) { + if (this.authEnabled) { + try { + const idpToken = await this.oauthApi.getAccessToken(); + if (idpToken) headers.set("Authorization", `Bearer ${idpToken}`); + } catch { + // No IDP token — proceed unauthenticated. + } + } + } else { + const { token: backstageToken } = await this.identityApi.getCredentials(); + if (backstageToken) + headers.set("Authorization", `Bearer ${backstageToken}`); + + if (this.authEnabled) { + try { + const idpToken = await this.oauthApi.getAccessToken(); + if (idpToken) headers.set(OPENCHOREO_TOKEN_HEADER, idpToken); + } catch { + // No IDP token available — proceed with just the Backstage token. + } + } + } + + return fetch(input, { ...init, headers }); + } +} + +class OpenChoreoPermissionApi { + private readonly enabled: boolean; + private readonly authEnabled: boolean; + private readonly discovery: DiscoveryApi; + private readonly identityApi: IdentityApi; + private readonly oauthApi: OAuthApi; + + constructor(options: { + config: Config; + discovery: DiscoveryApi; + identity: IdentityApi; + oauthApi: OAuthApi; + }) { + this.discovery = options.discovery; + this.identityApi = options.identity; + this.oauthApi = options.oauthApi; + this.enabled = + options.config.getOptionalBoolean("permission.enabled") ?? false; + this.authEnabled = + options.config.getOptionalBoolean("openchoreo.features.auth.enabled") ?? + true; + } + + async authorize(request: { + permission: { name: string }; + resourceRef?: string; + }) { + if (!this.enabled) return { result: AuthorizeResult.ALLOW }; + + const permissionApiUrl = await this.discovery.getBaseUrl("permission"); + const { token: backstageToken } = await this.identityApi.getCredentials(); + + let idpToken: string | undefined; + if (this.authEnabled) { + try { + idpToken = await this.oauthApi.getAccessToken(); + } catch { + // No IDP token — proceed with just the Backstage token. + } + } + + const headers: Record = { + "Content-Type": "application/json", + }; + if (backstageToken) headers.Authorization = `Bearer ${backstageToken}`; + if (idpToken) headers[OPENCHOREO_TOKEN_HEADER] = idpToken; + + const response = await fetch(`${permissionApiUrl}/authorize`, { + method: "POST", + headers, + body: JSON.stringify({ + items: [{ id: crypto.randomUUID(), ...request }], + }), + }); + + if (!response.ok) { + throw new Error(`Permission request failed: ${response.statusText}`); + } + + const data = await response.json(); + return data.items[0]; + } +} + +function DynamicSignInPage(props: any) { + const configApi = useApi(configApiRef); + const authEnabled = + configApi.getOptionalBoolean("openchoreo.features.auth.enabled") ?? true; + + if (!authEnabled) { + return ; + } + + return ( + + ); +} + +export const customAppModule = createFrontendModule({ + pluginId: "app", + extensions: [ + SignInPageBlueprint.make({ + params: { + loader: async () => DynamicSignInPage, + }, + }), + ApiBlueprint.make({ + name: "openchoreo-auth", + params: (defineParams) => + defineParams({ + api: openChoreoAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + configApi: configApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi, configApi }) => + OAuth2.create({ + discoveryApi, + oauthRequestApi, + configApi, + provider: { + id: "openchoreo-auth", + title: "OpenChoreo", + icon: () => null, + }, + environment: configApi.getOptionalString("auth.environment"), + defaultScopes: ["openid", "profile", "email"], + }), + }), + }), + ApiBlueprint.make({ + name: "fetch-api", + params: (defineParams) => + defineParams({ + api: fetchApiRef, + deps: { + identityApi: identityApiRef, + oauthApi: openChoreoAuthApiRef, + configApi: configApiRef, + }, + factory: ({ identityApi, oauthApi, configApi }) => + new OpenChoreoFetchApi(identityApi, oauthApi, configApi), + }), + }), + ApiBlueprint.make({ + name: "permission-api", + params: (defineParams) => + defineParams({ + api: permissionApiRef, + deps: { + configApi: configApiRef, + discoveryApi: discoveryApiRef, + identityApi: identityApiRef, + oauthApi: openChoreoAuthApiRef, + }, + factory: ({ configApi, discoveryApi, identityApi, oauthApi }) => + new OpenChoreoPermissionApi({ + config: configApi, + discovery: discoveryApi, + identity: identityApi, + oauthApi, + }) as any, + }), + }), + ], +}); +``` + +:::warning Backend and frontend auth flags must agree + +`openchoreo.features.auth.enabled` is read in both places (4.3.2 here and 4.2 on the backend). If the backend module sees it as `true` but `DynamicSignInPage` falls through to guest, the OpenChoreo authz API will reject the guest token. Set it once in `app-config` and let both sides read it. + +::: + +#### 4.3.3 Entity-page tabs — already done {#entity-tabs-auto} + +Under NFS, every Core OpenChoreo tab is contributed by `openchoreoPluginAlpha` as an `EntityContentBlueprint` extension. You do not need to edit `EntityPage.tsx` (the NFS scaffold does not even create one). + +After [Section 4.5 — Verify](#45-verify) you should see: + +- **Domain** pages: `OVERVIEW`, `TECHDOCS`, `DEFINITION`. +- **System** pages: `OVERVIEW`, `TECHDOCS`, `DEFINITION`, `CELL DIAGRAM` — plus auto-mounted overview cards (Project Contents, Deployment Pipeline, etc.). +- **Component** pages: `OVERVIEW`, `TECHDOCS`, `APIS`, `DEFINITION`, `DEPLOY` — plus the Deployments widget on Overview. + +If you need to override where a tab appears or hide one for a specific kind, see [Entity views — customizing under NFS](./entity-views.mdx#nfs-customization). + +### 4.4 Configure `app-config` {#configure-app-config} + +Add an `openchoreo` block to your `app-config.yaml` (or `app-config.local.yaml` for development). + +:::warning Feature flags must mirror the OpenChoreo cluster + +`openchoreo.features.auth.enabled` and `openchoreo.features.authz.enabled` are **not** independent installer defaults. They must match how the OpenChoreo cluster your Backstage instance is talking to was deployed: + +| Cluster runs with… | Set in Backstage | +| ------------------------------------------ | --------------------------------------------- | +| auth + authz both **off** (local dev mode) | `auth.enabled: false`, `authz.enabled: false` | +| auth + authz both **on** (production mode) | `auth.enabled: true`, `authz.enabled: true` | + +The in-tree OpenChoreo portal hides this knob because the Helm chart configures both halves in lockstep. External Backstage hosts installing the published `@openchoreo/*` plugins bypass the chart and must align by hand. Mismatch produces failure modes covered in [Troubleshooting](./troubleshooting.mdx): the catalog provider 401s if auth disagrees, and tabs render "No permissions" if authz disagrees. + +Check your cluster: look at the `features` block in the OpenChoreo helm values, or ask whoever deployed it. + +::: + +```yaml title="app-config.local.yaml" +auth: + environment: development + providers: + openchoreo-auth: + development: + clientId: ${OPENCHOREO_AUTH_CLIENT_ID} + clientSecret: ${OPENCHOREO_AUTH_CLIENT_SECRET} + # Set the OAuth2 endpoints explicitly. `metadataUrl` (OIDC discovery) + # is *not* used because the default OpenChoreo IDP (ThunderID) does not + # expose a reliable /.well-known/openid-configuration endpoint on k3d + # — uncomment it only if your IDP advertises one. + # metadataUrl: ${OPENCHOREO_AUTH_METADATA_URL} + authorizationUrl: ${OPENCHOREO_AUTH_AUTHORIZATION_URL} + tokenUrl: ${OPENCHOREO_AUTH_TOKEN_URL} + scope: "openid profile email" + guest: + dangerouslyAllowOutsideDevelopment: true + +openchoreo: + baseUrl: ${OPENCHOREO_API_URL} # e.g. http://api.openchoreo.localhost:8080/api/v1 + + # OAuth2 client credentials used by the catalog provider for + # service-to-service auth (client_credentials flow). Required even when + # features.auth.enabled is false, because the catalog provider still needs + # to fetch namespaces/projects/components from the OpenChoreo API. + auth: + clientId: ${OPENCHOREO_CLIENT_ID} + clientSecret: ${OPENCHOREO_CLIENT_SECRET} + tokenUrl: ${OPENCHOREO_TOKEN_URL} + + features: + # MIRROR THE CLUSTER (see warning above). Backend and frontend both read + # these — they must agree across the whole stack. + auth: + enabled: true + authz: + enabled: true + + defaultOwner: openchoreo-users + schedule: + frequency: 30 # seconds between catalog provider runs + timeout: 120 # seconds for catalog provider timeout + +permission: + enabled: true # required for the OpenChoreo permission policy to run + +# The catalog must accept Domain entities from the OpenChoreo provider. +catalog: + rules: + - allow: [Component, System, Domain, API, Resource, Location, Group, User] +``` + +#### Local k3d quickstart {#k3d-quickstart} + +OpenChoreo's k3d helm install seeds known credentials. Skip the `${VAR}` placeholders and hardcode these values to get sign-in working without touching env vars: + +```yaml title="app-config.local.yaml (k3d-only)" +auth: + environment: development + providers: + openchoreo-auth: + development: + clientId: openchoreo-backstage-client + clientSecret: backstage-portal-secret + authorizationUrl: http://thunder.openchoreo.localhost:8080/oauth2/authorize + tokenUrl: http://thunder.openchoreo.localhost:8080/oauth2/token + scope: "openid profile email" + +openchoreo: + baseUrl: http://api.openchoreo.localhost:8080/api/v1 + auth: + clientId: openchoreo-backstage-client + clientSecret: backstage-portal-secret + tokenUrl: http://thunder.openchoreo.localhost:8080/oauth2/token +``` + +These are **k3d dev cluster seed values, not real secrets** — never use them against a production OpenChoreo install. For deployed clusters see [Identity configuration](../identity-configuration.mdx). + +### 4.5 Verify + +```bash +yarn start +``` + +Expected: + +1. Backend logs show `Plugin initialization complete` for `openchoreo`, `catalog`, `permission`, `auth`. +2. After ~30s: `Successfully processed N entities (X domains, Y systems, Z components, ...)`. +3. Browser → `http://localhost:3000` → sign-in page shows "Sign in using OpenChoreo." Click through and land in the catalog. +4. `http://localhost:3000/catalog?filters[kind]=domain` → see your OpenChoreo namespaces. +5. Click into any project (`kind=system`) → **CELL DIAGRAM** and **DEFINITION** tabs are present and render real data. +6. Click into any component → **DEPLOY** and **DEFINITION** tabs are present and render real data. + +If you get a 401 on tab data fetches, your `customAppModule`'s `ApiBlueprint` for `fetchApiRef` isn't being registered — check that `customAppModule` is in the `features: [...]` array in `App.tsx`. If you get "No permissions" on Deploy, same check for the `permissionApiRef` `ApiBlueprint`. See [Troubleshooting](./troubleshooting.mdx) for the full failure-mode index. + +--- + +## 5. Add Observability tabs (optional) + +Adds **Logs, Events, Metrics, Alerts, Wirelogs** to Component pages and **Logs, Traces, Incidents, RCA Reports, Cost Analysis** to System pages. Built on top of Core. + +**Prerequisites:** Section 4 (Core) complete and verified. + +### 5.1 Install packages + +```bash +yarn workspace app add @openchoreo/backstage-plugin-openchoreo-observability@^1.2.0 +yarn workspace backend add @openchoreo/backstage-plugin-openchoreo-observability-backend@^1.2.0 +``` + +### 5.2 Wire the backend + +Append to `packages/backend/src/index.ts`: + +```ts +backend.add( + import("@openchoreo/backstage-plugin-openchoreo-observability-backend"), +); +``` + +### 5.3 Wire the frontend + +Append the observability Alpha feature to `createApp({ features: [...] })`: + +```tsx title="packages/app/src/App.tsx" +import openchoreoObservabilityPluginAlpha from "@openchoreo/backstage-plugin-openchoreo-observability/alpha"; + +export default createApp({ + features: [ + catalogPlugin, + openchoreoPluginAlpha, + openchoreoObservabilityPluginAlpha, // <-- add + navModule, + customAppModule, + ], +}); +``` + +**No `EntityPage.tsx` edits.** Every observability tab auto-mounts on the correct entity kind. + +### 5.4 Configure + +Append to the `openchoreo.features` block in `app-config.local.yaml`: + +```yaml +openchoreo: + features: + observability: + enabled: true +``` + +### 5.5 Verify + +Restart `yarn start`. Open any Component → the **LOGS**, **EVENTS**, **METRICS**, **ALERTS**, **WIRELOGS** tabs appear. Open any System → **LOGS**, **TRACES**, **INCIDENTS**, **RCA REPORTS**, **COST ANALYSIS** tabs appear. If a tab renders an empty state, the backend reached OpenChoreo but no data is available yet for that scope. If a tab errors, see [Troubleshooting](./troubleshooting.mdx). + +--- + +## 6. Add CI/Build tab (optional) + +Adds a **Build** tab to Component pages, showing workflow runs and a parameter-form trigger. Built on top of Core. + +**Prerequisites:** Section 4 (Core) complete and verified. + +### 6.1 Install packages + +```bash +yarn workspace app add @openchoreo/backstage-plugin-openchoreo-ci@^1.2.0 +yarn workspace backend add @openchoreo/backstage-plugin-openchoreo-ci-backend@^1.2.0 +``` + +### 6.2 Wire the backend + +Append to `packages/backend/src/index.ts`: + +```ts +backend.add(import("@openchoreo/backstage-plugin-openchoreo-ci-backend")); +``` + +### 6.3 Wire the frontend + +Append the CI Alpha feature to `createApp({ features: [...] })`: + +```tsx title="packages/app/src/App.tsx" +import openchoreoCiPluginAlpha from "@openchoreo/backstage-plugin-openchoreo-ci/alpha"; + +export default createApp({ + features: [ + catalogPlugin, + openchoreoPluginAlpha, + openchoreoCiPluginAlpha, // <-- add + navModule, + customAppModule, + ], +}); +``` + +### 6.4 Configure + +Append to the `openchoreo.features` block: + +```yaml +openchoreo: + features: + workflows: + enabled: true +``` + +### 6.5 Verify + +Restart `yarn start`. Open any Component → the **BUILD** tab appears. It lists past workflow runs and (depending on permissions) offers a "Trigger build" form. + +--- + +## 7. Add standalone Workflows page (optional) + +Adds an org-level `/workflows` page for generic (non-component-scoped) workflow templates and runs, plus a **Runs** tab on `Workflow` and `ClusterWorkflow` entities. Built on top of Core. + +**Prerequisites:** Section 4 (Core) complete and verified. + +### 7.1 Install packages + +```bash +yarn workspace app add @openchoreo/backstage-plugin-openchoreo-workflows@^1.2.0 +yarn workspace backend add @openchoreo/backstage-plugin-openchoreo-workflows-backend@^1.2.0 +``` + +### 7.2 Wire the backend + +Append to `packages/backend/src/index.ts`: + +```ts +backend.add( + import("@openchoreo/backstage-plugin-openchoreo-workflows-backend"), +); +``` + +### 7.3 Wire the frontend + +Append the workflows Alpha feature: + +```tsx title="packages/app/src/App.tsx" +import openchoreoWorkflowsPluginAlpha from "@openchoreo/backstage-plugin-openchoreo-workflows/alpha"; + +export default createApp({ + features: [ + catalogPlugin, + openchoreoPluginAlpha, + openchoreoWorkflowsPluginAlpha, // <-- add + navModule, + customAppModule, + ], +}); +``` + +The plugin contributes the standalone `/workflows` page as a `PageBlueprint` — no `` mount needed. + +Optionally add a sidebar entry in `packages/app/src/modules/nav/Sidebar.tsx` so users can navigate to it. + +### 7.4 Verify + +Restart `yarn start`. Navigate to `http://localhost:3000/workflows` → see the org-level workflow list. + +--- + +## 8. Troubleshooting + +If anything misbehaves at any step, see [Troubleshooting](./troubleshooting.mdx) for the full failure-mode index, indexed by exact error message. + +--- + +## 9. Legacy frontend system (fallback) {#9-legacy-frontend-system-fallback} + +If your Backstage host is scaffolded with `--legacy` (or you have heavy `EntityPage.tsx` customization you want to keep), follow the legacy wiring below instead of Sections 4.3 through 7. Sections 1–3 and 4.1–4.2 (prereqs, resolutions, GitHub Packages auth, package install, backend wiring) are identical. + +The legacy install registers each plugin's default export via `createApp({ apis, plugins, bindRoutes })` and manually mounts every entity tab into `components/catalog/EntityPage.tsx`. + +:::warning Choose one path + +Do NOT mix the two. If you import `openchoreoPluginAlpha` from `/alpha` _and_ also mount `` in `EntityPage.tsx`, you will see duplicate tabs (or the wrong tab will win depending on extension load order). + +::: + +### 9.1 Wire the frontend (legacy) + +In `packages/app/src/App.tsx`: + +```tsx title="packages/app/src/App.tsx (legacy host)" +import { choreoPlugin } from '@openchoreo/backstage-plugin'; + +const app = createApp({ + apis, + plugins: [choreoPlugin], // <-- add; opt-in sections will append more + bindRoutes({ bind }) { ... }, +}); +``` + +Wire OpenChoreo sign-in by creating `packages/app/src/apis/authRefs.ts`: + +```ts title="packages/app/src/apis/authRefs.ts" +import { + ApiRef, + BackstageIdentityApi, + createApiRef, + OAuthApi, + ProfileInfoApi, + SessionApi, +} from "@backstage/core-plugin-api"; + +export const openChoreoAuthApiRef: ApiRef< + OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi +> = createApiRef({ + id: "auth.openchoreo-auth", +}); +``` + +Register the OAuth2 factory in `packages/app/src/apis.ts`: + +```tsx title="packages/app/src/apis.ts" +import { OAuth2 } from "@backstage/core-app-api"; +import { openChoreoAuthApiRef } from "./apis/authRefs"; + +export const apis: AnyApiFactory[] = [ + // ... your existing factories ... + createApiFactory({ + api: openChoreoAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + configApi: configApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi, configApi }) => + OAuth2.create({ + discoveryApi, + oauthRequestApi, + configApi, + provider: { + id: "openchoreo-auth", + title: "OpenChoreo", + icon: () => null, + }, + environment: configApi.getOptionalString("auth.environment"), + defaultScopes: ["openid", "profile", "email"], + }), + }), +]; +``` + +The `OpenChoreoFetchApi` and `OpenChoreoPermissionApi` classes from [Section 4.3.2](#custom-app-module) above are registered as legacy `createApiFactory` entries in `apis.ts` (same shape as upstream `apiFactories`). Pass `components: { SignInPage: DynamicSignInPage }` to `createApp` for the sign-in slot. + +### 9.2 Mount entity tabs + +Add the Core tab components to `packages/app/src/components/catalog/EntityPage.tsx`: + +```tsx title="packages/app/src/components/catalog/EntityPage.tsx" +import { + Environments, + CellDiagram, + ResourceDefinitionTab, +} from '@openchoreo/backstage-plugin'; + +// componentEntityPage / defaultEntityPage: + + + + + + + +// systemPage: + + + + + + + +// domainPage: + + + +``` + +For the legacy opt-in tab packs (Observability / CI / Workflows), see [Entity views — Legacy wiring example](./entity-views.mdx#legacy-wiring). The wiring is the same as the 1.1.x install guide — `plugins: [..., openchoreoObservabilityPlugin]` plus the per-tab `` blocks. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2.mdx new file mode 100644 index 00000000..178bb127 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2.mdx @@ -0,0 +1,138 @@ +--- +title: Migrating from 1.1.x to 1.2.x +description: Upgrade an existing OpenChoreo Backstage host from the 1.1.x plugin line to 1.2.x. +sidebar_position: 2 +--- + +# Migrating from 1.1.x to 1.2.x + +The 1.2.x line of `@openchoreo/backstage-plugin*` brings two coordinated changes for adopters who installed the plugins into their own Backstage host: + +1. **Backstage `1.51.0`** is the new minimum. 1.1.x targeted `1.43.3`; every transitive `@backstage/*` peer-dep range moves to the 1.51 line, and `@backstage/cli` minimum becomes `^0.36.2`. +2. **New Frontend System (NFS) install path** — each plugin now ships an `/alpha` entry point that exports a `createFrontendPlugin` instance. Adopters can drop `--legacy` from `@backstage/create-app`, install via `createApp({ features: [...] })`, and get every OpenChoreo entity tab and overview card mounted automatically — no `EntityPage.tsx` edits. + +The default (legacy) plugin exports keep working unchanged. Existing 1.1.x adopters on the legacy frontend system can take just the Backstage bump and keep their `EntityPage.tsx`; opting into NFS is recommended but not required. + +:::tip Tracking the upcoming 1.2.0 release + +The upgrade commands on this page reference `@openchoreo/@^1.2.0`, which will be the GA dist-tag of the 1.2.0 release. While `1.2.0` is still under active development, swap `@^1.2.0` for `@next` in every command below to bump to the latest prerelease today. Once `1.2.0` GA is announced, switch back to `@^1.2.0` to pin to the stable release. + +::: + +## Step 1 — Bump Backstage to 1.51 + +In your workspace root, run: + +```bash +yarn backstage-cli versions:bump --release 1.51.0 +``` + +This rewrites every `@backstage/*` caret range in your `package.json` files to the 1.51 line. Then replace the heavy `resolutions` block (carried over from the 1.1.x install guide) with the much smaller 1.2.x block. In your root `package.json`: + +```json title="package.json" +{ + "resolutions": { + "@types/react": "^18", + "@types/react-dom": "^18", + "@mui/material": "^5.18.0" + } +} +``` + +The `@mui/material` pin is new — it fixes a `material-ui-popup-state` transitive resolution issue that surfaces with the newer scaffold. Without it Rspack fails to compile with `Module not found: Can't resolve '@mui/material/version'`. + +Then: + +```bash +rm -rf node_modules yarn.lock +yarn install +``` + +If anything in `@backstage/*` peer-deps fails to resolve after this, fall back to the [compatibility matrix](./compatibility-matrix.mdx) for the exact pinned set. + +## Step 2 — Bump OpenChoreo plugins to 1.2.0 + +```bash +yarn workspace app upgrade \ + @openchoreo/backstage-design-system@^1.2.0 \ + @openchoreo/backstage-plugin-common@^1.2.0 \ + @openchoreo/backstage-plugin-react@^1.2.0 \ + @openchoreo/backstage-plugin@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-ci@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-observability@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-workflows@^1.2.0 + +yarn workspace backend upgrade \ + @openchoreo/openchoreo-client-node@^1.2.0 \ + @openchoreo/openchoreo-auth@^1.2.0 \ + @openchoreo/backstage-plugin-common@^1.2.0 \ + @openchoreo/backstage-plugin-catalog-backend-module@^1.2.0 \ + @openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy@^1.2.0 \ + @openchoreo/backstage-plugin-scaffolder-backend-module@^1.2.0 \ + @openchoreo/backstage-plugin-backend@^1.2.0 \ + @openchoreo/backstage-plugin-auth-backend-module-openchoreo-auth@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-ci-backend@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-observability-backend@^1.2.0 \ + @openchoreo/backstage-plugin-openchoreo-workflows-backend@^1.2.0 +``` + +(Drop the optional packs you don't have installed.) + +## Step 3 — Choose an install path + +### Option A: Stay on the legacy frontend system + +If you have heavy `EntityPage.tsx` customization you want to keep, or you're not ready to move to NFS, you're effectively done. The default plugin exports from `@openchoreo/*@^1.2.0` are API-compatible with `1.1.x` — same `createPlugin` instances, same component exports (`Environments`, `CellDiagram`, `ResourceDefinitionTab`, `Workflows`, `ObservabilityRuntimeLogs`, etc.). Your existing `App.tsx` `plugins: [...]` array and `EntityPage.tsx` mounts continue to work. + +Restart `yarn start` and verify the catalog still syncs and the entity tabs still render. + +### Option B: Switch to NFS (recommended) + +NFS gives you simpler wiring (no `EntityPage.tsx` mounts, no per-tab imports) and is the path the install guide will continue to maintain. To switch: + +1. **Re-scaffold or migrate `App.tsx`.** The legacy `App.tsx` builds `createApp({ apis, plugins, bindRoutes })` and wraps `` in ``. NFS uses `createApp({ features: [...] })` with feature contributions handling routing. Easiest path: scaffold a fresh `npx @backstage/create-app@latest` host alongside your existing one, port your `app-config.yaml`, then follow [install guide Section 4](./installing-into-existing-backstage.mdx#core) to wire OpenChoreo features into the new host. Use the legacy host as a reference for any custom routes / sidebar items you need to recreate as NFS modules. + +2. **Move `apis.ts` factories into a `customAppModule`.** Each `createApiFactory({ api, deps, factory })` becomes an `ApiBlueprint.make({ params: defineParams => defineParams({ api, deps, factory }) })` inside a `createFrontendModule({ pluginId: 'app', extensions: [...] })`. The shape is in [install guide Section 4.3.2](./installing-into-existing-backstage.mdx#custom-app-module). + +3. **Delete the per-tab `` mounts from `EntityPage.tsx`.** Once `openchoreoPluginAlpha` (and the opt-in packs' Alpha features) are in `createApp({ features: [...] })`, every OpenChoreo tab auto-mounts via `EntityContentBlueprint`. Leaving the legacy mounts in produces duplicate tabs. + +4. **Drop the legacy `` for `/workflows`** if you mounted `GenericWorkflowsPage` by hand — under NFS, `openchoreoWorkflowsPluginAlpha` contributes `/workflows` as a `PageBlueprint`. + +5. **Update `.yarnrc.yml`** to add `@openchoreo/*` to `npmPreapprovedPackages` so newly published prereleases install immediately instead of being blocked by the 3-day age gate: + + ```yaml + npmPreapprovedPackages: + - "@backstage/*" + - "@openchoreo/*" + ``` + +## Step 4 — Verify + +```bash +yarn start +``` + +1. Backend logs show `Plugin initialization complete` for `openchoreo`, `catalog`, `permission`, `auth`. No `MODULE_NOT_FOUND` or `serviceRef{alpha.core.metrics}` errors. +2. After ~30s: `Successfully processed N entities (X domains, Y systems, Z components, ...)`. +3. Browser → catalog renders, sign-in works, you can click into a Component and see the **DEPLOY** tab render real deployment data. +4. Browser DevTools console: no "extension not discovered" or "missing api factory" warnings at boot. Under NFS, the `Source` tab of every loaded extension should be `loaded`. + +If you see duplicated tabs (e.g. two `DEPLOY` tabs), you're on the NFS path but left legacy `EntityPage.tsx` mounts in place — see [Troubleshooting → NFS: duplicate Core tab](./troubleshooting.mdx#nfs-duplicate-core-tab-two-deploy-tabs-etc). + +## What did NOT change between 1.1.x and 1.2.x + +- The package set — same names, same default exports. Adopters on Option A above keep their `import { Environments } from '@openchoreo/backstage-plugin'` lines unchanged. +- Backend wiring shape — `index.ts` keeps the same `immediateCatalogServiceFactory`, `annotationStoreFactory`, `createIdpTokenHeaderMiddleware`, `OpenChoreoAuthModule`, permission policy, and catalog/scaffolder modules. Only the `@backstage/*` versions move. +- `app-config.yaml` shape — `openchoreo.baseUrl`, `openchoreo.features.*`, `openchoreo.auth.*`, the `permission.enabled` flag, and the catalog rules are all unchanged. +- `OpenChoreoFetchApi` and `OpenChoreoPermissionApi` — still the same classes; 1.2.x does not ship them. Adopters keep them in `apis/` (legacy) or move them into the `customAppModule` (NFS). +- Catalog sync behavior — same `schedule.frequency` / `schedule.timeout` integers, same entity-kind mapping, same client-credentials auth flow. + +## What did change + +- **Backstage minimum** — 1.43.3 → 1.51.0. +- **`@backstage/cli` minimum** — 0.34.3 → 0.36.2. +- **Yarn scaffold version** — `create-app@latest` now produces Yarn 4.13.x with `npmMinimalAgeGate: 3d`. The install guide adds `@openchoreo/*` to `npmPreapprovedPackages`. +- **NFS install path added** — see install guide [Section 4 — Core](./installing-into-existing-backstage.mdx#core). +- **Tab catalog additions** — `Component → EVENTS` and `Component → WIRELOGS` are new tabs in the observability pack. They auto-mount under NFS; for legacy hosts add the corresponding `` mounts (see [entity-views legacy wiring](./entity-views.mdx#legacy-wiring)). +- **Workflows `/alpha` contributes a `/workflows` page** — under NFS the standalone Workflows page mounts via `PageBlueprint`; no manual `` mount needed. +- **Notifications-removal cleanup is no longer required** — the 1.43.3-era `@backstage/plugin-notifications` crash that the 1.1.x install guide Section 8 worked around is fixed in the 1.51 line. If you removed those packages on the old install you can re-add them; if you left them you're fine. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/overview.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/overview.mdx new file mode 100644 index 00000000..3401c7b2 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/overview.mdx @@ -0,0 +1,67 @@ +--- +title: Overview +description: Install OpenChoreo plugins into your existing Backstage app. +sidebar_position: 1 +--- + +# Backstage Plugins for OpenChoreo + +OpenChoreo ships its own Backstage portal preconfigured for the platform. If you already run a Backstage instance and just want to add OpenChoreo capabilities, this guide is for you. + +This is an alternative to forking the [`openchoreo/backstage-plugins`](https://github.com/openchoreo/backstage-plugins) repository. You install a small set of npm packages into your own Backstage workspace and wire them up. + +## What you get + +**Core** (required) — delivered by a single install path: + +| Capability | Details | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Catalog sync** | OpenChoreo namespaces become `Domain` entities, projects become `System` entities, components become `Component` entities, with relations preserved. | +| **OpenChoreo sign-in** | OIDC sign-in against the OpenChoreo IDP. The signed-in user's token flows into entity-page tab calls. Falls through to guest sign-in when your OpenChoreo cluster runs with auth off. | +| **Domain entity views** | **Overview**, **Definition**. | +| **System entity views** | **Overview**, **Definition**, **Cell** (architectural diagram), **Diagram** (catalog graph). | +| **Component entity views** | **Overview**, **Definition**, **Deploy** (per-environment runtime state). | +| **Permission policy** | Composable Backstage permission policy that delegates `openchoreo.*` permissions to the OpenChoreo authorization service and falls back to ALLOW for everything else. | +| **Scaffolder actions** | OpenChoreo-aware actions for use in your own scaffolder templates. | + +**Optional tab packs** — install only the ones you want: + +| Pack | Adds | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `@openchoreo/backstage-plugin-openchoreo-observability` | System tabs: **Logs**, **Traces**, **Incidents**, **RCA Reports**, **Cost Analysis**. Component tabs: **Logs**, **Events**, **Metrics**, **Alerts**, **Wirelogs**. | +| `@openchoreo/backstage-plugin-openchoreo-ci` | Component tab: **Build** (workflow runs + trigger form). | +| `@openchoreo/backstage-plugin-openchoreo-workflows` | Standalone `/workflows` page + **Runs** tab on Workflow/ClusterWorkflow entities. | + +See the [compatibility matrix](./compatibility-matrix.mdx) for the full list of packages. + +## What is not in scope yet + +The following live in `openchoreo/backstage-plugins` but are not packaged for external installation: + +- **External CI integrations** (Jenkins, GitHub Actions, GitLab CI) — third-party plugin wiring that the in-tree portal ships preconfigured. +- **Pre-built scaffolder _templates_** — the scaffolder _backend module_ (which ships actions) is part of Core, but the default templates that consume those actions are still in the upstream repo. To author your own templates that reuse the actions, see [Custom Backstage Scaffolder Templates](../backstage-scaffolder-templates.mdx). + +If you need any of these today, fork the upstream repo or file an issue at [openchoreo/backstage-plugins](https://github.com/openchoreo/backstage-plugins/issues). + +## Compatibility + +OpenChoreo plugins target a specific Backstage release line. See the [compatibility matrix](./compatibility-matrix.mdx) for the tested combinations. Installing into a Backstage app on a different release line may surface dependency-resolution issues; the [troubleshooting](./troubleshooting.mdx) guide lists the common ones and how to pin around them. + +## Install paths + +There are two ways to install OpenChoreo plugins: + +- **New Frontend System (NFS)** — the default for hosts scaffolded with `npx @backstage/create-app@latest`. Plugins are added to `createApp({ features: [...] })`, tabs and overview cards auto-mount, and you do not edit `EntityPage.tsx`. This is the recommended path. +- **Legacy frontend system** — for hosts scaffolded with `--legacy` or with heavy `EntityPage.tsx` customization. See [Section 9 of the install guide](./installing-into-existing-backstage.mdx#9-legacy-frontend-system-fallback) for the legacy wiring. + +If you are upgrading from a plugin version `^1.1.x` install, see the [1.1.x to 1.2.x migration guide](./migration-1.1-to-1.2.mdx). + +## Where to start + +1. [Installing into an existing Backstage app](./installing-into-existing-backstage.mdx) — the canonical step-by-step. Core first; opt-in tab packs follow. +2. [Catalog sync](./catalog-sync.mdx) — what gets synced and how to tune it. +3. [Entity views](./entity-views.mdx) — the full tab matrix and per-tab package mapping. +4. [Permission policy](./permission-policy.mdx) — composing OpenChoreo authorization with your existing policy. +5. [Troubleshooting](./troubleshooting.mdx) — failure-mode index keyed by exact error message. + +To author your own scaffolder templates that reuse the OpenChoreo scaffolder actions, see [Custom Backstage Scaffolder Templates](../backstage-scaffolder-templates.mdx) under Platform Setup. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/permission-policy.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/permission-policy.mdx new file mode 100644 index 00000000..f9413d32 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/permission-policy.mdx @@ -0,0 +1,97 @@ +--- +title: Permission policy +description: Compose the OpenChoreo permission policy with your existing host policy. +sidebar_position: 5 +--- + +# Permission policy + +The **`@openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy`** module installs a Backstage [permission policy](https://backstage.io/docs/permissions/concepts) that consults the OpenChoreo authorization service for `openchoreo.*` permissions. For everything else (catalog read, scaffolder execute, …) it returns ALLOW, so it is **composable** with your existing host policy as long as it is registered as the only top-level policy. + +## Wiring + +The Backstage backend can only have one permission policy active. If your existing `packages/backend/src/index.ts` registers the default allow-all policy: + +```ts +backend.add( + import("@backstage/plugin-permission-backend-module-allow-all-policy"), +); +``` + +Replace it with the OpenChoreo policy: + +```ts +backend.add(import("@backstage/plugin-permission-backend")); +backend.add( + import("@openchoreo/backstage-plugin-permission-backend-module-openchoreo-policy"), +); +``` + +If you have a custom policy already, you can call into the OpenChoreo policy from yours — see the policy's exported helpers in [`plugins/permission-backend-module-openchoreo-policy/src/index.ts`](https://github.com/openchoreo/backstage-plugins/blob/main/plugins/permission-backend-module-openchoreo-policy/src/index.ts). + +## Two operating modes + +Behaviour switches on `openchoreo.features.authz.enabled`. **This flag must mirror the OpenChoreo cluster's deployment state** — it is not an independent installer default: + +| Cluster state | Set in Backstage | Policy behaviour | +| --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| authz off (local dev) | `authz.enabled: false` | Policy short-circuits to ALLOW for every permission. Logs `OpenChoreo permission policy disabled via openchoreo.features.authz.enabled=false. Using allow-all policy.` at startup. | +| authz on (production) | `authz.enabled: true` | Policy queries `${openchoreo.baseUrl}/authz/profile` for the user's capabilities, evaluates `openchoreo.*` permissions against the result, and falls back to ALLOW for non-OpenChoreo permissions. | + +The in-tree OpenChoreo portal hides this knob because the Helm chart configures both halves in lockstep. External Backstage hosts must align by hand. + +## Enabling authz: extra wiring required + +When the cluster runs with authz on, the policy needs the user's IDP token to reach `/authz/profile`. Install the **IDP token middleware** on the root HTTP router. Edit `packages/backend/src/index.ts`: + +```ts +import { rootHttpRouterServiceFactory } from "@backstage/backend-defaults/rootHttpRouter"; +import { createIdpTokenHeaderMiddleware } from "@openchoreo/openchoreo-auth"; + +backend.add( + rootHttpRouterServiceFactory({ + configure: ({ app, applyDefaults, middleware }) => { + app.use(middleware.helmet()); + app.use(middleware.cors()); + app.use(middleware.compression()); + app.use(middleware.logging()); + + // Reads the IDP token from the request and exposes it via + // AsyncLocalStorage so the policy can use it for /authz/profile calls. + app.use(createIdpTokenHeaderMiddleware()); + + applyDefaults(); + }, + }), +); +``` + +You also need the frontend OIDC sign-in provider so the policy receives the user's IDP token. That wiring is part of [Core install Section 4.3.2](./installing-into-existing-backstage.mdx#custom-app-module) — `OpenChoreoAuthModule` on the backend, the `OAuth2` factory and `DynamicSignInPage` on the frontend, plus the `OpenChoreoPermissionApi` `ApiBlueprint` override, without which the IDP token doesn't reach the authorize call at all. + +## Composability semantics + +The policy decision tree: + +1. If the permission name starts with `openchoreo.`: + - If `authz.enabled = false`: **ALLOW**. + - If `authz.enabled = true`: query `/authz/profile`, evaluate, return ALLOW or DENY. +2. If the permission name is one of the OpenChoreo-managed catalog permissions (e.g. `catalog.entity.read` for an OpenChoreo-synced entity): same rules as above. +3. Otherwise (e.g. `scaffolder.task.execute`, `catalog.entity.create`, your-org's custom permissions): **ALLOW**. + +This means your existing Backstage permissions UX (scaffolder gating, catalog write rules, …) is unchanged. + +## Verification + +The simplest end-to-end smoke test runs the policy in AllowAll mode (matching a cluster deployed with `authz: false`). With the backend running: + +```bash +# Acquire a guest token (development only). +TOKEN=$(curl -sS -X POST http://localhost:7007/api/auth/guest/refresh \ + | jq -r '.backstageIdentity.token') + +# Authorize a no-op OpenChoreo permission. Expect "ALLOW". +curl -sS -X POST http://localhost:7007/api/permission/authorize \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"items":[{"id":"x","permission":{"type":"basic","name":"openchoreo.foo.read"}}]}' | jq +``` diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/troubleshooting.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/troubleshooting.mdx new file mode 100644 index 00000000..dd60ce64 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-plugins/troubleshooting.mdx @@ -0,0 +1,327 @@ +--- +title: Troubleshooting +description: Common installation issues and how to diagnose them. +sidebar_position: 6 +--- + +# Troubleshooting + +Issues you will most likely run into when installing the OpenChoreo plugins into an existing Backstage app, drawn from observed failures. + +## NFS: tab missing on entity page + +**Symptom:** you installed an opt-in pack (e.g. `@openchoreo/backstage-plugin-openchoreo-observability`) and the tab does not appear on the entity page after restart. + +**Cause:** the plugin's `Alpha` feature is not in `createApp({ features: [...] })`. + +**Fix:** add the import and append to the features array in `packages/app/src/App.tsx`: + +```tsx +import openchoreoObservabilityPluginAlpha from "@openchoreo/backstage-plugin-openchoreo-observability/alpha"; + +export default createApp({ + features: [ + catalogPlugin, + openchoreoPluginAlpha, + openchoreoObservabilityPluginAlpha, // <-- add + navModule, + customAppModule, + ], +}); +``` + +## NFS: 401 on tab data fetches / "No permissions" on Deploy + +**Cause:** the `OpenChoreoFetchApi` / `OpenChoreoPermissionApi` overrides aren't being registered. Either `customAppModule` is missing from `createApp({ features: [...] })`, or the `ApiBlueprint` extensions inside it didn't get loaded (look for an extension-disabled warning in the browser console). + +**Fix:** confirm `customAppModule` is the _last_ entry in `features: [...]` (NFS resolves api factories last-write-wins, so overrides must come after the plugins they override), and that both `ApiBlueprint.make` calls inside the module use `params: defineParams => defineParams({...})` (not `params: { factory: ... }` — that's the wrong shape and silently drops the extension). + +## NFS: duplicate Core tab (two `DEPLOY` tabs, etc.) + +**Cause:** you imported `openchoreoPluginAlpha` from `/alpha` (which auto-mounts the tab via `EntityContentBlueprint`) **and** left a legacy `` in `EntityPage.tsx`. + +**Fix:** pick one path. For NFS hosts, delete the legacy `` mounts from `EntityPage.tsx` (or delete the file entirely if you have no other host-custom tabs). For legacy hosts, do NOT add the `/alpha` features — install the plugin via its default export only. See [install guide Section 9](./installing-into-existing-backstage.mdx#9-legacy-frontend-system-fallback). + +## Rspack fails: `Can't resolve '@mui/material/version'` + +``` +ERROR in ../../node_modules/material-ui-popup-state/HoverPopover.mjs 5:1-46 + × Module not found: Can't resolve '@mui/material/version' in + '/.../node_modules/material-ui-popup-state' +``` + +**Cause:** `material-ui-popup-state` requires `@mui/material@>=5 <10`. Without a resolution, yarn satisfies it with a nested copy of `@mui/material@5.13.x` that predates the `/version` subpath. + +**Fix:** pin `@mui/material` in your workspace root `package.json`: + +```json +{ + "resolutions": { + "@mui/material": "^5.18.0" + } +} +``` + +Then `rm -rf node_modules yarn.lock && yarn install`. + +## Yarn age gate blocks fresh `@openchoreo/*` releases + +``` +YN0090: @openchoreo/backstage-plugin@npm:1.2.0 is younger than the +configured minimum age (3d) +``` + +**Cause:** the NFS `create-app` scaffold's `.yarnrc.yml` sets `npmMinimalAgeGate: 3d` to protect against supply-chain attacks. Fresh `@openchoreo/*` prereleases sometimes land within that window. + +**Fix:** add `@openchoreo/*` to the pre-approved list in `.yarnrc.yml`: + +```yaml +npmPreapprovedPackages: + - "@backstage/*" + - "@openchoreo/*" +``` + +## Missing `alpha.core.metrics` service ref + +``` +Service or extension point dependencies of plugin 'catalog' are missing +for the following ref(s): serviceRef{alpha.core.metrics} +``` + +**Cause:** your host app resolved a newer minor of `@backstage/plugin-catalog-backend` than the OpenChoreo plugins were tested against. Newer versions depend on alpha services (`alpha.core.metrics`, `catalogPermissionExtensionPoint`) that the older `backend-defaults` does not provide. + +**Fix:** pin every `@backstage/*` package to the version line tested by OpenChoreo. The full set is in the [compatibility matrix](./compatibility-matrix.mdx). Add the listed `resolutions` to your workspace root `package.json`, then: + +```bash +rm -rf node_modules yarn.lock +yarn install +``` + +## Missing `catalog.permission` extension point + +``` +Service or extension point dependencies of module 'openchoreo' for plugin +'catalog' are missing for the following ref(s): extensionPoint{catalog.permission} +``` + +Same root cause as above. The `catalogPermissionExtensionPoint` is registered by `@backstage/plugin-catalog-backend@3.1.x`; in `3.6.x+` it moved out of the main package. Pin to `3.1.1`. + +## `AnnotationStore is not available` + +``` +Failed to instantiate service 'openchoreo.annotation-store' because the +default factory loader threw an error, Error: AnnotationStore is not +available. Make sure the catalog-backend-module-openchoreo is installed. +``` + +**Cause:** the catalog-backend-module is installed but the **service factories** are not registered. The factories are required by both `catalog-backend-module-openchoreo` (for processors) and `openchoreo-backend` (for the API surface). + +**Fix:** add the explicit `backend.add(...)` lines in `packages/backend/src/index.ts`: + +```ts +import { + immediateCatalogServiceFactory, + annotationStoreFactory, +} from "@openchoreo/backstage-plugin-catalog-backend-module"; + +backend.add(immediateCatalogServiceFactory); +backend.add(annotationStoreFactory); +``` + +These must be added **before** `backend.start()`. + +## `openchoreo.schedule.frequency` config rejected as object + +``` +Invalid type in config for key 'openchoreo.schedule.frequency' in +'app-config.local.yaml', got object, wanted number +``` + +**Cause:** the catalog provider expects `frequency` and `timeout` to be plain integers (seconds), not the Backstage `HumanDuration` shape. + +**Fix:** + +```yaml +openchoreo: + schedule: + frequency: 30 # ✅ correct + timeout: 120 # ✅ correct + # frequency: { seconds: 30 } ❌ wrong — produces this error +``` + +## Catalog sync fails with 401 from OpenChoreo + +``` +Failed to fetch namespaces: 401 Unauthorized - missing or invalid +authentication token +``` + +**Cause:** the catalog provider tried to call the OpenChoreo API without a token. This happens when **either** `openchoreo.features.auth.enabled` is `false` **or** the OAuth `clientId` / `clientSecret` / `tokenUrl` are missing or wrong. + +**Fix:** keep `auth.enabled: true` and confirm the credentials work: + +```bash +curl -X POST -d 'grant_type=client_credentials' \ + -d "client_id=${OPENCHOREO_CLIENT_ID}" \ + -d "client_secret=${OPENCHOREO_CLIENT_SECRET}" \ + ${OPENCHOREO_TOKEN_URL} +``` + +A successful response returns a JSON object with `access_token`. If you see `invalid_client`, the credentials are wrong; if the request times out, the IDP is not reachable. + +## Yarn `portal:` link conflicts on `@backstage/*` + +``` +Cannot link @openchoreo/backstage-plugin-react ... dependency +@backstage/catalog-model conflicts with parent dependency +``` + +**Cause:** you tried to use Yarn `portal:` to point at a sibling `openchoreo/backstage-plugins` checkout. Portal preserves each portal'd workspace's own `node_modules`, which produces duplicate `@backstage/*` package instances and broken service-ref identity. + +**Fix:** install from GitHub Packages instead of using `portal:`. See the [installation guide](./installing-into-existing-backstage.mdx#core) — `yarn add` against the published `@openchoreo/*` packages lets yarn dedupe `@backstage/*` against your host app's tree. + +## React duplicate-instance error / "Invalid hook call" + +**Cause:** two copies of `react` in the dependency tree, usually because a portal'd or `link:`-ed plugin pulled its own `react` instead of using the host's. + +**Fix:** add to your workspace root `resolutions`: + +```json +"resolutions": { + "react": "18.3.1", + "react-dom": "18.3.1", + "@types/react": "18.3.26", + "@types/react-dom": "18.3.7" +} +``` + +## `csstype` type errors during `yarn tsc` + +``` +Property.AlignmentBaseline ... is not assignable +``` + +**Cause:** version drift on `csstype` between the OpenChoreo plugin tree and your app's tree. + +**Fix:** + +```json +"resolutions": { + "csstype": "3.1.3" +} +``` + +## Backend module startup fails with `Cannot read properties of undefined (reading 'id')` + +``` +Module 'openchoreo' for plugin 'catalog' startup failed; +caused by TypeError: Cannot read properties of undefined (reading 'id') +``` + +**Cause:** one of the modules registered with `backend.add(...)` declares a dependency on a service ref that resolved to `undefined`. Usually a version skew where one of `@backstage/plugin-scaffolder-backend-module-notifications` or similar is pulled at a version newer than your Backstage release line. + +**Fix:** pin all transitive `@backstage/*` resolutions to the tested versions in the [compatibility matrix](./compatibility-matrix.mdx). If you do not need a specific module (e.g. `scaffolder-backend-module-notifications`), remove its `backend.add(...)` line and `yarn remove` it. + +## Port 7007 already in use + +``` +EADDRINUSE: address already in use :::7007 +``` + +A previous failed boot left a node process on port 7007. Kill it: + +```bash +lsof -i :7007 -i :3000 +kill +``` + +## Catalog provider runs but no entities show up + +Check `catalog.rules.allow` includes `Domain` and any other custom kinds the OpenChoreo provider produces. The catalog silently drops disallowed kinds. + +```yaml +catalog: + rules: + - allow: [Component, System, Domain, API, Resource, Location, Group, User] +``` + +## `NotificationsSidebarItem` crashes the app at boot + +``` +Uncaught TypeError: Cannot read properties of undefined (reading 'id') + in +``` + +**Cause:** the create-app template installs `@backstage/plugin-notifications`, which in versions newer than the 1.43.3 release line expects exports (`toastApiRef`, `Tag`, `Dialog`, `DialogHeader`, ...) that the pinned `@backstage/ui` and `@backstage/frontend-plugin-api` do not provide. + +**Fix (legacy 1.43-era hosts only):** remove `NotificationsSidebarItem` from `packages/app/src/components/Root/Root.tsx` and `` from `packages/app/src/App.tsx`. The 1.51 NFS scaffold does not exhibit this crash — if you are on `^1.2.x` of the OpenChoreo plugins against Backstage 1.51, you can leave the notifications wiring in place. + +## `choreoPlugin` API factories not registered on entity tabs + +``` +NotImplementedError: No implementation available for +apiRef{plugin.openchoreo.client} +``` + +**Cause:** Backstage's plugin auto-discovery walks the JSX tree of the rendered app to find plugins. The `Environments` and `CellDiagram` components are mounted inside `EntitySwitch.Case` branches that only render once an entity is loaded, so they are not in the static tree at app boot. Backstage never adds `choreoPlugin` to its plugin set, and its `apis: [...]` factories are never registered. + +**Fix:** register `choreoPlugin` explicitly in `packages/app/src/App.tsx`: + +```tsx +import { choreoPlugin } from "@openchoreo/backstage-plugin"; + +const app = createApp({ + apis, + plugins: [choreoPlugin], + // ... +}); +``` + +## Observability API factory missing on Environments tab + +``` +NotImplementedError: No implementation available for +apiRef{plugin.openchoreo-observability.service} +``` + +**Cause:** the Deploy tab tries to render incident chips but no factory is registered for the observability API. The Core plugin resolves this API lazily via `useApiHolder().get()`, so the tab itself renders fine without observability — but if something else in your app force-references the API, or you're on a build that uses `useApi()`, you get this throw. + +**Fix:** install the observability tab pack as documented in the [installation guide → Observability tabs](./installing-into-existing-backstage.mdx#5-add-observability-tabs-optional). It registers the API factory and feeds real incident data into the same UI. + +## `openchoreo-auth` provider misconfigured + +``` +NotFoundError: Auth provider registered for 'openchoreo-auth' is misconfigured. +This could mean the configs under auth.providers.openchoreo-auth are missing +or the environment variables used are not defined. +``` + +**Cause:** one or more of the `OPENCHOREO_AUTH_*` env vars referenced by `auth.providers.openchoreo-auth.development.*` in your `app-config.local.yaml` is undefined. Backstage's config loader expands `${VAR}` placeholders at startup; if a var is missing, the literal `${OPENCHOREO_AUTH_CLIENT_ID}` string ends up in the config, and the auth module rejects it. + +**Fix:** for local k3d, hardcode the seeded credentials instead of using env-var substitution — see the [Local k3d quickstart](./installing-into-existing-backstage.mdx#k3d-quickstart) section. For a real deployment, set the env vars in your shell or process manager before starting Backstage. + +## 401 on tab data fetches after signing in + +``` +HTTP 401: Unauthorized +``` + +**Cause:** you're signed in to Backstage but the OpenChoreo backend modules (`-observability-backend`, `-ci-backend`, `-workflows-backend`) reject your requests because they can't find the IDP token. Backstage's default `fetchApi` only injects the Backstage identity token in `Authorization`; it has no concept of the `x-openchoreo-token` header the backend modules read. + +**Fix:** install the custom `OpenChoreoFetchApi` and register it against `fetchApiRef` via an `ApiBlueprint` extension in your `customAppModule`. See [install guide Section 4.3.2](./installing-into-existing-backstage.mdx#custom-app-module). The same fix is needed for permission requests — `OpenChoreoPermissionApi` against `permissionApiRef`, also covered in the same section. + +## "No permissions to view this environment" on Deploy / Logs / Metrics tabs + +**Cause:** one of two things, in order of likelihood: + +1. **`OpenChoreoPermissionApi` not registered.** The default `PermissionClient` bypasses `fetchApi` entirely and never gets the IDP token, so every authorize call fails. Fix: register `OpenChoreoPermissionApi` against `permissionApiRef` — via the `customAppModule` `ApiBlueprint` extension under NFS (see [install guide Section 4.3.2](./installing-into-existing-backstage.mdx#custom-app-module)), or via `createApiFactory` in `apis.ts` on the legacy frontend. +2. **Your user genuinely has no capabilities** in OpenChoreo. The IDP token is valid but the user's entitlements from ThunderID have not been mapped to a role in OpenChoreo that grants `release-binding:read` / `environment:read`. Confirm with `LOG_LEVEL=debug yarn start`, hit a Deploy tab, and grep backend logs for `[AUTHZ] Parsed capabilities` — that dumps what the OpenChoreo authz service returned. If the expected capabilities aren't there, fix the user's role bindings on the OpenChoreo control plane, not in Backstage. + +## `JWKSNoMatchingKey` warnings in permission backend logs + +``` +permission warn Failed to verify incoming user token no applicable key +found in the JSON Web Key Set +``` + +Benign. It means the permission backend is trying to verify an incoming user token against the OpenChoreo IDP's JWKS but the token was issued by another provider (typically Backstage's guest provider when your cluster is in auth-off mode). Catalog sync still works because the catalog provider uses its own client-credentials flow, not the user token. The warning disappears once users sign in via OpenChoreo (i.e. when the cluster runs with `auth.enabled: true` and your Backstage config mirrors it). diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-scaffolder-templates.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-scaffolder-templates.mdx new file mode 100644 index 00000000..97e881e7 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/backstage-scaffolder-templates.mdx @@ -0,0 +1,572 @@ +--- +title: Custom Backstage Scaffolder Templates +description: Author your own Backstage scaffolder templates that reuse the OpenChoreo scaffolder actions. +sidebar_position: 8 +--- + +import CodeBlock from "@theme/CodeBlock"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { versions } from "../_constants.mdx"; + +# Custom Backstage Scaffolder Templates + +OpenChoreo's Backstage integration registers a set of scaffolder actions — small, composable building blocks (create a Project, create a Component, create a Resource, etc.) that templates can chain together. The portal also ships default templates that consume those actions and cover the core OpenChoreo resources out of the box. + +Enterprises may need to wrap the OpenChoreo actions in their own opinionated templates for use cases the defaults don't cover — for example, chaining multiple OpenChoreo actions into a single user-facing flow (onboarding a new team, provisioning a managed resource together with its consumer, etc.), or composing OpenChoreo actions with Backstage's built-in actions for Git providers and CI. + +This guide shows how to author a custom template, what OpenChoreo actions are available, and how to deploy the template in either of the two supported portal setups. + +## Audience + +Two ways of running Backstage with OpenChoreo are covered here. The **Actions**, **Example Template**, and **User-Token Form Decorator** sections are common to both. Only the deployment steps (registering the decorator, making the template discoverable) differ. + +| Setup | Description | Where divergent steps apply | +| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| **OpenChoreo shell app** (default) | The Backstage portal that ships with OpenChoreo and is installed by the `openchoreo-control-plane` Helm chart. You do not edit Backstage source — you customize via Helm values. | Pick the **"Shell app"** tab in the deployment sections below. | +| **Your own Backstage app** | A Backstage workspace you own, with the `@openchoreo/*` plugins installed per [Installing into an existing Backstage app](./backstage-plugins/installing-into-existing-backstage.mdx). | Pick the **"Own Backstage app"** tab in the deployment sections below. | + +:::info Backstage scaffolder concepts + +This page does **not** re-document Backstage's scaffolder template format. For the general concept of a `Template` resource, parameters, JSON-schema form fields, step expressions, and registering templates with the catalog, see the upstream Backstage docs: + +- [Software Templates Overview](https://backstage.io/docs/features/software-templates/) +- [Writing Templates](https://backstage.io/docs/features/software-templates/writing-templates) +- [Built-in actions](https://backstage.io/docs/features/software-templates/builtin-actions) + +What follows is only the OpenChoreo-specific piece: the actions, how to authenticate them, and how to deploy the template. + +::: + +## Available OpenChoreo Actions + +### Resource-Creation Actions (Structured Input) + +Use these when you want your template's form fields to drive a specific resource. Inputs map directly to fields on the OpenChoreo CRD. + +| Action ID | Creates | Audience | Required input | +| --------------------------------------- | --------------------------------------------------- | ----------------- | ---------------------------------------------------------------------- | +| `openchoreo:namespace:create` | `Namespace` (Backstage `Domain`) | Platform engineer | `namespaceName` | +| `openchoreo:project:create` | `Project` (Backstage `System`) | Developer | `namespaceName`, `projectName`, `deploymentPipeline` | +| `openchoreo:component:create` | `Component` + optional `Workload` | Developer | `namespaceName`, `projectName`, `componentName`, `componentType` | +| `openchoreo:resource:create` | `Resource` (managed resource from a `ResourceType`) | Developer | `namespaceName`, `projectName`, `resourceName`, `typeKind`, `typeName` | +| `openchoreo:environment:create` | `Environment` | Platform engineer | `namespaceName`, `environmentName`, `isProduction` | +| `openchoreo:deployment-pipeline:create` | `DeploymentPipeline` | Platform engineer | `namespaceName`, `pipelineName` | + +:::note Type-driven parameters + +`openchoreo:component:create` and `openchoreo:resource:create` reference an OpenChoreo `ComponentType` / `ResourceType` whose own schema can declare additional parameters. Both actions forward any extra template inputs to that schema, so a template targeting a type that declares required parameters must collect and pass those inputs as well. The default ComponentTypes and ResourceTypes shipped with OpenChoreo declare no required parameters, so the columns above are sufficient out of the box; types published by your platform team may require more. + +::: + +### Definition Actions (Raw YAML Input) + +These take a `yamlContent` string containing the resource manifest. Use them when the resource's shape varies enough that a fixed form would be limiting — for example, governance resources that platform teams curate by hand. + +| Action ID | Creates | Required input | +| --------------------------------------------------- | ------------------------------------- | ------------------------------ | +| `openchoreo:componenttype-definition:create` | Namespaced `ComponentType` | `namespaceName`, `yamlContent` | +| `openchoreo:resourcetype-definition:create` | Namespaced `ResourceType` | `namespaceName`, `yamlContent` | +| `openchoreo:trait-definition:create` | Namespaced `Trait` | `namespaceName`, `yamlContent` | +| `openchoreo:componentworkflow-definition:create` | Namespaced `Workflow` | `namespaceName`, `yamlContent` | +| `openchoreo:clustercomponenttype-definition:create` | Cluster-scoped `ClusterComponentType` | `yamlContent` | +| `openchoreo:clusterresourcetype-definition:create` | Cluster-scoped `ClusterResourceType` | `yamlContent` | +| `openchoreo:clustertrait-definition:create` | Cluster-scoped `ClusterTrait` | `yamlContent` | +| `openchoreo:clusterworkflow-definition:create` | Cluster-scoped `ClusterWorkflow` | `yamlContent` | + +Each action also emits an `entityRef` output (and `projectName` / `namespaceName` / etc. where applicable) that downstream steps and the template's `output.links` can consume. The source of truth for every input and output is the action's Zod schema — see [`plugins/scaffolder-backend-module-openchoreo/src/actions/`](https://github.com/openchoreo/backstage-plugins/tree/main/plugins/scaffolder-backend-module-openchoreo/src/actions). + +## The User-Token Form Decorator + +When OpenChoreo runs with authentication enabled, every OpenChoreo action checks for an `OPENCHOREO_USER_TOKEN` secret in the template execution context. The secret is the **signed-in user's OpenChoreo IDP access token** — actions present it to the OpenChoreo API so writes are attributed to (and authorized for) the real user, not a shared service account. + +The token is injected by a Backstage **form decorator** that runs in the browser at form-submit time, retrieves the OAuth token from the OpenChoreo auth API, and stashes it into the template's `secrets` map. Any template that calls an OpenChoreo action **must** opt into that decorator in its `spec`: + +```yaml title="my-template.yaml" +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +spec: + EXPERIMENTAL_formDecorators: + - id: openchoreo:inject-user-token + # ... parameters, steps, output ... +``` + +Without the decorator the action throws `User authentication token not available. Ensure you are logged in.` at runtime. + +### Registering the Decorator + + + + +The decorator is already wired into the OpenChoreo shell app — you don't need to do anything. Including `EXPERIMENTAL_formDecorators: [{ id: openchoreo:inject-user-token }]` in your template `spec` is sufficient. + + + + +The decorator implementation is not yet shipped from a published plugin. Drop the following file into your app and register it once against `formDecoratorsApiRef`: + +```ts title="packages/app/src/scaffolder/openChoreoTokenDecorator.ts" +import { createScaffolderFormDecorator } from "@backstage/plugin-scaffolder-react/alpha"; +import { configApiRef } from "@backstage/core-plugin-api"; +import { openChoreoAuthApiRef } from "../apis/authRefs"; + +export const openChoreoTokenDecorator = createScaffolderFormDecorator({ + id: "openchoreo:inject-user-token", + deps: { oauthApi: openChoreoAuthApiRef, configApi: configApiRef }, + async decorator({ setSecrets }, { oauthApi, configApi }) { + const authEnabled = + configApi.getOptionalBoolean("openchoreo.features.auth.enabled") ?? true; + if (!authEnabled) return; + + const token = await oauthApi.getAccessToken(); + if (!token) { + throw new Error( + "Failed to get authentication token. Ensure you are logged in.", + ); + } + setSecrets((state) => ({ ...state, OPENCHOREO_USER_TOKEN: token })); + }, +}); +``` + +Register it in `packages/app/src/apis.ts`: + +```ts title="packages/app/src/apis.ts" +import { + DefaultScaffolderFormDecoratorsApi, + formDecoratorsApiRef, +} from "@backstage/plugin-scaffolder-react/alpha"; +import { openChoreoTokenDecorator } from "./scaffolder/openChoreoTokenDecorator"; + +export const apis: AnyApiFactory[] = [ + // ... existing factories ... + createApiFactory({ + api: formDecoratorsApiRef, + deps: {}, + factory: () => + DefaultScaffolderFormDecoratorsApi.create({ + decorators: [openChoreoTokenDecorator], + }), + }), +]; +``` + +The `openChoreoAuthApiRef` import is the same one wired up in [section 4.3.2 of the install guide](./backstage-plugins/installing-into-existing-backstage.mdx#custom-app-module). + + + + +## Example Template + +The template below is an example of what a custom scaffolder template can look like. It onboards a new team by chaining three OpenChoreo scaffolder actions — `openchoreo:namespace:create`, `openchoreo:deployment-pipeline:create`, and `openchoreo:project:create` — into a single user-facing form, with each step's outputs feeding the next. + +```yaml title="onboard-team/template.yaml" +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: onboard-team + title: Onboard a new team + description: | + Provision a namespace, a deployment pipeline, and a starter project for a + new team. All three resources are created in a single flow. + tags: + - openchoreo + - platform-setup +spec: + owner: platform-engineering + type: team + + # Inject the signed-in user's OpenChoreo IDP token as OPENCHOREO_USER_TOKEN. + # Required by every OpenChoreo action whenever the cluster runs with auth enabled. + EXPERIMENTAL_formDecorators: + - id: openchoreo:inject-user-token + + parameters: + - title: Team details + required: [teamName, sourceEnvironment, targetEnvironment] + properties: + teamName: + title: Team name + type: string + pattern: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" + description: Lowercase, hyphenated. Used as the namespace name. + sourceEnvironment: + title: Source environment + type: string + description: First environment in the promotion path (e.g. "dev"). Must already exist. + targetEnvironment: + title: Target environment + type: string + description: Final environment in the promotion path (e.g. "prod"). Must already exist. + + steps: + # 1. Create the namespace. + - id: namespace + name: Create namespace + action: openchoreo:namespace:create + input: + namespaceName: ${{ parameters.teamName }} + + # 2. Create a deployment pipeline in the new namespace, referencing the + # namespaceName output of step 1. + - id: pipeline + name: Create deployment pipeline + action: openchoreo:deployment-pipeline:create + input: + namespaceName: ${{ steps.namespace.output.namespaceName }} + pipelineName: ${{ parameters.teamName }}-pipeline + promotionPaths: + - sourceEnvironmentRef: + name: ${{ parameters.sourceEnvironment }} + targetEnvironmentRefs: + - name: ${{ parameters.targetEnvironment }} + + # 3. Create a starter project that uses the new pipeline, referencing + # outputs from both earlier steps. + - id: project + name: Create starter project + action: openchoreo:project:create + input: + namespaceName: ${{ steps.namespace.output.namespaceName }} + projectName: ${{ parameters.teamName }}-starter + deploymentPipeline: ${{ steps.pipeline.output.pipelineName }} + + output: + links: + - title: Namespace + icon: catalog + entityRef: ${{ steps.namespace.output.entityRef }} + - title: Deployment pipeline + icon: catalog + entityRef: ${{ steps.pipeline.output.entityRef }} + - title: Starter project + icon: catalog + entityRef: ${{ steps.project.output.entityRef }} +``` + +The example uses plain JSON Schema input fields so the template is portable to any Backstage instance. If you're running the OpenChoreo shell app, several OpenChoreo-specific field extensions are also available — `NamespaceEntityPicker`, `ResourceNamePicker`, `DeploymentPipelinePicker`, `ComponentNamePicker`, `BuildWorkflowPicker`, `TraitsField`, and others — that you can swap in via `ui:field:` for richer dropdowns, validation, and entity-aware behavior. See the [in-tree templates](https://github.com/openchoreo/backstage-plugins/tree/main/templates) for examples of how each is wired up. + +## Making the Template Discoverable + +A template only appears in the scaffolder's **Create** page once Backstage has ingested it. + +:::info Template source + +This section assumes your `template.yaml` lives in a GitHub repository. For templates hosted in other supported sources (GitLab, Bitbucket, AWS S3, Google GCS, etc.), the same mechanisms apply — you'll just configure a different `integrations.*` block. See the [Backstage integrations reference](https://backstage.io/docs/integrations/) for the full list of supported sources. Sources Backstage doesn't natively support (Google Drive, OneDrive, etc.) need to be mirrored into a supported backend first. + +::: + +Two approaches are documented below, and they're not mutually exclusive: + +- **Catalog Import UI** — paste a URL into Backstage's `/catalog-import` wizard. The Location is stored in the Backstage database and does not survive a fresh install or DB reset. +- **`catalog.locations`** — declare the template in `app-config`. The Location is config-resident, version-controlled alongside the rest of your platform settings, and survives a fresh install. + +Pick the tab below that matches your setup; each tab walks through both approaches plus a single Applying Your Changes step at the end. + + + + +For the shell app, every change below is an edit to a single `values.override.yaml`, applied via one `helm upgrade --reuse-values` at the end. You don't need separate upgrades per change. + +#### Prerequisite: GitHub Integration + +Backstage needs an `integrations.github` block in `app-config` to recognize github.com as a fetchable host. + +For private repo access, configure a [GitHub Personal Access Token](https://github.com/settings/tokens/new) (or [GitHub App](https://docs.github.com/en/apps/creating-github-apps)) with the required read permissions on the repository, and store it in a Kubernetes secret: + +```bash +kubectl create secret generic backstage-git-secrets \ + --namespace openchoreo-control-plane \ + --from-literal=github-token='ghp_your_personal_access_token' \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +For a private repo, add to `values.override.yaml`: + +```yaml title="values.override.yaml — GitHub integration (private repo)" +backstage: + extraEnv: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: backstage-git-secrets + key: github-token + + appConfig: + integrations: + github: + - host: github.com + token: ${GITHUB_TOKEN} +``` + +For a public repo, add to `values.override.yaml`: + +```yaml title="values.override.yaml — GitHub integration (public repo)" +backstage: + appConfig: + integrations: + github: + - host: github.com +``` + +#### Approach 1: Register via the Catalog Import UI + +Backstage ships a wizard at **Create** → **Import to Catalog** (route: `/catalog-import`) that accepts a URL to any entity file and registers it as a `Location` in the catalog database. This is the lowest-friction path for one-off template additions. + +**One-time setup: allow `Template` entities globally.** The OpenChoreo shell app's bundled `catalog.rules.allow` does **not** include `Template` at the global level — the default templates work because each is declared in `catalog.locations` with its own per-location `allow: [Template]` rule. UI-imported Locations live in the database and have no per-location rules to fall back on, so the global rules apply, and Backstage rejects the Template entity with `NotAllowedError` unless `Template` is in the global allow list. + +Fragment for `values.override.yaml`: + +```yaml title="values.override.yaml — global allow list (Approach 1)" +backstage: + appConfig: + catalog: + rules: + - allow: + - Component + - System + - API + - Resource + - Location + - User + - Group + - Environment + - Template # <-- new +``` + +The list mirrors the chart-shipped defaults plus `Template`. The wizard is used after the changes are applied — see Applying Your Changes below. + +#### Approach 2: Register via `catalog.locations` + +Declare the template as a `Location` in `app-config`. Locations defined this way are config-resident: they survive a fresh install, live in version control alongside the rest of your platform settings, and don't require the `catalog.rules` tweak from Approach 1 (the per-location `rules: [allow: [Template]]` is enough). + +The custom-template fragment (the bundled defaults are listed in the combined example below): + +```yaml +- type: url + target: https://github.com///blob/main/template.yaml + rules: + - allow: [Template] +``` + +#### Applying Your Changes + +Merge the fragments above into one `values.override.yaml` and apply with a single `helm upgrade`. The example below combines **all** the fragments — strip whichever blocks you don't need (e.g., remove the `rules` block if you only use Approach 2, or remove the `extraEnv` and `token:` line for a public repo). + +:::warning Overriding Default Backstage Configurations +Backstage replaces arrays across configs rather than concatenating them. Any `catalog.*` block you set in `values.override.yaml` must contain the **full** value, including the chart-shipped defaults — listing only your additions would drop everything else. The example below re-declares the bundled defaults for both `catalog.rules` and `catalog.locations` so you can copy it as-is. See the [Backstage configuration docs](https://backstage.io/docs/conf/writing) for the merge semantics. +::: + +```yaml title="values.override.yaml — combined" +backstage: + # Prerequisite: PAT secret env var. Omit if your repo is public. + extraEnv: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: backstage-git-secrets + key: github-token + + appConfig: + # Prerequisite: GitHub integration (required for both approaches). + integrations: + github: + - host: github.com + # Remove the `token` line if your repo is public. + token: ${GITHUB_TOKEN} + + catalog: + # Approach 1: allow Template entities globally so UI imports succeed. + # Omit this block if you only use Approach 2. + rules: + - allow: + - Component + - System + - API + - Resource + - Location + - User + - Group + - Environment + - Template + + # Approach 2: declare templates via catalog.locations. + # Omit this block if you only use Approach 1. + locations: + # Bundled defaults — must be re-declared due to array replacement. + - type: file + target: /app/catalog-entities/org.yaml + rules: + - allow: [Group] + - type: file + target: /app/templates/create-openchoreo-project/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-componenttype/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-resourcetype/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-trait/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-workflow/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-environment/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-namespace/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-deploymentpipeline/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-clustercomponenttype/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-clusterresourcetype/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-clustertrait/template.yaml + rules: + - allow: [Template] + - type: file + target: /app/templates/create-openchoreo-clusterworkflow/template.yaml + rules: + - allow: [Template] + + # Your custom template (Approach 2). + - type: url + target: https://github.com///blob/main/template.yaml + rules: + - allow: [Template] +``` + +Apply with a single `helm upgrade --reuse-values`: + + + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + -f values.override.yaml`} + + +The chart rolls the Backstage pod automatically when the rendered ConfigMap changes. If the new config isn't picked up, force a restart: + +```bash +kubectl rollout restart deployment/backstage -n openchoreo-control-plane +``` + +**If you're using Approach 1**, navigate to **Create** → **Import to Catalog** after the pod is back up. + +Backstage Create page with the Import to Catalog entry point + +Paste the `blob` URL of your `template.yaml`: + +``` +https://github.com///blob/main/template.yaml +``` + +Backstage Import to Catalog wizard with a template.yaml URL pasted into the analyze step + +Click **Analyze**, review the preview, then **Import**. The template appears under **Create** within a few seconds. Repeat for each new template — no further chart upgrade needed. + +#### How It Appears in the Portal + +Once the template's `Location` is ingested (and, for `catalog.locations` changes, the Backstage pod is restarted), the new template shows up on Backstage's **Create** page under **Other Templates** section. + +Custom enterprise template appearing on the Backstage Create page alongside the built-in OpenChoreo templates + + + + +For an own Backstage app, every change below is an edit to your `app-config.yaml`. Restart Backstage (e.g., `yarn dev`) once after all the edits. + +#### Prerequisite: GitHub Integration + +Add `integrations.github` to your `app-config.yaml`. The block is required regardless of whether your template repo is public or private — only the `token` within it is conditional: + +```yaml title="app-config.yaml" +integrations: + github: + - host: github.com + # Omit the `token` line for a public repo. + token: ${GITHUB_TOKEN} +``` + +For a **private** repo, set `GITHUB_TOKEN` in the environment where Backstage runs (your shell, a `.env` file in dev, or the deployment's env in production). Don't commit the token to source control. For classic PATs, the `repo` scope is sufficient; for fine-grained PATs, grant `Contents: Read` on the template repository. + +For a **public** repo, omit the `token:` line and the env var entirely. + +#### Approach 1: Register via the Catalog Import UI + +Backstage ships a wizard at **Create** → **Import to Catalog** (route: `/catalog-import`) that accepts a URL to any entity file and registers it as a `Location` in the catalog database. + +**One-time setup: allow `Template` entities globally.** UI-imported Locations live in the database and don't carry per-location rules, so the global `catalog.rules.allow` list must include `Template` for the Template entity to be accepted: + +```yaml title="app-config.yaml" +catalog: + rules: + - allow: + - Component + - System + - API + - Resource + - Location + - User + - Group + - Template # <-- new +``` + +Adjust the list to mirror whatever your existing `catalog.rules.allow` contains, plus `Template`. The wizard is used after the changes are applied — see Applying Your Changes below. + +#### Approach 2: Register via `catalog.locations` + +Declare the template as a `Location` in `catalog.locations`. The per-location `rules: [allow: [Template]]` makes the global allow-list tweak unnecessary: + +```yaml title="app-config.yaml" +catalog: + locations: + # ...your existing entries... + - type: url + target: https://github.com///blob/main/template.yaml + rules: + - allow: [Template] +``` + +For the general form of `catalog.locations` entries — including how to index many templates from one Location pointer file — see Backstage's [catalog configuration docs](https://backstage.io/docs/features/software-catalog/configuration#static-location-configuration). + +#### Applying Your Changes + +Save your `app-config.yaml` and restart Backstage. **If you're using Approach 1**, navigate to **Create** → **Import to Catalog** after the restart. Paste the `blob` URL of your `template.yaml`: + +``` +https://github.com///blob/main/template.yaml +``` + +Click **Analyze**, review the preview, then **Import**. + + + diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cli-configuration.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cli-configuration.mdx new file mode 100644 index 00000000..ab7d4eb3 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cli-configuration.mdx @@ -0,0 +1,143 @@ +--- +title: CLI Configuration +description: Configure the OpenChoreo CLI (occ) for authentication and usage. +sidebar_position: 11 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# CLI Configuration + +The OpenChoreo CLI (`occ`) is the command-line interface for managing OpenChoreo resources, projects, and deployments. It provides commands to create, read, update, and delete OpenChoreo resources from your terminal. + +## Prerequisites + +Before configuring the CLI, ensure the following: + +- OpenChoreo Control Plane installed and accessible +- CLI installed (see [CLI Installation](../getting-started/cli-installation.mdx)) +- Network connectivity to the OpenChoreo API endpoint + +## Using an External Identity Provider + +By default, OpenChoreo configures ThunderID as the identity provider for the CLI with a pre-configured OAuth client for testing purposes. If you are using an external identity provider, create an OAuth 2.0 client with the following requirements: + +**OAuth Client Requirements:** + +1. **Grant Types**: The OAuth client must support: + - `authorization_code` - For user authentication and login flows + - `refresh_token` - For refreshing access tokens without re-authentication + - Support for **PKCE (Proof Key for Code Exchange)** - For secure authentication without client secrets + +2. **Token Format**: Configure the client to issue **JWT tokens** (not opaque tokens) + +3. **Redirect URLs**: Add the CLI callback URL: + - `http://127.0.0.1:55152/auth-callback` + - This is the local callback URL where the CLI receives the authentication response + +4. **Public Client**: The CLI OAuth client should be configured as a **public client** (does not require client secret) since it uses PKCE flow + +:::note +The CLI uses the OAuth 2.0 Authorization Code flow with PKCE extension. This is a secure authentication method for public clients (like CLI tools) that don't store client secrets. +::: + +### Configuring the CLI OAuth Client + +Once you have created the OAuth client in your identity provider, update the OpenChoreo control plane configuration with the client ID: + +```yaml +security: + oidc: + externalClients: + - name: cli + client_id: "your-cli-client-id" + scopes: + - openid + - profile + - email +``` + +After updating the configuration, you can use the CLI to login. The CLI will automatically open a browser window for authentication: + +{`occ login`} + +## Service Account Authentication + +For automation scenarios (CI/CD pipelines, scripts, etc.), you can use client credentials flow with a service account OAuth client: + +**OAuth Client Requirements for Service Accounts:** + +1. **Grant Type**: `client_credentials` +2. **Token Format**: JWT tokens +3. **Confidential Client**: Store client secret securely +4. **Token Endpoint Authentication**: `client_secret_post` (credentials sent in the request body, not as a Basic auth header) + +You can authenticate using command-line flags: + + + {`occ login --client-credentials \\ + --client-id \\ + --client-secret `} + + +**Configuration Parameters:** + +- `--client-credentials`: Enable client credentials flow +- `--client-id`: OAuth client ID for service account +- `--client-secret`: OAuth client secret for service account + +**Alternative: Using Environment Variables** + +For CI/CD pipelines, you can use environment variables instead of command-line flags: + + +{`export OCC_CLIENT_ID="your-client-id" +export OCC_CLIENT_SECRET="your-client-secret" + +occ login --client-credentials`} + + + +**Environment Variables:** + +- `OCC_CLIENT_ID`: OAuth client ID for service account +- `OCC_CLIENT_SECRET`: OAuth client secret for service account + +## Verifying the Configuration + +After logging in, verify that the CLI is configured correctly: + +```bash +occ component list +``` + +This should return a list of components (or an empty list if none exist yet), confirming that the CLI can authenticate and communicate with the control plane. + +## Troubleshooting + +### Browser Not Opening + +If the browser doesn't open automatically during login: + +1. Check that you have a default browser configured +2. Manually copy the URL displayed in the terminal and open it in your browser +3. Complete the authentication flow and return to the terminal + +### Token Refresh Failures + +If token refresh fails: + +```bash +# Re-authenticate with the CLI +occ login +``` + +See [Identity Provider Configuration](./identity-configuration.mdx) for detailed identity provider setup instructions. + +## Next Steps + +After configuring the CLI: + +- Explore available commands with `occ --help` +- See the [CLI Reference](../reference/cli-reference.md) for detailed command documentation diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cluster-agent-rbac.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cluster-agent-rbac.mdx new file mode 100644 index 00000000..3b243ba6 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/cluster-agent-rbac.mdx @@ -0,0 +1,272 @@ +--- +title: Cluster Agent RBAC Configuration +description: Configure additional permissions for the cluster agent to manage custom resources. +sidebar_position: 7 +--- + +# Cluster Agent RBAC Configuration + +The cluster agent in OpenChoreo's data plane, workflow plane, and observability plane requires specific Kubernetes permissions to manage resources. By default, the cluster agent has permissions to manage OpenChoreo's built-in custom resources. However, if you need the cluster agent to manage additional custom resources (CRDs) that are not provided by OpenChoreo, you must grant additional RBAC permissions. + +## Overview + +The cluster agent uses a Kubernetes service account to interact with the Kubernetes API. The permissions are defined in a `ClusterRole` and bound to the service account via a `ClusterRoleBinding`. + +:::warning Check Your Service Account Name and Namespace +Both the service account name and namespace can be customized via Helm values during installation. The default values are listed in the [Service Account Names](#service-account-names-by-plane) section below, but if you've overridden them in your Helm configuration, you must use your actual service account name and namespace when creating the ClusterRoleBinding. +::: + +## When to Configure Additional Permissions + +You need to configure additional RBAC permissions if: + +- You're deploying components that use third-party custom resources (e.g., Istio VirtualServices, Knative Services, etc.) +- Your workloads require the cluster agent to create, update, or manage CRDs that are not part of the OpenChoreo installation +- You receive permission errors in cluster agent logs indicating missing RBAC privileges + +## Configuring Additional Permissions + +### Step 1: Identify Required Permissions + +First, identify the custom resources and API groups that need to be accessible to the cluster agent. Check the cluster agent logs for permission errors: + +```bash +# For data plane (replace namespace if you customized it during installation) +kubectl logs -n openchoreo-data-plane -l app=cluster-agent --tail=50 + +# For workflow plane (replace namespace if you customized it during installation) +kubectl logs -n openchoreo-workflow-plane -l app=cluster-agent --tail=50 + +# For observability plane (replace namespace if you customized it during installation) +kubectl logs -n openchoreo-observability-plane -l app=cluster-agent --tail=50 +``` + +Look for errors like: + +``` +error: failed to create resource: customresources.example.com is forbidden: +User "system:serviceaccount:openchoreo-data-plane:cluster-agent-dataplane" +cannot create resource "customresources" in API group "example.com" +``` + +### Step 2: Create Additional ClusterRole + +Create a new `ClusterRole` with the required permissions. This keeps your custom permissions separate from the default OpenChoreo ClusterRole, making upgrades easier. + +:::tip +Ensure you use standard ASCII spaces for YAML indentation. Copy-pasting may introduce non-breaking spaces that cause kubectl parsing errors. +::: + +```yaml title="cluster-agent-custom-permissions.yaml" +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cluster-agent-custom-permissions +rules: + # Example: Add permissions for a custom CRD + - apiGroups: ["example.com"] + resources: ["customresources"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + + # Example: Add permissions for Istio resources + - apiGroups: ["networking.istio.io"] + resources: ["virtualservices", "destinationrules", "gateways"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + + # Add more rules as needed for your custom resources +``` + +### Step 3: Create ClusterRoleBinding + +Bind the new `ClusterRole` to the cluster agent service account. + +:::important Verify Service Account Name and Namespace +Before creating the ClusterRoleBinding, verify the actual service account name and namespace used in your installation. If you've customized these via Helm values, replace the default values below with your actual values. See [Service Account Names](#service-account-names-by-plane) for how to find your actual service account name and namespace. +::: + +:::tip +Ensure you use standard ASCII spaces for YAML indentation. Copy-pasting may introduce non-breaking spaces that cause kubectl parsing errors. +::: + +```yaml title="cluster-agent-custom-binding.yaml" +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-agent-custom-permissions +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-agent-custom-permissions +subjects: + # For data plane (default values shown) + # Replace with your actual service account name and namespace if customized + - kind: ServiceAccount + name: cluster-agent-dataplane + namespace: openchoreo-data-plane + + # Uncomment if you need the same permissions for workflow plane + # - kind: ServiceAccount + # name: cluster-agent-workflowplane + # namespace: openchoreo-workflow-plane + + # Uncomment if you need the same permissions for observability plane + # - kind: ServiceAccount + # name: cluster-agent-observabilityplane + # namespace: openchoreo-observability-plane +``` + +### Step 4: Apply the Configuration + +Apply both resources to your cluster: + +```bash +kubectl apply -f cluster-agent-custom-permissions.yaml +kubectl apply -f cluster-agent-custom-binding.yaml +``` + +### Step 5: Verify Permissions + +Verify that the service account now has the required permissions: + +```bash +# Check if the service account can perform the action +# Replace namespace and service account name with your actual values if customized +kubectl auth can-i create customresources.example.com \ + --as=system:serviceaccount:openchoreo-data-plane:cluster-agent-dataplane + +# Should output: yes +``` + +## Service Account Names by Plane + +The **default** values used by the cluster agent in each plane are: + +| Plane | Default Namespace | Default Service Account Name | Helm Value Paths | +| ------------------- | -------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------ | +| Data Plane | `openchoreo-data-plane` | `cluster-agent-dataplane` | Namespace: Helm `--namespace` flag
Service Account: `clusterAgent.serviceAccount.name` | +| Workflow Plane | `openchoreo-workflow-plane` | `cluster-agent-workflowplane` | Namespace: Helm `--namespace` flag
Service Account: `clusterAgent.serviceAccount.name` | +| Observability Plane | `openchoreo-observability-plane` | `cluster-agent-observabilityplane` | Namespace: Helm `--namespace` flag
Service Account: `clusterAgent.serviceAccount.name` | + +:::tip Finding Your Actual Service Account Name and Namespace +If you're unsure of the service account name or namespace in your installation, you can find them by running: + +```bash +# List all cluster-agent deployments across namespaces +kubectl get deployment -A -l app=cluster-agent + +# For a specific namespace (replace with your actual namespace) +kubectl get deployment cluster-agent -n -o jsonpath='{.spec.template.spec.serviceAccountName}' +``` + +Examples for default namespaces: + +```bash +# For data plane +kubectl get deployment cluster-agent -n openchoreo-data-plane -o jsonpath='{.spec.template.spec.serviceAccountName}' + +# For workflow plane +kubectl get deployment cluster-agent -n openchoreo-workflow-plane -o jsonpath='{.spec.template.spec.serviceAccountName}' + +# For observability plane +kubectl get deployment cluster-agent -n openchoreo-observability-plane -o jsonpath='{.spec.template.spec.serviceAccountName}' +``` + +::: + +## Example: Adding Permissions for Common CRDs + +:::tip YAML Indentation +All examples below use standard ASCII spaces for indentation. When copying these examples, ensure your text editor doesn't introduce non-breaking spaces or tabs. +::: + +### Cert-Manager Certificates + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cluster-agent-cert-manager +rules: + - apiGroups: ["cert-manager.io"] + resources: ["certificates", "issuers", "clusterissuers"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +``` + +### Prometheus ServiceMonitors + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cluster-agent-prometheus +rules: + - apiGroups: ["monitoring.coreos.com"] + resources: ["servicemonitors", "prometheusrules"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +``` + +### External Secrets Operator + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cluster-agent-external-secrets +rules: + - apiGroups: ["external-secrets.io"] + resources: ["externalsecrets", "secretstores", "clustersecretstores"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +``` + +## Best Practices + +1. **Principle of Least Privilege**: Only grant the minimum permissions required for your use case. Avoid using wildcards (`*`) for `apiGroups`, `resources`, or `verbs` unless absolutely necessary. + +2. **Separate ClusterRoles**: Keep custom permissions in separate `ClusterRole` resources rather than modifying the default OpenChoreo ClusterRole. This prevents your changes from being overwritten during Helm upgrades. + +3. **Documentation**: Document which custom resources require additional permissions and why, to help with troubleshooting and maintenance. + +4. **Version Control**: Store your RBAC configuration files in version control alongside your OpenChoreo deployment manifests. + +5. **Testing**: Test permission changes in a non-production environment first to ensure they work as expected and don't grant excessive privileges. + +## Troubleshooting + +### Permission Denied Errors Persist + +If you continue to see permission errors after applying the ClusterRole and ClusterRoleBinding: + +1. Verify the ClusterRoleBinding references the correct service account name and namespace +2. Check that the ClusterRole includes the specific resource and verb that's failing +3. Use `kubectl auth can-i` to verify permissions are correctly configured +4. Wait a few seconds and retry - RBAC changes are effective immediately but the cluster agent may need to retry the failed operation + +### Finding the Correct API Group + +If you're unsure of the API group for a custom resource: + +```bash +# List all CRDs and their API groups +kubectl get crds -o custom-columns=NAME:.metadata.name,GROUP:.spec.group + +# Get details about a specific CRD +kubectl get crd -o yaml +``` + +### Checking Current Permissions + +To see all permissions currently granted to a service account: + +```bash +# For data plane cluster agent +kubectl describe clusterrolebinding | grep -A 10 cluster-agent-dataplane + +# View the ClusterRole permissions +kubectl describe clusterrole +``` + +## Related Documentation + +- [Kubernetes RBAC Documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) +- [Secret Management](./secret-management.mdx) - For managing secrets with External Secrets Operator +- [Data Plane Helm Chart Reference](../reference/helm/data-plane.mdx) diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/overview.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/overview.md new file mode 100644 index 00000000..c7618208 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/overview.md @@ -0,0 +1,357 @@ +--- +title: Overview +description: Learn how to create ComponentTypes and Traits for OpenChoreo +--- + +# Authoring ComponentTypes and Traits + +This guide covers how to create custom [ComponentTypes](../../reference/api/platform/componenttype.md) and [Traits](../../reference/api/platform/trait.md) in OpenChoreo. It also covers their cluster-scoped variants, [ClusterComponentTypes](../../reference/api/platform/clustercomponenttype.md) and [ClusterTraits](../../reference/api/platform/clustertrait.md). + +## What is a ComponentType? + +OpenChoreo ships with default component types for common cases—backend services, web applications, scheduled tasks. In most organizations, these defaults are a starting point, not the finish line. + +A **ComponentType** provides platform operators with a declarative way to define the infrastructure created when a component is deployed. It builds on base workload types that map to Kubernetes (Deployment, StatefulSet, CronJob), letting you customize what resources get created and how they're configured. The default platform setup ships with ClusterComponentTypes (cluster-scoped), making them available across all namespaces out of the box. + +Platform operators can: + +- Adjust defaults to match internal standards +- Add new component types for the team's specific patterns +- Enforce best practices and security policies + +Developers keep working with a simple Component model without worrying about underlying Kubernetes details. + +### ClusterComponentType + +A **ClusterComponentType** is a cluster-scoped variant of ComponentType. The default platform setup uses ClusterComponentTypes so that all namespaces can reference them without duplication. Namespace-scoped ComponentTypes are available when you need to customize or override the defaults for a specific namespace. + +ClusterComponentTypes share the same spec structure as ComponentTypes. The only difference is scope. + +:::note +Because ClusterComponentType is a cluster-scoped resource, its manifest must **not** include `metadata.namespace`. If you are copying from a namespace-scoped ComponentType example, remove the `namespace` field to avoid validation errors. +::: + +**Key concepts:** + +- `workloadType` - The primary workload kind: `deployment`, `statefulset`, `cronjob`, `job`, or `proxy` +- `allowedTraits` - List of traits that can be applied to components of this type +- `parameters` / `environmentConfigs` - Define what developers can configure and environment-specific overrides +- `resources` - Templates that generate Kubernetes resources using CEL expressions + +### ComponentType Example + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: web-service + namespace: default +spec: + # Primary workload type - must have a matching resource id + workloadType: deployment + + # Traits that can be applied to components of this type + allowedTraits: + - kind: Trait + name: persistent-volume + - kind: Trait + name: autoscaler + - kind: Trait + name: monitoring + + # Parameters set by developers in Component spec + parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + minimum: 1 + + # Environment-specific values set in ReleaseBinding + environmentConfigs: + openAPIV3Schema: + type: object + properties: + resources: + type: object + properties: + cpu: + type: string + default: "100m" + memory: + type: string + default: "256Mi" + + # Resources to generate - templates use CEL expressions + resources: + # Primary workload - id must match workloadType + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.componentName} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + replicas: ${parameters.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${metadata.podSelectors} + spec: + containers: + - name: main + image: ${workload.container.image} + resources: + requests: + cpu: ${environmentConfigs.resources.cpu} + memory: ${environmentConfigs.resources.memory} + + # Service for the deployment + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.componentName} + namespace: ${metadata.namespace} + spec: + selector: ${metadata.podSelectors} + ports: ${workload.toServicePorts()} + + # HTTPRoutes created per endpoint based on visibility scope + - id: httproute-external + forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility && ep.type in ["HTTP", "GraphQL", "Websocket"]) ? [name] : []).flatten()}' + var: endpoint + template: + apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: ${oc_generate_name(metadata.componentName, endpoint)} + namespace: ${metadata.namespace} + labels: '${oc_merge(metadata.labels, {"openchoreo.dev/endpoint-name": endpoint, "openchoreo.dev/endpoint-visibility": "external"})}' + spec: + parentRefs: + - name: ${gateway.ingress.external.name} + namespace: ${gateway.ingress.external.namespace} + hostnames: | + ${[gateway.ingress.external.?http, gateway.ingress.external.?https] + .filter(g, g.hasValue()).map(g, g.value().host).distinct() + .map(h, oc_dns_label(endpoint, metadata.componentName, metadata.environmentName, metadata.componentNamespace) + "." + h)} + rules: + - matches: + - path: + type: PathPrefix + value: /${metadata.componentName}-${endpoint} + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("") != "" ? workload.endpoints[endpoint].?basePath.orValue("") : "/"}' + backendRefs: + - name: ${metadata.componentName} + port: ${workload.endpoints[endpoint].port} +``` + +## What is a Trait? + +A **Trait** augments a Component with operational behavior without modifying the ComponentType. Think of it as a composable overlay—you can mix and match Traits to add capabilities like storage, autoscaling, or network policies to any component. + +This lets platform operators define reusable operational patterns separately from the base component types, and lets developers attach only the capabilities they need. + +### ClusterTrait + +A **ClusterTrait** is a cluster-scoped variant of Trait. While Traits are namespace-scoped, ClusterTraits are available across all namespaces, enabling platform engineers to define shared cross-cutting concerns once—such as persistent storage, observability, or security policies—and allow Components in any namespace to reference them. + +ClusterTraits share the same spec structure as Traits—the only difference is scope. + +**Examples of what Traits can do:** + +- Add persistent storage (PVCs, volume mounts) +- Configure autoscaling rules +- Set network policies or ingress routing +- Inject sidecars for observability or service mesh + +**Key concepts:** + +- `parameters` / `environmentConfigs` - Define trait-specific parameters and environment overrides +- `creates` - New Kubernetes resources to create (e.g., PVC, ConfigMap) +- `patches` - Modifications to existing ComponentType resources (e.g., add volume mounts) + +### Trait Example + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: persistent-volume + namespace: default +spec: + # Static parameters set in Component.spec.traits[].parameters + parameters: + openAPIV3Schema: + type: object + properties: + volumeName: + type: string + mountPath: + type: string + + # Environment-specific values in ReleaseBinding.spec.traitEnvironmentConfigs + environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: "10Gi" + storageClass: + type: string + default: "standard" + + # Create new resources + creates: + - template: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + # Use trait.instanceName for unique naming + name: ${metadata.name}-${trait.instanceName} + namespace: ${metadata.namespace} + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: ${environmentConfigs.storageClass} + resources: + requests: + storage: ${environmentConfigs.size} + + # Patch existing resources from ComponentType + patches: + - target: + kind: Deployment + group: apps + version: v1 + operations: + # Add volume to pod spec + - op: add + path: /spec/template/spec/volumes/- + value: + name: ${parameters.volumeName} + persistentVolumeClaim: + claimName: ${metadata.name}-${trait.instanceName} + + # Add volume mount to container + - op: add + path: /spec/template/spec/containers[?(@.name=='main')]/volumeMounts/- + value: + name: ${parameters.volumeName} + mountPath: ${parameters.mountPath} +``` + +## How Components Use ComponentTypes and Traits + +Developers create **Components** that reference a ComponentType and optionally attach Traits. The Component specifies parameter values defined in the ComponentType and Trait schemas: + +- `componentType` references the ComponentType as a structured object with `kind` (`ComponentType` or `ClusterComponentType`, defaulting to `ComponentType`) and `name` (format: `workloadType/name`) fields. Set `kind: ClusterComponentType` explicitly when using the default platform types. +- `parameters` provides values for the ComponentType schema +- `traits[]` attaches Traits (or ClusterTraits) with their instance-specific parameters, using the `kind` field to specify `ClusterTrait` or `Trait` + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-api + namespace: default +spec: + # Reference a ClusterComponentType (must set kind explicitly) + componentType: + kind: ClusterComponentType + name: deployment/web-service + + # Set ComponentType parameters + parameters: + port: 3000 + replicas: 2 + + # Attach traits with instance-specific configuration + traits: + - name: persistent-volume + kind: ClusterTrait + instanceName: data-storage # Unique name for this trait instance + parameters: + volumeName: data + mountPath: /var/data +``` + +To deploy a Component, you first create a **ComponentRelease** that captures the Component, its Workload, ComponentType, and Traits as an immutable snapshot. Then you create a **ReleaseBinding** to deploy that release to a specific environment. + +The ReleaseBinding is where environment-specific values are set—the `environmentConfigs` defined in ComponentType and Trait specs. The same ComponentRelease can be deployed to multiple environments (dev → staging → prod), with each ReleaseBinding providing different override values: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-api-production +spec: + # Required: identifies the component this binding belongs to + owner: + projectName: my-project + componentName: my-api + + # Required: target environment + environment: production + + # Optional: specific release to deploy (omit for auto-deploy) + releaseName: my-api-release-v1 + + # ComponentType environment overrides + componentTypeEnvironmentConfigs: + resources: + cpu: "500m" + memory: "1Gi" + + # Trait environment overrides (keyed by instanceName) + traitEnvironmentConfigs: + data-storage: + size: "100Gi" + storageClass: "production-ssd" +``` + +## Syntax Systems + +ComponentTypes and Traits use three interconnected syntax systems: + +| Syntax | Purpose | Used In | +| ----------------------------------------- | ---------------------------------------------- | --------------------------------------------------------------------- | +| [Templating](./templating-syntax.md) | Dynamic value generation using CEL expressions | Resource templates | +| [Schema](./schema-syntax.md) | Parameter validation and defaults | `parameters.openAPIV3Schema` and `environmentConfigs.openAPIV3Schema` | +| [Patching](./patching-syntax.md) | Modifying existing resources | Trait `patches` section | +| [Validation Rules](./validation-rules.md) | CEL-based semantic validation | `validations` section in ComponentTypes and Traits | + +## CEL Reference + +Templates use CEL expressions that have access to context variables and built-in functions: + +- **[Context Variables](../../reference/cel/context-variables.md)** - `metadata`, `parameters`, `workload`, `configurations`, etc. +- **[Built-in Functions](../../reference/cel/built-in-functions.md)** - `oc_omit()`, `oc_merge()`, `oc_generate_name()`, `oc_dns_label()` +- **[Configuration Helpers](../../reference/cel/helper-functions.md)** - Helper functions for working with configs and secrets + +## Next Steps + +- **[Templating Syntax](./templating-syntax.md)** - Learn CEL expression syntax and resource control fields +- **[Schema Syntax](./schema-syntax.md)** - Define parameters with validation and defaults +- **[Patching Syntax](./patching-syntax.md)** - Modify resources in Traits using JSON Patch +- **[Validation Rules](./validation-rules.md)** - Define CEL-based semantic validation for ComponentTypes and Traits + +## Related Resources + +- [ComponentType API Reference](../../reference/api/platform/componenttype.md) - Full CRD specification +- [ClusterComponentType API Reference](../../reference/api/platform/clustercomponenttype.md) - Cluster-scoped variant +- [Trait API Reference](../../reference/api/platform/trait.md) - Full CRD specification +- [ClusterTrait API Reference](../../reference/api/platform/clustertrait.md) - Cluster-scoped variant +- [Component API Reference](../../reference/api/application/component.md) - Full CRD specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/patching-syntax.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/patching-syntax.md new file mode 100644 index 00000000..7e7e3622 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/patching-syntax.md @@ -0,0 +1,479 @@ +--- +title: Patching Syntax +description: JSON Patch operations for modifying resources in Traits +--- + +# Patching Syntax + +This guide explains how to use the patching system in OpenChoreo Traits to modify resources generated by ComponentTypes. + +## Overview + +Traits can modify existing resources using patches, which are JSON Patch operations enhanced with: + +- Array filtering using JSONPath-like syntax +- CEL-based resource targeting +- forEach iteration support + +A Trait can also **delete** whole resources produced by the ComponentType or earlier traits using the `spec.removes` section. See [Removing Resources](#removing-resources). + +## Basic Patch Structure + +Patches are defined in the Trait's `spec.patches` section: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: monitoring-sidecar +spec: + patches: + - target: + kind: Deployment + group: apps + version: v1 + operations: + - op: add + path: /spec/template/spec/containers/- + value: + name: prometheus-exporter + image: prom/node-exporter:latest + ports: + - containerPort: 9100 +``` + +## Supported Operations + +### add + +Adds a value at the specified path: + +```yaml +# Add a new label +- op: add + path: /metadata/labels/monitoring + value: "enabled" + +# Append to array (using -) +- op: add + path: /spec/containers/- + value: + name: sidecar + image: sidecar:latest + +# Add nested structure +- op: add + path: /metadata/annotations/example.com~1version + value: "v2.0" +``` + +### replace + +Replaces an existing value. The path must exist: + +```yaml +# Replace a value +- op: replace + path: /spec/replicas + value: 3 + +# Replace array element +- op: replace + path: /spec/containers/0/image + value: nginx:latest +``` + +### remove + +Removes a value at the path: + +```yaml +# Remove a label +- op: remove + path: /metadata/labels/deprecated + +# Remove array element +- op: remove + path: /spec/containers/1 +``` + +## Array Filtering + +Use JSONPath-like syntax to target specific array elements by field value: + +### Basic Filtering + +```yaml +# Target container by name +- op: add + path: /spec/template/spec/containers[?(@.name=='app')]/env/- + value: + name: MONITORING + value: enabled + +# Target volume by name +- op: replace + path: /spec/template/spec/volumes[?(@.name=='data')]/emptyDir + value: + sizeLimit: 10Gi +``` + +### Nested Field Filters + +```yaml +# Filter by nested field path (dot notation) +- op: replace + path: /spec/containers[?(@.resources.limits.memory=='2Gi')]/image + value: app:high-mem-v2 + +# Filter by configMap name +- op: add + path: /spec/volumes[?(@.configMap.name=='app-config')]/configMap/defaultMode + value: 0644 +``` + +### Filter Limitations + +**Supported**: Simple equality filters of the form `@.field.path=='value'` + +```yaml +# Supported +- op: add + path: /spec/containers[?(@.name=='app')]/env/- + value: { name: VAR, value: val } +``` + +**Not supported**: Multiple conditions (`&&`, `||`), operators like `contains`, array indexing in filters, or existence checks. + +## CEL Expression Support + +CEL expressions (`${...}`) can be used in patch fields: + +### In path + +```yaml +# Dynamic path segments +- op: add + path: /data/${env.name} + value: ${env.value} + +# Dynamic filter conditions +- op: add + path: /spec/containers[?(@.name=='${parameters.containerName}')]/env/- + value: + name: VERSION + value: ${parameters.version} +``` + +### In value + +```yaml +- op: add + path: /metadata/labels/app + value: ${metadata.name} + +- op: add + path: /spec/template/spec/containers/- + value: + name: ${parameters.sidecarName} + image: ${parameters.sidecarImage} + ports: + - containerPort: ${parameters.sidecarPort} +``` + +## Resource Targeting + +### Basic Targeting + +The `target` spec requires `kind`, `group`, and `version`: + +```yaml +patches: + # Patch apps/v1 Deployment + - target: + kind: Deployment + group: apps + version: v1 + operations: + - op: add + path: /metadata/labels/patched + value: "true" + + # Patch core v1 Service (empty string for core API) + - target: + kind: Service + group: "" # Empty string for core API resources + version: v1 + operations: + - op: add + path: /metadata/annotations/patched + value: "true" +``` + +**Key points:** + +- `kind`, `group`, and `version` are **required** +- For core API resources (Service, ConfigMap, Secret), use `group: ""` +- `targetPlane` is optional, defaults to `"dataplane"` + +### CEL-Based Filtering with where + +Use `where` clause to target resources conditionally: + +```yaml +patches: + - target: + kind: Deployment + group: apps + version: v1 + where: ${resource.spec.replicas > 1} # Only multi-replica deployments + operations: + - op: add + path: /metadata/annotations/ha-mode + value: "true" + + - target: + kind: Service + group: "" + version: v1 + where: ${resource.spec.type == 'LoadBalancer'} + operations: + - op: add + path: /metadata/annotations/external + value: "true" +``` + +## ForEach Iteration + +Apply patches iteratively over a list: + +```yaml +patches: + - target: + kind: ConfigMap + group: "" + version: v1 + forEach: ${parameters.environments} + var: env + operations: + - op: add + path: /data/${env.name} + value: ${env.value} + + - target: + kind: Deployment + group: apps + version: v1 + forEach: ${parameters.extraPorts} + var: port + operations: + - op: add + path: /spec/template/spec/containers[?(@.name=='app')]/ports/- + value: + containerPort: ${port.number} + name: ${port.name} +``` + +## Removing Resources + +Patches modify resources in place. When a Trait needs to **delete** a whole resource produced by the ComponentType or by an earlier trait, use the `spec.removes` section instead. Each entry matches resources by GVK (with an optional `where` filter) and removes the matched resources entirely from the rendered output. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: drop-default-route +spec: + removes: + - target: + kind: HTTPRoute + group: gateway.networking.k8s.io + version: v1 + targetPlane: dataplane +``` + +A remove entry uses the same `target` shape as a patch, but has no `operations`. The whole matched resource is deleted: + +| Field | Required | Description | +| ----------------- | -------- | ---------------------------------------------------------------------- | +| `target.kind` | Yes | Resource kind to remove (e.g. `HTTPRoute`, `ConfigMap`) | +| `target.group` | Yes | API group; use `""` for core API resources | +| `target.version` | Yes | API version (e.g. `v1`) | +| `target.where` | No | CEL expression filtering which matching resources are removed | +| `targetPlane` | No | Plane whose resources are targeted; defaults to `"dataplane"` | +| `forEach` / `var` | No | Iterate over a CEL list, binding each item to `var` for use in `where` | + +**Execution order** - Within a single trait, removes run **after** its `creates` and `patches`. This lets one trait fully express a substitution: create a replacement resource and then remove the original. + +```yaml +spec: + creates: + - template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${metadata.name}-tuned-config + data: + mode: optimized + removes: + # Drop the ConfigMap the ComponentType emitted, now that the tuned one exists + - target: + kind: ConfigMap + group: "" + version: v1 + where: ${resource.metadata.name == metadata.name + "-default-config"} +``` + +:::warning Workload resources cannot be removed +The primary workload is defined by the ComponentType, so traits **must not** delete it. The admission webhook rejects removes that target a built-in workload GVK: kinds `Deployment`, `StatefulSet`, `DaemonSet`, `CronJob`, or `Job` in the `apps` or `batch` groups. The match is on the full GVK, so a custom CRD that merely shares one of these kind names in a different group (e.g. `group: example.com`, `kind: Deployment`) is **not** rejected. +::: + +`forEach` is supported just like in patches, letting you remove a set of resources derived from a CEL list: + +```yaml +removes: + - target: + kind: HTTPRoute + group: gateway.networking.k8s.io + version: v1 + where: ${resource.metadata.labels["openchoreo.dev/endpoint-name"] == route} + forEach: ${parameters.routesToDrop} + var: route +``` + +## Path Resolution Behavior + +| Path Type | Operation | Behavior | +| ----------------- | -------------------- | ------------------------------------------ | +| Map key | add | Auto-creates parent maps if missing | +| Map key | replace | Error if target doesn't exist | +| Map key | remove | Idempotent - no error if key doesn't exist | +| Filter `[?(...)]` | add, replace, remove | Error if no match | +| Array index | add, replace, remove | Error if index out of bounds | + +**Auto-create and idempotent removal** - The `add` operation automatically creates missing parent objects, and `remove` on map keys succeeds silently if the key doesn't exist. This reduces boilerplate and matches Kubernetes Strategic Merge Patch behavior. + +**Array indices** - All array index operations error on out-of-bounds indices, as this likely indicates a mismatch between the patch and the resource. Use filters like `[?(@.name=='app')]` instead of positional indices for resilient patches. + +## Path Escaping + +Paths use JSON Pointer syntax with special character escaping: + +- `/` in a key → `~1` +- `~` in a key → `~0` + +This is commonly needed for Kubernetes annotations that contain `/`: + +```yaml +# Annotation: kubernetes.io/ingress-class +- op: add + path: /metadata/annotations/kubernetes.io~1ingress-class + value: nginx + +# Annotation: sidecar.istio.io/inject +- op: add + path: /spec/template/metadata/annotations/sidecar.istio.io~1inject + value: "true" + +# Key containing ~ +- op: add + path: /data/config~0backup + value: backup-data +``` + +## Common Patterns + +### Safe Label Addition + +```yaml +# Good - adds individual labels without affecting existing ones +- op: add + path: /metadata/labels/monitoring + value: enabled + +# Bad - replaces all existing labels +- op: replace + path: /metadata/labels + value: + monitoring: enabled +``` + +### Add Sidecar Container + +```yaml +patches: + - target: + kind: Deployment + group: apps + version: v1 + operations: + # Add sidecar container + - op: add + path: /spec/template/spec/containers/- + value: + name: fluentd + image: fluent/fluentd:v1.14 + volumeMounts: + - name: logs + mountPath: /var/log + + # Add shared volume + - op: add + path: /spec/template/spec/volumes/- + value: + name: logs + emptyDir: {} + + # Mount to main container + - op: add + path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/- + value: + name: logs + mountPath: /app/logs +``` + +### Volume Mount Injection + +```yaml +- op: add + path: /spec/template/spec/volumes/- + value: + name: config + configMap: + name: ${metadata.name}-config + +- op: add + path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/- + value: + name: config + mountPath: /etc/config + readOnly: true +``` + +### Environment Variables from Parameters + +```yaml +patches: + - target: + kind: Deployment + group: apps + version: v1 + forEach: ${parameters.envVars} + var: envVar + operations: + - op: add + path: /spec/template/spec/containers[?(@.name=='${parameters.containerName}')]/env/- + value: + name: ${envVar.name} + value: ${envVar.value} +``` + +:::tip +**Use filters for explicit targeting** - Prefer `[?(@.name=='app')]` over positional indices like `[0]`. Filters are more resilient to changes in resource structure. +::: + +## Related Resources + +- [Templating Syntax](./templating-syntax.md) - CEL expressions for dynamic values +- [Schema Syntax](./schema-syntax.md) - Parameter definitions for Traits +- [Trait API Reference](../../reference/api/platform/trait.md) - Full CRD specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/schema-syntax.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/schema-syntax.md new file mode 100644 index 00000000..becb44d9 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/schema-syntax.md @@ -0,0 +1,472 @@ +--- +title: openAPIV3Schema +description: Parameter schema definition for ComponentTypes and Traits using openAPIV3Schema +--- + +# openAPIV3Schema + +This guide explains how to define schemas for ComponentTypes and Traits using `openAPIV3Schema`. Schemas are defined using standard [OpenAPI v3 JSON Schema](https://swagger.io/docs/specification/data-models/) format, giving you full control over parameter validation with a widely adopted specification. + +## Overview + +Schemas are defined under the `openAPIV3Schema` field in your ComponentType or Trait spec. They follow the standard JSON Schema structure used by OpenAPI v3: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + fieldName: + type: string + description: "A description of this field" +``` + +## Basic Types + +### Primitives + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + name: + type: string # Required string + age: + type: integer + minimum: 0 + maximum: 120 # Integer with constraints + price: + type: number + minimum: 0.01 # Number (float) with minimum + enabled: + type: boolean + default: false # Optional boolean with default +``` + +### Arrays + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + tags: + type: array + items: + type: string # Array of strings + ports: + type: array + items: + type: integer # Array of integers + mounts: + type: array + items: + type: object + properties: + path: + type: string + readOnly: + type: boolean # Array of objects + configs: + type: array + items: + type: object + additionalProperties: + type: string # Array of maps +``` + +### Maps + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + labels: + type: object + additionalProperties: + type: string # Map with string values + ports: + type: object + additionalProperties: + type: integer # Map with integer values + settings: + type: object + additionalProperties: + type: boolean # Map with boolean values +``` + +### Objects + +For structured objects, use nested `properties`: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + database: + type: object + properties: + host: + type: string + port: + type: integer + default: 5432 + username: + type: string + password: + type: string + options: + type: object + properties: + ssl: + type: boolean + default: true + timeout: + type: integer + default: 30 +``` + +## Defaults + +All fields are **required by default**. To make a field optional, provide a `default` value. + +### Primitives, Arrays, and Maps + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + # Required - must provide value + name: + type: string + tags: + type: array + items: + type: string + + # Optional - have explicit defaults + replicas: + type: integer + default: 1 + optionalTags: + type: array + items: + type: string + default: [] + labels: + type: object + additionalProperties: + type: string + default: {} +``` + +### Objects + +Objects are required unless they have a `default`. Provide a default at the object level: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + # Optional: all fields have defaults, object defaults to empty + monitoring: + type: object + default: {} + properties: + enabled: + type: boolean + default: false + port: + type: integer + default: 9090 + + # Optional: default provides required host field + database: + type: object + default: + host: "localhost" + properties: + host: + type: string + port: + type: integer + default: 5432 +``` + +### Default Precedence + +When an object is **not provided**, the object default is used, then field-level defaults apply to missing fields: + +```yaml +# Schema +parameters: + openAPIV3Schema: + type: object + properties: + database: + type: object + default: + host: "localhost" + properties: + host: + type: string + port: + type: integer + default: 5432 +# Input: parameters: {} +# Result: database = {host: "localhost", port: 5432} +``` + +When an object **is provided**, the object default is ignored and field-level defaults apply: + +```yaml +# Input: parameters: {database: {host: "production-db"}} +# Result: database = {host: "production-db", port: 5432} +``` + +:::note Why explicit defaults are required +Objects are required unless you explicitly provide a default—even when all nested fields have defaults. This is intentional: + +- **Predictable**: You can tell if an object is optional by checking for a default, without inspecting nested fields +- **Safe evolution**: When you add a required field to an object, the existing `default: {}` fails validation, alerting you to update it. Without explicit defaults, the object would silently become required, breaking existing Components. +- **Clear intent**: `default: {}` signals that the entire configuration block is optional + ::: + +## Constraint Markers + +Standard JSON Schema validation keywords are used directly as properties. + +### Validation Constraints + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + # Strings + username: + type: string + minLength: 3 + maxLength: 20 + pattern: "^[a-z][a-z0-9_]*$" + email: + type: string + format: email + + # Numbers + age: + type: integer + minimum: 0 + maximum: 150 + price: + type: number + minimum: 0 + exclusiveMinimum: true + multipleOf: 0.01 + + # Arrays + tags: + type: array + items: + type: string + minItems: 1 + maxItems: 10 + uniqueItems: true +``` + +### Enumerations + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + environment: + type: string + enum: + - development + - staging + - production + logLevel: + type: string + enum: + - debug + - info + - warning + - error + default: info +``` + +### Documentation + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + apiKey: + type: string + title: "API Key" + description: "Authentication key for external service" + example: "sk-abc123" + timeout: + type: integer + description: "Request timeout in seconds" + default: 30 +``` + +## Custom Annotations + +Add custom metadata using `x-oc-` extension fields. These are ignored during validation but can be used by UI generators and tooling: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + commitHash: + type: string + x-oc-build-inject: "git.sha" + x-oc-ui-hidden: true + advancedTimeout: + type: string + default: "30s" + x-oc-scaffolding: "omit" +``` + +## Schema Evolution + +OpenChoreo schemas allow additional properties beyond what's defined, enabling safe schema evolution: + +- **Development**: Add fields to Component before updating ComponentType schema +- **Promotion**: Add new `environmentConfigs` in target environment before promoting +- **Rollback**: Rolling back works - extra fields are simply ignored +- **Safety**: Unknown fields don't cause failures + +```yaml +# Environment prepared for promotion +environmentConfigs: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 2 + monitoring: + type: string + default: "enabled" # Added before new Release arrives +``` + +## Complete Example + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: web-service + namespace: default +spec: + workloadType: deployment + + # Traits that can be applied to components of this type + allowedTraits: + - kind: Trait + name: persistent-volume + - kind: Trait + name: autoscaler + - kind: Trait + name: monitoring + + parameters: + openAPIV3Schema: + type: object + properties: + # Optional parameters with defaults + replicas: + type: integer + default: 1 + minimum: 1 + maximum: 100 + serviceType: + type: string + enum: + - ClusterIP + - NodePort + - LoadBalancer + default: ClusterIP + + # Nested optional objects + livenessProbe: + type: object + default: {} + properties: + path: + type: string + default: "/healthz" + port: + type: integer + default: 8080 + initialDelaySeconds: + type: integer + default: 0 + periodSeconds: + type: integer + default: 10 + readinessProbe: + type: object + default: {} + properties: + path: + type: string + default: "/healthz" + port: + type: integer + default: 8080 + initialDelaySeconds: + type: integer + default: 0 + periodSeconds: + type: integer + default: 10 + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + resources: + type: object + default: {} + properties: + cpu: + type: string + default: "100m" + memory: + type: string + default: "256Mi" + replicas: + type: integer + default: 1 + + # Validation rules for cross-field validation + validations: + - rule: ${size(workload.endpoints) > 0} + message: "Service components must expose at least one endpoint" + + resources: + # Primary workload - id must match workloadType + - id: deployment + template: + # ... uses ${workload.endpoints}, ${environmentConfigs.resources.cpu}, etc. +``` + +## Related Resources + +- [Templating Syntax](./templating-syntax.md) - Using parameters in templates +- [Patching Syntax](./patching-syntax.md) - JSON Patch operations for Traits +- [Validation Rules](./validation-rules.md) - CEL-based semantic validation +- [ComponentType API Reference](../../reference/api/platform/componenttype.md) - Full CRD specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/templating-syntax.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/templating-syntax.md new file mode 100644 index 00000000..2bc24a77 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/templating-syntax.md @@ -0,0 +1,383 @@ +--- +title: Templating Syntax +description: CEL expression syntax for dynamic resource generation in ComponentTypes and Traits +--- + +# Templating Syntax + +This guide covers the OpenChoreo templating system for dynamic resource generation in ComponentTypes and Traits. + +## Overview + +OpenChoreo's templating system enables dynamic configuration through expressions embedded in YAML/JSON structures. Expressions are enclosed in `${}` and evaluated using [CEL (Common Expression Language)](https://github.com/google/cel-spec). + +CEL expressions can be used in: + +- **Resource templates** (`template:` in ComponentType `resources[]` or Trait `creates[]`) - complete Kubernetes resources with embedded expressions +- **Patch values** (`value:` in Trait `patches[]`) - primitives, objects, or nested structures +- **Resource control fields** (`includeWhen`, `forEach`) - entire field value is a CEL expression + +```yaml +resources: + - id: deployment + includeWhen: ${parameters.enabled} # Resource control - entire CEL expression + forEach: ${parameters.instances} # Resource control - entire CEL expression + template: # Resource template + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} # Embedded expression + spec: + replicas: ${parameters.replicas} + +patches: + - target: + kind: Deployment + operations: + - op: add + path: /metadata/labels/app + value: ${metadata.name} # Patch value - primitive + - op: add + path: /spec/template/spec/volumes/- + value: # Patch value - object + name: ${parameters.volumeName} + emptyDir: {} +``` + +**Key components:** + +- **Template Syntax**: Where expressions can be used and how to control resource generation +- **CEL Expression Language**: What you can write inside `${}` +- **[Built-in Functions](../../reference/cel/built-in-functions.md)**: OpenChoreo-provided functions like `oc_omit()`, `oc_merge()`, and `oc_generate_name()` +- **[Context Variables](../../reference/cel/context-variables.md)**: Variables providing access to metadata, parameters, workload, and configurations + +## Template Syntax + +This section covers where expressions can be used and how to control resource generation. + +### Expression Formats + +Expressions can appear in three formats within templates: + +#### Standalone Value + +When an expression is the entire value, it preserves the original data type. + +```yaml +# Returns an integer +replicas: ${parameters.replicas} + +# Returns a map +labels: ${metadata.labels} + +# Returns a boolean +enabled: ${has(parameters.feature) ? parameters.feature : false} + +# Returns a list +volumes: ${parameters.volumes} + +# Complex expression with block scalar (avoids quoting issues) +nodeSelector: | + ${parameters.highPerformance ? {"node-type": "compute"} : {"node-type": "standard"}} +``` + +#### String Interpolation + +When an expression is embedded within a string, it is converted to a string and interpolated. + +```yaml +# Multiple expressions in a string +message: "Application ${metadata.name} has ${parameters.replicas} replicas" + +# URL construction +url: "https://${metadata.name}.${metadata.namespace}.svc.cluster.local:${parameters.port}" + +# Image tag +image: "${parameters.registry}/${parameters.repository}:${parameters.tag}" +``` + +#### Dynamic Map Keys + +Map keys can be dynamically generated (must evaluate to strings). + +```yaml +# Dynamic labels based on component name +labels: + ${metadata.name}: active + ${metadata.name + "-metrics"}: enabled + +# Dynamic labels with parameters +labels: + ${'app.kubernetes.io/' + metadata.name}: active + ${parameters.labelPrefix + '/version'}: ${parameters.version} +``` + +### Resource Control Fields + +These fields control resource generation in ComponentTypes and Traits. They use CEL expressions to determine which resources to generate. + +#### includeWhen + +Controls whether a resource is included based on a CEL expression: + +```yaml +resources: + # Only create HPA if auto-scaling is enabled + - id: hpa + includeWhen: ${parameters.autoscaling.enabled} + template: + apiVersion: autoscaling/v2 + kind: HorizontalPodAutoscaler + # ... + + # Create PDB only for production with multiple replicas + - id: pdb + includeWhen: ${parameters.environment == "production" && parameters.replicas > 1} + template: + apiVersion: policy/v1 + kind: PodDisruptionBudget + # ... +``` + +#### forEach + +Generates multiple resources from a list or map: + +```yaml +resources: + # Generate ConfigMaps for each database + - id: db-config + forEach: ${parameters.databases} + var: db + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${oc_generate_name(metadata.name, db.name, "config")} + data: + host: ${db.host} + port: ${string(db.port)} +``` + +**Iterating over maps** - Each item has `.key` and `.value` fields: + +```yaml +resources: + - id: config + forEach: ${parameters.configFiles} + var: config + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${oc_generate_name(metadata.name, config.key)} + data: + "${config.key}": ${config.value} +``` + +Map keys are iterated in **alphabetical order** for deterministic output. + +#### Filtering Items in forEach + +Use `.filter()` within the forEach expression: + +```yaml +resources: + # Generate secrets only for enabled integrations + - id: secrets + forEach: ${parameters.integrations.filter(i, i.enabled && has(i.credentials))} + var: integration + template: + apiVersion: v1 + kind: Secret + metadata: + name: ${oc_generate_name(metadata.name, integration.name, "secret")} + stringData: + api_key: ${integration.credentials.apiKey} +``` + +#### Combining forEach with includeWhen + +`includeWhen` is evaluated **before** the forEach loop and controls the **entire block**. The loop variable is **not available** in `includeWhen`: + +```yaml +resources: + # CORRECT - includeWhen controls entire forEach block + - includeWhen: ${parameters.createSecrets} + forEach: ${parameters.integrations} + var: integration + template: + # ... + + # WRONG - loop variable not available in includeWhen + - includeWhen: ${integration.enabled} # ERROR: 'integration' doesn't exist yet + forEach: ${parameters.integrations} + var: integration + + # CORRECT - use filter() for item-level filtering + - forEach: ${parameters.integrations.filter(i, i.enabled)} + var: integration + template: + # ... +``` + +## CEL Expression Language + +This section documents what you can write inside `${}` expressions. These are standard CEL and cel-go extension capabilities, documented here for convenience. + +### Map Access + +Both dot notation and bracket notation work for accessing map fields: + +```yaml +# Equivalent for static keys: +${parameters.replicas} +${parameters["replicas"]} +``` + +**Bracket notation is required for:** + +- Dynamic keys: `${parameters.labels[parameters.labelKey]}` +- Keys with special characters: `${resource.metadata.labels["app.kubernetes.io/name"]}` +- Optional access: `${resource.metadata.labels[?"app.kubernetes.io/name"].orValue("")}` + +### Conditional Logic + +```yaml +# Ternary operator with default +serviceType: ${has(parameters.serviceType) ? parameters.serviceType : "ClusterIP"} + +# Minimum value check +replicas: ${parameters.replicas > 0 ? parameters.replicas : 1} + +# Multi-condition logic +nodeSelector: | + ${parameters.highPerformance ? + {"node-type": "compute-optimized"} : + (parameters.costOptimized ? + {"node-type": "spot"} : + {"node-type": "general-purpose"})} +``` + +### Safe Navigation + +```yaml +# Optional chaining with ? for static keys +customValue: ${parameters.?custom.?value.orValue("default")} + +# Optional access with safe navigation +containerConfig: ${configurations.?configs.?envs.orValue([])} + +# Map with optional keys +config: | + ${{"required": parameters.requiredConfig, ?"optional": parameters.?optionalConfig}} +``` + +### Array and List Operations + +```yaml +# Transform list items +env: | + ${parameters.envVars.map(e, {"name": e.key, "value": e.value})} + +# Filter and transform +ports: | + ${parameters.services.filter(s, s.enabled).map(s, {"port": s.port, "name": s.name})} + +# List operations +firstItem: ${parameters.items[0]} +lastItem: ${parameters.items[size(parameters.items) - 1]} +joined: ${parameters.items.join(",")} + +# Sorting +sortedStrings: ${parameters.names.sort()} +sortedByName: ${parameters.items.sortBy(item, item.name)} + +# List concatenation +combined: ${parameters.list1 + parameters.list2} +withInlineItem: ${parameters.userPorts + [{"port": 8080, "name": "http"}]} + +# Flatten nested lists +flattened: ${[[1, 2], [3, 4]].flatten()} # returns [1, 2, 3, 4] + +# Wrap the single workload container in a list +containerList: | + ${[{"name": "main", "image": workload.container.image}]} +``` + +### Map Operations + +```yaml +# Transform list to map with dynamic keys +envMap: | + ${parameters.envVars.transformMapEntry(i, v, {v.name: v.value})} + +# Map transformation (map to map) +labelMap: | + ${parameters.labels.transformMap(k, v, {"app/" + k: v})} +``` + +### String Operations + +```yaml +uppercaseName: ${metadata.name.upperAscii()} +trimmedValue: ${parameters.value.trim()} +replaced: ${parameters.text.replace("old", "new")} +prefixed: ${parameters.value.startsWith("prefix")} + +# Split string into list +parts: ${parameters.path.split("/")} +limited: ${parameters.text.split(",", 2)} # "a,b,c" → ["a", "b,c"] + +# Extract substring +suffix: ${parameters.name.substring(4)} # "hello-world" → "o-world" +middle: ${parameters.name.substring(0, 5)} # "hello-world" → "hello" +``` + +### Math Operations + +```yaml +maxValue: ${math.greatest([parameters.min, parameters.max, parameters.default])} +minValue: ${math.least([parameters.v1, parameters.v2, parameters.v3])} +rounded: ${math.ceil(parameters.floatValue)} +``` + +### Encoding Operations + +```yaml +# Base64 encode (convert to bytes first) +encoded: ${base64.encode(bytes(parameters.value))} + +# Base64 decode to string +decoded: ${string(base64.decode(parameters.encodedValue))} +``` + +### Built-in Functions + +OpenChoreo provides built-in CEL functions for common operations: + +- `oc_omit()` - Remove fields conditionally from output +- `oc_merge()` - Shallow merge maps +- `oc_generate_name()` - Generate Kubernetes-safe names with hash suffix +- `oc_dns_label()` - Generate DNS-compliant labels from component context +- `oc_hash()` - Generate hash from string + +See the [Built-in Functions Reference](../../reference/cel/built-in-functions.md) for complete documentation and examples. + +### Context Variables + +Templates have access to context variables that provide component metadata, parameters, workload specifications, and platform configuration. + +**ComponentType variables:** `metadata`, `parameters`, `environmentConfigs`, `workload`, `configurations`, `dataplane` + +**Trait variables:** All ComponentType variables plus `trait.name` and `trait.instanceName` + +See the [Context Variables Reference](../../reference/cel/context-variables.md) for complete documentation of all available fields. + +## Related Resources + +- [Schema Syntax](./schema-syntax.md) - Parameter validation and defaults +- [Patching Syntax](./patching-syntax.md) - JSON Patch operations for Traits +- [Context Variables](../../reference/cel/context-variables.md) - Variables available in templates +- [Built-in Functions](../../reference/cel/built-in-functions.md) - OpenChoreo CEL functions +- [Configuration Helpers](../../reference/cel/helper-functions.md) - Helper functions for configurations diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/validation-rules.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/validation-rules.md new file mode 100644 index 00000000..93bb4b48 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/component-types/validation-rules.md @@ -0,0 +1,540 @@ +--- +title: Validation Rules +description: CEL-based validation rules for ComponentTypes and Traits +--- + +# Validation Rules + +This guide explains how to define CEL-based validation rules for ComponentTypes and Traits to enforce semantic constraints and cross-field relationships beyond basic schema validation. + +## Overview + +Validation rules complement schema validation by enabling: + +- **Cross-field relationships** - Validate that multiple fields work together correctly +- **Domain-specific invariants** - Enforce business logic constraints +- **Rendering context validation** - Check parameters against the workload, dataplane, and environment configuration resolved for the target environment +- **Rendered output invariants** - Assert that a guarantee still holds on the final rendered resources after all traits are applied +- **Custom error messages** - Provide clear, actionable feedback when validation fails + +Validation rules use CEL expressions wrapped in `${}` that must evaluate to `true` for validation to pass. + +Validations run in two stages. Both stages are available on ComponentTypes and Traits (and their Cluster-scoped variants): + +| | [Pre-render](#pre-render-validations) (`preRenderValidations`) | [Post-render](#post-render-validations) (`postRenderValidations`) | +| --------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------- | +| Runs | Before rendering | After all traits are applied | +| Evaluates against | Static configuration (`parameters`, `environmentConfigs`, `workload`, ...) | The final rendered Kubernetes resources | +| Rule shape | `rule` + `message` | `target` selection + `rule` + `message`, with optional `when` / `forEach` | +| `${...}` in `message` | Interpolated | Not interpolated (shown literally) | +| Typical use | "These parameters are consistent" | "No trait undid my guarantee" | + +:::warning ComponentTypes and Traits are environment-agnostic +A ComponentType or Trait is a reusable definition applied across **every** environment, so validation rules must never hard-code environment names (`"production"`, `"staging"`, ...) — the same definition has to work regardless of how a platform names its environments. To vary behavior per environment, expose the varying value or toggle in `environmentConfigs` and let the platform set it per environment via the `ReleaseBinding`. Write rules that check **relationships and overrides**, not environment-name string comparisons. +::: + +## Context Variables in Validations + +Validation rules have access to different context variables depending on scope: + +### ComponentType Context + +- `metadata` - Component metadata (`componentName`, `componentNamespace`, `environmentName`, labels, etc.). The environment name is present, but don't branch on it — see the warning above +- `parameters` - Component parameters with schema defaults applied +- `environmentConfigs` - Environment-specific parameter overrides (from the `ReleaseBinding`) +- `workload` - Workload specification (container, endpoints, workloadType) +- `configurations` - Configuration and secret references +- `dataplane` - DataPlane configuration (secretStore, gateway, etc.) +- `gateway` - Ingress gateway resolved for the environment (`gateway.ingress.external` / `internal`) +- `environment` - Environment-specific configuration (gateway overrides, `defaultNotificationChannel`) +- `dependencies` - Resolved endpoint connections and resource dependencies + +### Trait Context + +All ComponentType variables plus: + +- `trait.name` - Name of the trait type +- `trait.instanceName` - Unique instance name for this trait within the component + +### Post-render Context + +Post-render rules evaluate with the declaring resource's own context (the same variables listed above), plus: + +- `resource` - The rendered Kubernetes resource matched by the validation's `target` (bound per match, available in `target.where` and `rule`) + +## Pre-render Validations + +Pre-render rules (`spec.preRenderValidations`) run against static configuration after schema defaults are applied, before any resource is rendered. + +### Rule Format + +Each pre-render validation rule consists of two required fields: + +```yaml +preRenderValidations: + - rule: ${parameters.replicas >= 1} + message: "replicas must be at least 1" + - rule: ${parameters.port > 0 && parameters.port <= 65535} + message: "port must be between 1 and 65535" +``` + +| Field | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------------- | +| `rule` | string | Yes | CEL expression wrapped in `${...}` that must evaluate to true | +| `message` | string | Yes | Error message shown when the rule evaluates to false | + +:::note `validations` is deprecated +`spec.validations` is a deprecated alias for `spec.preRenderValidations` with identical shape and semantics. Set only one of the two — specifying both on the same resource is rejected at admission time. +::: + +### ComponentType Examples + +#### Cross-field parameter validation + +Use validation rules for cross-field relationships that a schema alone can't express. This `web-service` type exposes an `autoscaling` range as parameters and checks that the range is internally consistent: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: web-service +spec: + workloadType: deployment + parameters: + openAPIV3Schema: + type: object + properties: + port: + type: integer + minimum: 1 + maximum: 65535 + autoscaling: + type: object + # default: {} makes the nested defaults apply even when the + # developer omits autoscaling entirely, so rules can read the + # fields without has() guards + default: {} + properties: + enabled: + type: boolean + default: false + minReplicas: + type: integer + default: 1 + minimum: 1 + maxReplicas: + type: integer + default: 5 + minimum: 1 + environmentConfigs: + openAPIV3Schema: + type: object + properties: + autoscaling: + type: object + # An environment that overrides the range must set both bounds + required: [minReplicas, maxReplicas] + properties: + minReplicas: + type: integer + minimum: 1 + maxReplicas: + type: integer + minimum: 1 + + preRenderValidations: + # Cross-field parameter check: the autoscaling range must be internally consistent + - rule: ${!parameters.autoscaling.enabled || parameters.autoscaling.maxReplicas >= parameters.autoscaling.minReplicas} + message: "autoscaling.maxReplicas (${parameters.autoscaling.maxReplicas}) must be >= autoscaling.minReplicas (${parameters.autoscaling.minReplicas})" +``` + +#### Validating environment overrides + +To vary behavior per environment, validate the per-environment overrides in `environmentConfigs` — the platform sets these through the `ReleaseBinding`, so the same rule works no matter what an environment is named. + +The rules worth writing here read `parameters` and `environmentConfigs` **together**. The schema validates each one in isolation; only a rule can check that an environment's override makes sense for the component that declared it: + +```yaml +preRenderValidations: + # Cross-object check: an environment may only override the range if the component + # turned autoscaling on. Otherwise the override is silently ignored at render time. + - rule: ${!has(environmentConfigs.autoscaling) || parameters.autoscaling.enabled} + message: "this environment overrides the autoscaling range, but the component has autoscaling disabled" + + # The override itself must stay internally consistent. has() is required here because + # environmentConfigs.autoscaling has no `default: {}` — it is genuinely absent in + # environments that don't override the range, unlike parameters.autoscaling above. + - rule: ${!has(environmentConfigs.autoscaling) || environmentConfigs.autoscaling.maxReplicas >= environmentConfigs.autoscaling.minReplicas} + message: "this environment's autoscaling override must keep maxReplicas (${environmentConfigs.autoscaling.maxReplicas}) >= minReplicas (${environmentConfigs.autoscaling.minReplicas})" +``` + +Because the schema requires both bounds whenever the override is present, a single `has()` on the object is enough — no per-field guards. The same holds for the other static-config variables listed in [Context Variables](#context-variables-in-validations): `workload`, `dataplane`, `gateway`, and `dependencies` are all in scope here and can be combined the same way. + +#### Workload-based validation + +These rules constrain the workload and relate endpoint visibility to the ingress resolved for the environment via the `gateway` context — never to an environment name: + +```yaml +preRenderValidations: + # A service must expose at least one endpoint + - rule: ${size(workload.endpoints) > 0} + message: "Service components must have at least one endpoint. Use 'deployment/worker' for components without endpoints." + + # Restrict the allowed endpoint types + - rule: ${workload.endpoints.all(name, ep, ep.type == "HTTP")} + message: "This component only supports endpoints of type HTTP." + + # Endpoints exposed externally need an external ingress on the Environment or DataPlane. + # gateway is resolved per environment, so this holds for every environment. + - rule: >- + ${workload.endpoints.exists(name, ep, "external" in ep.visibility) + ? has(gateway.ingress) && has(gateway.ingress.external) + : true} + message: "Endpoints with 'external' visibility require gateway.ingress.external to be configured on the Environment or DataPlane." +``` + +### Trait Examples + +#### Parameter validation + +Prefer the schema for shape constraints — required fields, lengths, patterns, enums all belong there. Use rules for what the schema can't express: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: persistent-volume +spec: + parameters: + openAPIV3Schema: + type: object + required: [volumeName, mountPath] + properties: + volumeName: + type: string + maxLength: 63 + mountPath: + type: string + pattern: "^/" + accessMode: + type: string + enum: [ReadWriteOnce, ReadOnlyMany, ReadWriteMany] + default: ReadWriteOnce + + preRenderValidations: + # A blacklist the schema can't express: block mounts over system temp directories, + # including anything nested beneath them (/tmp/cache, /var/tmp/build/out, ...) + - rule: ${!["/tmp", "/var/tmp"].exists(d, parameters.mountPath == d || parameters.mountPath.startsWith(d + "/"))} + message: "Cannot mount volumes to system temp directories /tmp or /var/tmp" +``` + +#### Workload-aware validation + +```yaml +preRenderValidations: + # Validate access modes for different workload types + - rule: ${parameters.accessMode == "ReadWriteOnce" || workload.workloadType == "statefulset"} + message: "ReadWriteMany and ReadOnlyMany access modes are only supported for StatefulSet workloads" + + # Ensure container exists for volume mounts + - rule: ${!has(parameters.containerName) || has(workload.container)} + message: "Cannot mount volume: no container found in workload" + + # Validate trait instance naming + - rule: ${trait.instanceName.matches("^[a-z]([a-z0-9-]*[a-z0-9])?$")} + message: "Trait instanceName must be lowercase DNS-compliant: start/end with alphanumeric, contain only lowercase letters, numbers, and hyphens" +``` + +### Common Patterns + +#### Context-aware checks + +```yaml +preRenderValidations: + # Access component metadata + - rule: ${size(metadata.componentName) <= 63} + message: "Component name must be 63 characters or less for DNS compatibility" + + # Check dataplane capabilities + - rule: ${!parameters.externalAccess || has(dataplane.publicVirtualHost)} + message: "External access requires publicVirtualHost configuration in the dataplane" + + # Validate against workload container + - rule: ${!has(parameters.containerPort) || parameters.containerPort == workload.container.port} + message: "Container port parameter must match workload container configuration" +``` + +#### List and map validation + +```yaml +preRenderValidations: + # Validate all items in a list + - rule: ${!has(parameters.databases) || parameters.databases.all(db, has(db.host) && has(db.port) && db.port > 0)} + message: "All databases must have valid host and port configuration" + + # Check for required keys in maps + - rule: ${!has(parameters.secrets) || parameters.secrets.all(name, secret, has(secret.key))} + message: "All secrets must specify a key field" + + # Validate uniqueness + - rule: ${!has(parameters.endpoints) || size(parameters.endpoints) == size(parameters.endpoints.map(ep, ep.name).distinct())} + message: "Endpoint names must be unique" +``` + +#### Conditional validation + +```yaml +preRenderValidations: + # Conditional requirements based on features. + # ssl is an optional object, so guard it with has() before reading enabled — + # an object without `default: {}` in the schema is absent, not empty. + - rule: ${!has(parameters.ssl) || !parameters.ssl.enabled || (has(parameters.ssl.certSecret) && has(parameters.ssl.keySecret))} + message: "SSL enabled requires both certificate and key secrets" + + # Conditional requirement driven by a component parameter (author intent), not an environment name + - rule: ${!parameters.highAvailability || (parameters.replicas >= 2 && has(environmentConfigs.resources) && has(environmentConfigs.resources.limits))} + message: "highAvailability requires >=2 replicas and resource limits" + + # Mutually exclusive options + - rule: ${[has(parameters.basicAuth), has(parameters.oauth)].filter(x, x).size() <= 1} + message: "Cannot enable both basicAuth and oauth authentication" +``` + +## Post-render Validations + +Pre-render rules see only static configuration — they cannot check what the rendering pipeline actually produced. Traits stack: each one can create, patch, or remove resources, so a guarantee established by the ComponentType or an earlier trait can be silently undone by a later one. `postRenderValidations` close this gap. They are CEL rules evaluated **after all traits are applied**, against the final rendered Kubernetes resources. + +Post-render rules see the rendered manifests exactly as the traits produced them: no Kubernetes server-side defaulting or admission mutation has been applied, and OpenChoreo's own labels and owner references are not yet injected. A field the cluster would default (like `spec.replicas`) may simply be absent — guard reads with `has()`. + +Each entry selects rendered resources by GVK (plus an optional `where` filter), binds each match to the `resource` variable, and requires `rule` to evaluate to `true`: + +| Field | Required | Description | +| ------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `when` | No | CEL guard evaluated against the trait/component context; if it evaluates to `false`, the validation is skipped | +| `forEach` / `var` | No | Repeats the validation per item of a CEL-evaluated list; `var` names the loop variable (in scope for `target.where` and `rule`) | +| `target.group` / `.version` / `.kind` | Yes | GVK of the rendered resources to select | +| `target.where` | No | CEL filter over the selected resources, with `resource` bound | +| `target.mustMatch` | No | Defaults to `true`: when no rendered resource matches the target, the validation fails | +| `targetPlane` | No | `dataplane` (default) or `observabilityplane` | +| `rule` | Yes | CEL expression wrapped in `${...}`, evaluated with `resource` bound to each match; must evaluate to `true` | +| `message` | Yes | Error message shown when the rule fails (a literal string — `${...}` interpolation is not applied) | + +A storage trait shows why this stage exists. With `accessMode: ReadWriteOnce`, the volume can only be attached to a single node, so the platform team's policy is to pin such workloads to a single replica. The trait can't enforce that on its own configuration: it neither renders nor patches `replicas` — the final value is the cumulative result of the ComponentType template and every other trait in the stack. Only the final rendered Deployment can answer whether the policy holds: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: single-writer-pvc +spec: + parameters: + openAPIV3Schema: + type: object + properties: + accessMode: + type: string + enum: [ReadWriteOnce, ReadWriteMany] + default: ReadWriteOnce + + postRenderValidations: + - when: ${parameters.accessMode == 'ReadWriteOnce'} + target: + group: apps + version: v1 + kind: Deployment + # replicas may be absent from the rendered manifest, in which case + # Kubernetes defaults it to 1 — so absence passes + rule: ${!has(resource.spec.replicas) || resource.spec.replicas <= 1} + message: "ReadWriteOnce volume requires a single replica for exclusive write access" +``` + +If an HA trait anywhere in the stack patched `replicas: 3`, this rule sees the final value and fails the release with the message above — nothing from this release is deployed. + +`mustMatch` defaults to `true`, so a target that matches zero rendered resources fails the validation. This catches the case where a later trait removed the resource entirely; set `mustMatch: false` only when the target is genuinely optional. + +ComponentTypes support `postRenderValidations` with the same field shape and semantics. The only difference is that `when`, `forEach`, and `rule` bind the component context (`parameters`, `environmentConfigs`, ...) instead of a trait's. A ComponentType author can use this to assert that invariants it rendered — a hardened `securityContext`, resource limits — survived the whole trait stack. + +## Validation Execution and Error Handling + +### Execution Order + +1. **Schema validation** - Type checking and constraint validation happens first +2. **Default application** - Schema defaults are applied to parameters and environmentConfigs +3. **Pre-render rule evaluation** - `preRenderValidations` (or the deprecated `validations`) are evaluated against the static context: the ComponentType's rules first, then each trait's rules just before that trait is applied +4. **Rendering** - Base resources are rendered from the ComponentType templates, then each trait's creates, patches, and removes are applied in order +5. **Post-render rule evaluation** - `postRenderValidations` from the ComponentType and every trait are evaluated against the final rendered resources, and failures from all of them are aggregated + +A failure at any stage stops the pipeline — later stages don't run — and the release is not deployed. Failures within the same rule list are collected and reported together rather than stopping at the first. + +### Error Message Format + +When validation fails, OpenChoreo provides structured error messages: + +``` +rule[0] "${parameters.replicas >= 1}" evaluated to false: replicas must be at least 1 +``` + +Multiple failures are joined with `; `: + +``` +rule[0] "${parameters.replicas >= 1}" evaluated to false: replicas must be at least 1; rule[1] "${parameters.port > 0}" evaluated to false: port must be greater than 0 +``` + +Post-render failures are aggregated the same way, across all matched resources and every declaring ComponentType and trait. Unlike pre-render messages, `${...}` inside a post-render `message` is **not** interpolated — it is shown literally. When a `forEach` iteration fails, the aggregated error already identifies the failing item, so you don't need to embed it in the message. + +### Best Practices for Error Messages + +Interpolating context values into `message` (as below) works for **pre-render** rules only: + +```yaml +preRenderValidations: + # Bad - unclear and not actionable + - rule: ${parameters.value > 0} + message: "Invalid value" + + # Good - specific and actionable + - rule: ${parameters.replicas > 0 && parameters.replicas <= 20} + message: "replicas must be between 1 and 20. Current value: ${parameters.replicas}" + + # Good - includes context and guidance + - rule: ${!parameters.highAvailability || parameters.replicas >= 3} + message: "High availability mode requires at least 3 replicas. Set replicas >= 3 or disable highAvailability." + + # Good - references documentation + - rule: ${parameters.storageClass in ["standard", "ssd", "premium"]} + message: "storageClass '${parameters.storageClass}' is not supported. Allowed values: standard, ssd, premium. See: https://docs.example.com/storage" +``` + +## Testing Validation Rules + +### Testing pre-render rules across environments + +Validation rules that read `environmentConfigs` run at render time, once the per-environment overrides from the `ReleaseBinding` are applied — not on the bare `Component`. So the same Component can pass in one environment and fail in another. Define one Component, then bind it to environments whose `autoscaling` overrides differ: + +```yaml +# The component is static and identical across every environment +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: test-web-service +spec: + componentType: + kind: ComponentType + name: deployment/web-service + parameters: + port: 8080 + autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 5 +``` + +The environment-specific autoscaling range comes from the `ReleaseBinding`, not the Component: + +```yaml +# Development: no override, so the override-consistency rule passes vacuously +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: test-web-service-development +spec: + owner: + projectName: default + componentName: test-web-service + environment: development + releaseName: test-web-service-v1 + # componentTypeEnvironmentConfigs omitted -> has(environmentConfigs.autoscaling) is false, rule passes + +--- +# Staging: overrides the range inconsistently (maxReplicas < minReplicas), so this environment FAILS +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: test-web-service-staging +spec: + owner: + projectName: default + componentName: test-web-service + environment: staging + releaseName: test-web-service-v1 + componentTypeEnvironmentConfigs: + autoscaling: + minReplicas: 8 + maxReplicas: 4 # maxReplicas < minReplicas -> validation fails for this environment +``` + +Validation is driven entirely by the target environment's overrides — no environment name is baked into the ComponentType or the Component. + +### Testing post-render rules + +Post-render rules are exercised by attaching a trait that breaks the invariant. With the `single-writer-pvc` trait from [Post-render Validations](#post-render-validations) attached, adding an HA trait that patches the replica count makes the rule fail against the final rendered Deployment — regardless of the order the traits appear in: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: test-single-writer +spec: + componentType: + kind: ComponentType + name: deployment/web-service + parameters: + port: 8080 + traits: + - kind: Trait + name: single-writer-pvc + instanceName: data-volume + # accessMode defaults to ReadWriteOnce -> the post-render rule is active + - kind: Trait + name: high-availability + instanceName: ha + parameters: + replicas: 3 # patches the Deployment -> final replicas is 3, rule fails +``` + +The failure surfaces only once the component is bound to an environment, because rendering happens per environment. Unlike the pre-render case above, no override is needed to trigger it — the conflict is between the two traits, so every environment fails identically: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: test-single-writer-development +spec: + owner: + projectName: default + componentName: test-single-writer + environment: development + releaseName: test-single-writer-v1 + # No componentTypeEnvironmentConfigs needed: the autoscaling override is optional, + # and the post-render failure comes from the trait stack, not from an override +``` + +The `ReleaseBinding` status reports the post-render failure and nothing from the release is deployed. + +### Verification Commands + +```bash +# Apply the pre-render example (component + per-environment bindings) +kubectl apply -f test-web-service.yaml + +# Apply the post-render example (component with conflicting traits + its binding) +kubectl apply -f test-single-writer.yaml + +# Check binding status for validation failures +kubectl get releasebindings -o wide + +# View detailed error messages for the failing pre-render environment +kubectl describe releasebinding test-web-service-staging + +# View the post-render failure (the single-replica rule broken by the HA trait) +kubectl describe releasebinding test-single-writer-development +``` + +## Related Resources + +- [Templating Syntax](./templating-syntax.md) - CEL expressions and context variables +- [Schema Syntax](./schema-syntax.md) - Parameter validation and constraints +- [Overview](./overview.md) - ComponentTypes and Traits fundamentals +- [Context Variables](../../reference/cel/context-variables.md) - Complete context reference +- [ComponentType API](../../reference/api/platform/componenttype.md) - Full API specification +- [Trait API](../../reference/api/platform/trait.md) - Full API specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/container-registry-configuration.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/container-registry-configuration.mdx new file mode 100644 index 00000000..2e51338c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/container-registry-configuration.mdx @@ -0,0 +1,201 @@ +--- +title: Container Registry Configuration +description: Configure the Workflow Plane to push images to your container registry. +sidebar_position: 3 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Container Registry Configuration + +The Workflow Plane requires a container registry to store built images. Both build pods (for pushing) and kubelets on the Data Plane (for pulling) need access to the registry. + +Registry configuration lives in the `publish-image` ClusterWorkflowTemplate, not in Helm values. To use a different registry, replace the `publish-image` CWT with one that has your registry endpoint and TLS settings baked in. + +## Replacing the Publish Step + +Create a custom `publish-image` CWT with your registry endpoint: + +```bash +kubectl apply -f - < /etc/containers/storage.conf + [storage] + driver = "overlay" + runroot = "/run/containers/storage" + graphroot = "/var/lib/containers/storage" + [storage.options.overlay] + mount_program = "/usr/bin/fuse-overlayfs" + CONF + + podman load -i /mnt/vol/app-image.tar + podman tag \$SRC_IMAGE \$REGISTRY_ENDPOINT/\$SRC_IMAGE + + if [ -f "\$AUTH_FILE" ]; then + podman push --tls-verify=true --authfile "\$AUTH_FILE" \$REGISTRY_ENDPOINT/\$SRC_IMAGE + else + podman push --tls-verify=true \$REGISTRY_ENDPOINT/\$SRC_IMAGE + fi + + echo -n "\$REGISTRY_ENDPOINT/\$SRC_IMAGE" > /tmp/image.txt + securityContext: + privileged: true + volumeMounts: + - mountPath: /mnt/vol + name: workspace + - mountPath: /etc/secrets/registry-push-secret + name: registry-push-secret + readOnly: true +EOF +``` + +Replace `YOUR_REGISTRY_HOST/YOUR_REPO_PATH` with your registry endpoint and adjust `--tls-verify` as needed. + +## Registry Providers + +Below are the `REGISTRY_ENDPOINT` values to use in the CWT above for common providers. + +### Amazon ECR + +See [Amazon ECR documentation](https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html) for repository setup and IAM configuration. + +``` +REGISTRY_ENDPOINT="123456789.dkr.ecr.us-east-1.amazonaws.com/openchoreo-builds" +``` + +### Google Artifact Registry + +See [Artifact Registry documentation](https://cloud.google.com/artifact-registry/docs/docker/store-docker-container-images) for repository setup and authentication. + +``` +REGISTRY_ENDPOINT="us-central1-docker.pkg.dev/my-project/openchoreo-builds" +``` + +### Azure Container Registry + +See [ACR documentation](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-get-started-azure-cli) for registry setup and AKS integration. + +``` +REGISTRY_ENDPOINT="myregistry.azurecr.io" +``` + +### GitHub Container Registry + +See [GHCR documentation](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) for authentication setup. + +``` +REGISTRY_ENDPOINT="ghcr.io/my-org/openchoreo" +``` + +### Docker Hub + +See [Docker Hub documentation](https://docs.docker.com/docker-hub/repos/create/) for repository setup. Note the [rate limits](https://docs.docker.com/docker-hub/download-rate-limit/) for free accounts. + +``` +REGISTRY_ENDPOINT="docker.io/your-username" +``` + +## Authentication + +### Push Secret (Workflow Plane) + +For registries requiring authentication, configure push credentials for the workflow plane. + +### Step 1: Encode Your Credentials + +Generate base64-encoded credentials: + +```bash +echo -n 'your-username:your-password' | base64 +``` + +**Example output:** `ZGVtby11c2VyOmRlbW8tcGFzcw==` + +### Step 2: Create Docker Config JSON + +Use the following format with escaped quotes (required for kubectl). Replace placeholders: + +- ``: Your registry host +- ``: Your base64 string from Step 1 + +**Template:** + +``` +{\"auths\":{\"\":{\"auth\":\"\"}}} +``` + +### Step 3: Store in Your Secret Backend + +Write the Docker config JSON to your secret backend with the key `registry-push-secret`. + +**OpenBao (default for local dev):** + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/registry-push-secret \ + value="{\"auths\":{\"\":{\"auth\":\"\"}}}" +' +``` + +**Complete example for Docker Hub:** + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/registry-push-secret \ + value="{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"ZGVtby11c2VyOmRlbW8tcGFzcw==\"}}}" +' +``` + +**Other backends (AWS Secrets Manager, Vault, etc.):** Store the same JSON value under the key `registry-push-secret` in your secret backend. + +### Pull Secret (Data Plane) + +For pulling images from private registries, see [Deploy from a Private Registry](../tutorials/deploy-prebuilt-image.mdx#deploy-from-a-private-registry). + +## Troubleshooting + +| Symptom | Check | +| ----------------------------------------------- | -------------------------------------------------------------- | +| "unauthorized" error | Verify `registry-push-secret` exists and credentials are valid | +| `ImagePullBackOff` | Verify image exists and ImagePullSecret is configured | +| "x509: certificate signed by unknown authority" | Set `tlsVerify=false` or configure CA certificate | +| "connection refused" | Check network connectivity and firewall rules | diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/deployment-topology.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/deployment-topology.mdx new file mode 100644 index 00000000..33e76017 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/deployment-topology.mdx @@ -0,0 +1,462 @@ +--- +title: Deployment Topology +description: Prerequisites and deployment topology for OpenChoreo in production. +sidebar_position: 1 +--- + +# Deployment Topology + +OpenChoreo uses a multi-plane architecture that separates concerns between control, runtime, build, and observability. This guide covers the prerequisites, topology options, and how planes connect. + +## Prerequisites + +Before deploying OpenChoreo to production, ensure your environment meets the following requirements. + +### Kubernetes Cluster + +| Requirement | Specification | +| ------------------ | ------------------------------------------------------------ | +| Kubernetes Version | 1.32 or later | +| Node Count | Minimum 3 nodes (for high availability) | +| Node Resources | 4 CPU cores, 8 GB RAM per node (minimum) | +| RBAC | Enabled | +| LoadBalancer | Required for external access | +| Storage Classes | At least one default StorageClass for PersistentVolumeClaims | + +:::note +For development or testing, a single-node cluster with 8 GB RAM and 4 CPU cores is sufficient. Production deployments should use a multi-node cluster with appropriate resource allocation. +::: + +### Required Tools + +Install the following tools on your workstation: + +| Tool | Version | Notes | +| ---------------------------------------------------------- | ------- | ------------------------------------------------------------- | +| [kubectl](https://kubernetes.io/docs/tasks/tools/) | 1.32+ | Kubernetes CLI | +| [Helm](https://helm.sh/docs/intro/install/) | 3.12+ | Package manager | +| [cert-manager](https://cert-manager.io/docs/installation/) | 1.12+ | Required on all clusters where OpenChoreo planes are deployed | + +### LoadBalancer Requirements + +OpenChoreo services require LoadBalancer with the ability to dynamically assign IPs. In production, each plane exposing services on port 443 needs a separate IP address (since multiple services cannot share the same IP:port combination). + +If only a single IP is available, ports can be customized per service. Refer to the [Helm Charts Reference](../reference/helm/control-plane.mdx) for port configuration options. + +#### IPs and Ports by Plane + +**Control Plane:** + +| Port | Purpose | +| ---- | ----------------------------------------------- | +| 443 | Backstage UI, OpenChoreo API, Identity Provider | +| 80 | HTTP to HTTPS redirect (optional) | + +**Data Plane:** + +| Port | Purpose | +| ---- | --------------------------------------------- | +| 443 | Application endpoints, deployment invocations | +| 80 | HTTP to HTTPS redirect (optional) | + +**Workflow Plane (Optional):** + +- No inbound ports required +- Only outbound connectivity needed (to Control Plane, container registry) + +**Observability Plane (Optional):** + +| Port | Purpose | +| ---- | ---------------------------------------------------------------- | +| 443 | Observability API, SRE Agent (optional), and ingestion endpoints | +| 80 | HTTP to HTTPS redirect (optional) | + +### Domain Requirements + +Each plane requires its own domain(s). These do not need to share a common base domain - configure each independently as needed. + +| Plane | Domains Required | +| ------------------------------ | ------------------------------------------------------------- | +| Control Plane | Console UI domain, API domain, Identity Provider domain | +| Data Plane | Application endpoints domain (wildcard for dynamic apps) | +| Workflow Plane (Optional) | No external domain required | +| Observability Plane (Optional) | Observer, SRE Agent (optional), and ingestion endpoint domain | + +Refer to the [Helm Charts Reference](../reference/helm/control-plane.mdx) for domain configuration options. + +### TLS Certificate Requirements + +| Plane | Certificate Type | Domains | +| ------------------------------ | ----------------------------- | ------------------------------------------------------ | +| Control Plane | Standard (SAN) | Console, API, Identity Provider | +| Data Plane | Wildcard | `*.{apps-domain}` for application endpoints | +| Workflow Plane (Optional) | None required (internal only) | +| Observability Plane (Optional) | Standard | Observer, SRE Agent (optional), and ingestion endpoint | + +Use [cert-manager](https://cert-manager.io/) to automatically provision and renew certificates, or bring your own certificates. + +### Resource Requirements + +#### Control Plane + +| Component | CPU Request | CPU Limit | Memory Request | Memory Limit | +| ------------------ | ----------- | --------- | -------------- | ------------ | +| Backstage | 200m | 2000m | 256Mi | 2Gi | +| OpenChoreo API | 200m | 1000m | 256Mi | 1Gi | +| Controller Manager | 200m | 1000m | 256Mi | 1Gi | +| Cluster Gateway | 100m | 500m | 64Mi | 256Mi | + +#### Data Plane + +| Component | CPU Request | CPU Limit | Memory Request | Memory Limit | +| ------------------- | ----------- | --------- | -------------- | ------------ | +| KGateway Controller | 100m | 200m | 128Mi | 256Mi | +| Cluster Agent | 50m | 100m | 128Mi | 256Mi | + +#### Workflow Plane (Optional) + +| Component | CPU Request | CPU Limit | Memory Request | Memory Limit | +| ------------------------- | ----------- | --------- | -------------- | ------------ | +| Argo Workflows Controller | 25m | 50m | 32Mi | 64Mi | +| Cluster Agent | 50m | 100m | 128Mi | 256Mi | + +#### Observability Plane (Optional) + +| Component | CPU Request | CPU Limit | Memory Request | Memory Limit | +| -------------------- | ----------- | --------- | -------------- | ------------ | +| Observer | 100m | 200m | 128Mi | 200Mi | +| Cluster Agent | 50m | 100m | 128Mi | 256Mi | +| SRE Agent (optional) | 100m | 250m | 1024Mi | 1536Mi | + +For resource requirements of the observability modules, please refer to the [observability modules documentation](https://github.com/openchoreo/community-modules). + +### Storage Requirements + +| Plane | Component | Default Size | +| ------------------- | ----------------------------------------------------------- | ------------ | +| Observability Plane | Observer PVC (Optional -- for alerts and incidents storage) | 128Mi | +| Observability Plane | SRE Agent PVC (Optional -- for RCA reports storage) | 128Mi | + +For storage requirements of the observability modules, please refer to the [observability modules documentation](https://github.com/openchoreo/community-modules). + +### Pre-Installation Checklist + +Before proceeding with installation: + +- [ ] Kubernetes cluster meets version and resource requirements +- [ ] `kubectl` and `helm` are installed and configured +- [ ] LoadBalancer service type is available +- [ ] Storage class is configured for PersistentVolumeClaims +- [ ] Domains are registered and DNS is configurable +- [ ] TLS certificate strategy is determined (cert-manager or bring your own) +- [ ] Network connectivity between clusters is verified (for multi-cluster) +- [ ] Required ports are accessible through firewalls + +## Architecture Overview + +| Plane | Required | Purpose | +| ------------------- | -------- | --------------------------- | +| Control Plane | Yes | Central management, API, UI | +| Data Plane | Yes | Application runtime | +| Workflow Plane | No | CI/CD workflows | +| Observability Plane | No | Logging and monitoring | + +### Resource Hierarchy + +``` +Namespace +├── Project +│ └── references → WorkflowPlane / ClusterWorkflowPlane (optional) +├── Environment +│ └── references → DataPlane / ClusterDataPlane +├── DataPlane +│ └── references → ObservabilityPlane / ClusterObservabilityPlane (optional) +├── WorkflowPlane +│ └── references → ObservabilityPlane / ClusterObservabilityPlane (optional) +└── ObservabilityPlane + +Cluster-Scoped Resources +├── ClusterDataPlane +│ └── references → ObservabilityPlane / ClusterObservabilityPlane (optional) +├── ClusterWorkflowPlane +│ └── references → ObservabilityPlane / ClusterObservabilityPlane (optional) +└── ClusterObservabilityPlane +``` + +### Cluster Agent Connectivity + +OpenChoreo planes communicate via **Cluster Agents** using WebSocket connections. The agent runs in each remote plane and establishes an outbound connection to the Control Plane's Cluster Gateway. + +**Single-Cluster Mode:** +Communication happens via Kubernetes ClusterIP services - no external networking required between planes. + +**Multi-Cluster Mode:** +Each plane's cluster agent connects outbound to the Control Plane. Only the Control Plane needs to be reachable from other clusters. + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Control Plane Cluster │ +│ ┌─────────────────────┐ │ +│ │ Cluster Gateway │ │ +│ │ (wss://:8443) │ │ +│ └──────────▲──────────┘ │ +└───────────────────────────────────┼─────────────────────────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + │ WebSocket │ WebSocket │ WebSocket + │ (outbound) │ (outbound) │ (outbound) + │ │ │ +┌───────────┴───────────┐ ┌─────────┴────────┐ ┌────────────┴────────────────┐ +│ Data Plane Cluster │ │ Workflow Plane │ │ Observability Plane Cluster │ +│ ┌─────────────────┐ │ │ Cluster │ │ (Optional) │ +│ │ Cluster Agent │ │ │ (Optional) │ │ ┌─────────────────┐ │ +│ └─────────────────┘ │ │ ┌─────────────┐ │ │ │ Cluster Agent │ │ +└───────────────────────┘ │ │Cluster Agent│ │ │ └─────────────────┘ │ + │ └─────────────┘ │ └─────────────────────────────┘ + └──────────────────┘ +``` + +## Deployment Workflow (Order of Operations) + +When building your production environment, follow this general sequence to ensure dependencies are met: + +1. **Control Plane Setup**: + - Deploy the `openchoreo-control-plane` chart + - Configure TLS certificates for the Console, API, and IdP + - **Crucial**: Configure the **Cluster Gateway** ingress and certificate - this is the entry point for all other planes + - Apply default resources (project, environments, component types, workflows) from [getting-started samples](https://github.com/openchoreo/openchoreo/tree/main/samples/getting-started) + +2. **Establish Trust** (Multi-Cluster Only): + - Extract the Cluster Gateway CA certificate from the Control Plane + - This CA is required by all other planes to verify the Control Plane's identity + - See [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx) for detailed steps + +3. **Observability Plane (Recommended First)**: + - Deploy the `openchoreo-observability-plane` chart + - Register it with the Control Plane using the `ObservabilityPlane` CRD + - This allows subsequent planes to immediately start sending logs and metrics + +4. **Data Plane(s)**: + - Deploy the `openchoreo-data-plane` chart + - Configure the ingress/gateway for your application workloads (`*.apps.example.com`) + - Register with the Control Plane using the `DataPlane` CRD + - Link to Observability Plane (if deployed) + +5. **Workflow Plane (Optional)**: + - Deploy the `openchoreo-workflow-plane` chart + - Configure the **Container Registry** ingress - this is critical for the Control Plane to read image metadata + - Register with the Control Plane using the `WorkflowPlane` CRD + - Link to Observability Plane (if deployed) + +## Common Topologies + +### Single-Cluster + +All planes run in the same Kubernetes cluster with namespace isolation. Communication happens via Kubernetes ClusterIP services. + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Single Kubernetes Cluster │ +├─────────────────┬─────────────────┬─────────────────────────┤ +│ Control Plane │ Data Plane │ Build & Observability │ +│ Namespace │ Namespace │ Namespaces │ +└─────────────────┴─────────────────┴─────────────────────────┘ +``` + +### Multi-Cluster + +Separate clusters provide isolation and independent scaling. Cluster agents establish outbound WebSocket connections to the Control Plane. + +``` +┌──────────────────┐ ┌──────────────────┐ +│ Control Plane │◀────│ Data Plane │ +│ Cluster │ │ Cluster │ +└────────┬─────────┘ └──────────────────┘ + │ + │ ┌──────────────────┐ + │◀──────────────│ Workflow Plane │ + │ │ Cluster │ + │ └──────────────────┘ + │ + │ ┌──────────────────┐ + └───────────────│ Observability │ + │ Cluster │ + └──────────────────┘ +``` + +### Hybrid (CP + BP + OP Co-located, Remote Data Planes) + +A common production topology: keep the Control Plane, Workflow Plane, and Observability Plane together in one cluster, while running Data Planes in separate clusters (potentially across regions). This reduces operational overhead for infrastructure planes while giving workloads their own isolated clusters. + +``` +┌──────────────────────────────────────────────┐ +│ Management Cluster │ +├──────────────┬───────────────┬───────────────┤ +│ Control Plane│ Workflow Plane │ Observability │ +│ │ │ Plane │ +└──────┬───────┴───────────────┴───────────────┘ + │ + ├────────────────┬────────────────┐ + ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ Data Plane │ │ Data Plane │ │ Data Plane │ +│ (Region A) │ │ (Region B) │ │ (Region C) │ +└──────────────┘ └──────────────┘ └──────────────┘ +``` + +Co-located planes communicate via Kubernetes ClusterIP services (no external networking needed between them). Only the Data Plane clusters need outbound connectivity to the Control Plane's Cluster Gateway. + +For multi-cluster setup instructions, see [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx). + +### Multi-Region + +Central Control Plane with Data Planes across regions. Each Data Plane has a unique gateway ingress host (e.g., `us.apps.example.com`, `eu.apps.example.com`) configured under `gateway.ingress.external.https.host`. + +``` + ┌──────────────────┐ + │ Control Plane │ + │ (Central) │ + └────────┬─────────┘ + │ + ┌───────────────────┼───────────────────┐ + ▼ ▼ ▼ +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Data Plane US │ │ Data Plane EU │ │ Data Plane APAC │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ +``` + +## Plane Resources + +### Namespaces + +Kubernetes **Namespace**s are used to group resources. OpenChoreo resources such as Environment, DataPlane, WorkflowPlane, ObservabilityPlane are created within a namespace. + +OpenChoreo identifies and manages namespaces using the label `openchoreo.dev/control-plane: true`. The control plane discovers namespaces, performs list/get operations, and organizes platform resources based on this label. During installation, a default namespace is automatically created and labeled, enabling immediate use for organizing platform resources. + +**Creating Additional Namespaces** + +To create additional namespaces for organizing resources: + +```bash +kubectl create namespace +kubectl label namespace openchoreo.dev/control-plane=true +``` + +### Environments + +An **Environment** represents a deployment stage (development, staging, production) bound to a specific DataPlane. + +Key considerations: + +- The `dataPlaneRef` is a structured reference with `kind` (`DataPlane` or `ClusterDataPlane`) and `name` fields +- The `dataPlaneRef` is **immutable** - to change the DataPlane, delete and recreate the Environment +- The `gateway` field embeds a full gateway configuration (ingress/egress endpoints with host and port) that can override the DataPlane's defaults per environment + +For complete configuration options, see the [Environment API Reference](../reference/api/platform/environment.md). + +### DataPlane + +A **DataPlane** defines where application workloads run. It requires: + +- Cluster agent configuration with CA certificate for authentication +- Gateway configuration with ingress host (`gateway.ingress.external.https.host`) for application endpoints + +For complete configuration options and examples, see the [DataPlane API Reference](../reference/api/platform/dataplane.md). + +### WorkflowPlane (Optional) + +A **WorkflowPlane** provides infrastructure for CI/CD workflows. When enabled: + +- Requires cluster agent configuration with CA certificate +- Can reference an ObservabilityPlane for build logs + +For complete configuration options, see the [WorkflowPlane API Reference](../reference/api/platform/workflowplane.md). + +### ObservabilityPlane (Optional) + +An **ObservabilityPlane** provides logging and monitoring infrastructure. Key fields: + +- `observerURL`: The Observer service endpoint +- `rcaAgentURL`: The SRE Agent service endpoint (optional) +- `agent`: Cluster agent configuration for communication + +Both DataPlane and WorkflowPlane can reference an ObservabilityPlane or ClusterObservabilityPlane via `observabilityPlaneRef`. + +### Cluster-Scoped Plane Resources + +OpenChoreo supports cluster-scoped variants of plane resources: + +- **ClusterDataPlane** - A cluster-scoped DataPlane that can be referenced by Environments. See the [ClusterDataPlane API Reference](../reference/api/platform/clusterdataplane.md). +- **ClusterWorkflowPlane** - A cluster-scoped WorkflowPlane that can be referenced by Projects. See the [ClusterWorkflowPlane API Reference](../reference/api/platform/clusterworkflowplane.md). +- **ClusterObservabilityPlane** - A cluster-scoped ObservabilityPlane that can be referenced by DataPlanes, ClusterDataPlanes, WorkflowPlanes, or ClusterWorkflowPlanes. See the [ClusterObservabilityPlane API Reference](../reference/api/platform/clusterobservabilityplane.md). + +Cluster-scoped resources are useful in shared infrastructure scenarios where multiple teams or organizations use the same underlying cluster without needing to duplicate plane configurations per namespace. + +## Linking Planes + +Planes reference each other in their spec to form a logical topology. + +| Resource | Reference Field | Target | Format | +| ------------- | ----------------------- | ---------------------------------------------- | --------------------------- | +| Project | `workflowPlaneRef` | WorkflowPlane / ClusterWorkflowPlane | Structured (`kind`, `name`) | +| Environment | `dataPlaneRef` | DataPlane / ClusterDataPlane | Structured (`kind`, `name`) | +| DataPlane | `observabilityPlaneRef` | ObservabilityPlane / ClusterObservabilityPlane | Structured (`kind`, `name`) | +| DataPlane | `secretStoreRef` | ClusterSecretStore | Name reference | +| WorkflowPlane | `observabilityPlaneRef` | ObservabilityPlane / ClusterObservabilityPlane | Structured (`kind`, `name`) | + +For detailed instructions on registering planes and establishing trust between clusters, see [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx). + +## Verifying Resources + +```bash +kubectl get namespaces +kubectl get environments -n +kubectl get dataplanes -n +kubectl get workflowplanes -n +kubectl get observabilityplanes -n +``` + +## Troubleshooting + +### Agent Connection Issues + +```bash +# Check agent pod status +kubectl get pods -n openchoreo-data-plane -l app=cluster-agent + +# View agent logs +kubectl logs -n openchoreo-data-plane deployment/cluster-agent +``` + +### Environment Not Ready + +```bash +# Check environment conditions +kubectl describe environment -n + +# Verify referenced DataPlane exists +kubectl get dataplane -n +``` + +### Plane Status Not Updating + +```bash +# Check controller-manager logs +kubectl logs -n openchoreo-control-plane deployment/controller-manager + +# View plane conditions +kubectl get dataplane -n -o jsonpath='{.status.conditions}' +``` + +## Related Documentation + +- [DataPlane API Reference](../reference/api/platform/dataplane.md) +- [ClusterDataPlane API Reference](../reference/api/platform/clusterdataplane.md) +- [WorkflowPlane API Reference](../reference/api/platform/workflowplane.md) +- [ClusterWorkflowPlane API Reference](../reference/api/platform/clusterworkflowplane.md) +- [ObservabilityPlane API Reference](../reference/api/platform/observabilityplane.md) +- [ClusterObservabilityPlane API Reference](../reference/api/platform/clusterobservabilityplane.md) +- [Environment API Reference](../reference/api/platform/environment.md) +- [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx) - Step-by-step multi-cluster setup +- [Secret Management](./secret-management.mdx) - External secret store integration diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/external-ca-tls-setup.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/external-ca-tls-setup.md new file mode 100644 index 00000000..75441ec8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/external-ca-tls-setup.md @@ -0,0 +1,480 @@ +--- +title: mTLS Setup for Cluster Gateway and Agent with External CA +description: Configure mTLS for cluster gateway and agent communication using an external CA instead of cert-manager. +sidebar_position: 6 +--- + +# mTLS Setup for Cluster Gateway and Agent with External CA + +This guide explains how to configure mTLS for OpenChoreo's cluster gateway and cluster agent communication without relying on cert-manager. Instead, you provision certificates using an external CA (e.g., OpenSSL, HashiCorp Vault, AWS ACM PCA, or a corporate PKI). + +## When to Use This Guide + +- **Air-gapped environments** where cert-manager cannot be installed +- **Corporate PKI mandates** requiring certificates from an approved CA +- **Proof-of-concept setups** where simplicity is preferred over automation +- **Environments** where cert-manager is not desired as a dependency + +## What cert-manager Does by Default + +In the default OpenChoreo installation, cert-manager handles the full certificate lifecycle: + +1. Creates a self-signed CA (stored in Secret `cluster-gateway-ca`) +2. Issues a server certificate for the cluster gateway (stored in Secret `cluster-gateway-tls`) +3. Issues client certificates for each cluster agent (stored in Secret `cluster-agent-tls`) +4. Extracts the CA certificate into a ConfigMap (`cluster-gateway-ca`) via a post-install Job +5. Handles automatic renewal before expiry + +Without cert-manager, you must perform all of these steps manually. + +## Certificate Architecture + +Three types of certificates are needed: + +```text +External CA (your CA) + | + ├── Gateway Server Certificate (control plane cluster) + | Secret: cluster-gateway-tls (tls.crt, tls.key) + | Used by: cluster-gateway Deployment + | Purpose: TLS server identity for WebSocket endpoint + | DNS SANs: cluster-gateway..svc, + | cluster-gateway..svc.cluster.local + | + └── Agent Client Certificate (one per plane, in each plane's cluster) + Secret: cluster-agent-tls (tls.crt, tls.key) + Used by: cluster-agent Deployment + Purpose: mTLS client authentication to gateway + CN: + Extended Key Usage: Client Authentication +``` + +Additionally, the CA certificate is distributed as a ConfigMap (`cluster-gateway-ca`) to: + +- The control plane cluster (for the CA extractor Job / controller-manager) +- Each plane cluster (so agents can verify the gateway's server certificate) + +And the CA certificate is configured in the [DataPlane](../reference/api/platform/dataplane.md)/[WorkflowPlane](../reference/api/platform/workflowplane.md)/[ObservabilityPlane](../reference/api/platform/observabilityplane.md) CR so the gateway can verify agent client certificates on a per-CR basis. + +## Prerequisites + +- `openssl` (or your preferred PKI tool) +- `kubectl` with access to the control plane cluster and each plane cluster +- Familiarity with your Helm values files + +## Step 1: Create a CA + +Generate a CA that will sign both the gateway server certificate and all agent client certificates. + +```bash +# Generate CA private key +openssl genrsa -out ca.key 4096 + +# Generate CA certificate (10 years validity) +openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \ + -out ca.crt \ + -subj "/CN=openchoreo-cluster-gateway-ca/O=OpenChoreo" +``` + +:::warning Security +Keep `ca.key` secure. It should only be accessible to administrators who issue certificates. +::: + +## Step 2: Generate the Gateway Server Certificate + +This certificate is used by the `cluster-gateway` deployment in the control plane cluster. + +```bash +# Generate server private key +openssl genrsa -out gateway-server.key 2048 + +# Create CSR config with SANs +cat > gateway-server-csr.conf < agent-client-ext.conf < + -----END CERTIFICATE----- + gateway: + ingress: + external: + name: default-gateway + namespace: openchoreo-system + https: + host: "gw.example.com" + port: 443 +``` + +### CA from a Secret Reference + +```yaml +apiVersion: core.openchoreo.dev/v1alpha1 +kind: DataPlane +metadata: + name: my-data-plane + namespace: default +spec: + planeID: "default" + clusterAgent: + clientCA: + secretKeyRef: + name: my-external-ca + key: ca.crt + namespace: openchoreo-control-plane + gateway: + ingress: + external: + name: default-gateway + namespace: openchoreo-system + https: + host: "gw.example.com" + port: 443 +``` + +:::tip Key Point +The `clientCA` field tells the gateway which CA to trust for verifying agent client certificates. Without this, agent connections will be rejected with certificate verification errors. +::: + +## Step 7: Certificate Renewal + +Without cert-manager, certificate renewal is a manual process. + +### Generating Replacement Certificates + +Use the same OpenSSL commands from Steps 2 and 3 with the **same CA** to generate new certificates. + +### Updating Kubernetes Secrets + +```bash +# Update the gateway server certificate +kubectl create secret tls cluster-gateway-tls \ + --cert=gateway-server-new.crt \ + --key=gateway-server-new.key \ + -n openchoreo-control-plane \ + --dry-run=client -o yaml | kubectl apply -f - + +# Update an agent client certificate +kubectl create secret tls cluster-agent-tls \ + --cert=agent-dataplane-new.crt \ + --key=agent-dataplane-new.key \ + -n openchoreo-data-plane \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +### Restarting Pods + +Both the gateway and agent read certificates at startup and do not hot-reload them. After updating secrets, restart the affected deployments: + +```bash +# Restart gateway +kubectl rollout restart deployment cluster-gateway -n openchoreo-control-plane + +# Restart agent +kubectl rollout restart deployment cluster-agent-dataplane -n openchoreo-data-plane +``` + +### Renewal Reminders + +Set calendar reminders or use external automation (e.g., a CronJob, CI/CD pipeline, or your PKI's built-in renewal workflow) to renew certificates before they expire. + +## Troubleshooting + +### Common Errors + +| Error | Cause | Fix | +| ----------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `x509: certificate signed by unknown authority` | Agent doesn't trust gateway's CA, or gateway doesn't trust agent's CA | Verify `cluster-gateway-ca` ConfigMap and `clientCA` in the plane CR both contain the correct CA | +| `tls: bad certificate` | Certificate format issue or wrong certificate type | Ensure server cert has `serverAuth` EKU and client cert has `clientAuth` EKU | +| `no CRs found with planeID` | No DataPlane/WorkflowPlane/ObservabilityPlane CR matches the agent's planeID | Ensure the plane CR exists and its `spec.planeID` matches the agent's `--plane-id` | +| `certificate not valid for any CR` | Agent's client cert cannot be verified by any CR's `clientCA` | Ensure the plane CR's `clientCA` contains the CA that signed the agent's client cert | + +### Verify the Certificate Chain + +```bash +# Verify gateway server cert +openssl verify -CAfile ca.crt gateway-server.crt + +# Verify agent client cert +openssl verify -CAfile ca.crt agent-dataplane.crt +``` + +### Inspect Certificate SANs + +```bash +openssl x509 -in gateway-server.crt -noout -text | grep -A1 "Subject Alternative Name" +``` + +### Inspect Certificate CN and Key Usage + +```bash +# Check CN (should match planeID for agent certs) +openssl x509 -in agent-dataplane.crt -noout -subject + +# Check key usage +openssl x509 -in agent-dataplane.crt -noout -text | grep -A1 "Extended Key Usage" +``` + +### Check Pod Logs + +```bash +# Gateway logs — look for TLS handshake or certificate verification errors +kubectl logs -l app=cluster-gateway -n openchoreo-control-plane + +# Agent logs — look for connection or TLS errors +kubectl logs -l app=cluster-agent -n openchoreo-data-plane +``` + +## Quick Reference: Secrets and ConfigMaps + +| Component | Cluster | Resource Type | Name | Keys | Purpose | +| ------------- | -------------- | ------------- | --------------------- | -------------------- | ------------------------------ | +| Gateway | Control Plane | Secret (TLS) | `cluster-gateway-tls` | `tls.crt`, `tls.key` | Gateway server certificate | +| Gateway CA | Control Plane | ConfigMap | `cluster-gateway-ca` | `ca.crt` | CA cert for controller-manager | +| Agent (DP) | Data Plane | Secret (TLS) | `cluster-agent-tls` | `tls.crt`, `tls.key` | Agent client certificate | +| Agent CA (DP) | Data Plane | ConfigMap | `cluster-gateway-ca` | `ca.crt` | CA cert to verify gateway | +| Agent (WP) | Workflow Plane | Secret (TLS) | `cluster-agent-tls` | `tls.crt`, `tls.key` | Agent client certificate | +| Agent CA (WP) | Workflow Plane | ConfigMap | `cluster-gateway-ca` | `ca.crt` | CA cert to verify gateway | +| Agent (OP) | Observability | Secret (TLS) | `cluster-agent-tls` | `tls.crt`, `tls.key` | Agent client certificate | +| Agent CA (OP) | Observability | ConfigMap | `cluster-gateway-ca` | `ca.crt` | CA cert to verify gateway | + +## Related Resources + +- [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx) — Default mTLS setup using cert-manager +- [Deployment Topology](./deployment-topology.mdx) — Overview of OpenChoreo deployment models +- [DataPlane API Reference](../reference/api/platform/dataplane.md) — DataPlane CR specification +- [Helm Chart Reference: Control Plane](../reference/helm/control-plane.mdx) — Control plane Helm values +- [Helm Chart Reference: Data Plane](../reference/helm/data-plane.mdx) — Data plane Helm values diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/build-and-release-workflows.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/build-and-release-workflows.mdx new file mode 100644 index 00000000..0b2964a2 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/build-and-release-workflows.mdx @@ -0,0 +1,107 @@ +--- +title: Build and Release Workflows +description: Automate container builds and GitOps releases using Workflows +sidebar_position: 1 +--- + +# Build and Release Workflows + +When using a GitOps approach, deploying a Component requires three resources in your GitOps repository: a **Workload** (container image and endpoint configuration), a **ComponentRelease** (immutable release snapshot), and a **ReleaseBinding** (binds the release to an Environment). Creating these by hand for every build is tedious and error-prone. + +OpenChoreo provides build-and-release Workflows that automate this entire cycle. They build a container image from source code, generate the required resources using the `occ` CLI, and open a pull request in your GitOps repository. Once the PR is merged, your GitOps operator (e.g., Flux CD) syncs the resources to the cluster. + +## How It Works + +All build-and-release workflows follow a two-phase architecture: + +```mermaid +flowchart TD + subgraph "Phase 1 - Build" + A[Clone Source Repo] --> B[Build Container Image] + B --> C[Push to Registry] + end + + subgraph "Phase 2 — Release" + C --> D[Clone GitOps Repo] + D --> E["Generate Resources (occ CLI)"] + E --> F[Create Pull Request] + end + + F --> G[Merge PR] + G --> H[GitOps Operator Syncs] + H --> I[Cluster Deploys] +``` + +**Phase 1 — Build:** Clones the source repository, builds a container image using the workflow-specific method (Docker, Buildpacks, or Node.js + nginx), and pushes it to the container registry. + +**Phase 2 — Release:** Clones the GitOps repository, creates a feature branch (`release/-`), runs `occ` CLI commands to generate Workload, ComponentRelease, and ReleaseBinding resources, and opens a pull request for review. + +## Available Workflows + +| Workflow | Use Case | Build Method | +| ---------------------------------------- | ------------------------------------------ | ----------------------- | +| `docker-gitops-release` | General-purpose services with a Dockerfile | Docker (Podman) | +| `google-cloud-buildpacks-gitops-release` | Source-to-image without a Dockerfile | Google Cloud Buildpacks | +| `react-gitops-release` | React/SPA frontend applications | Node.js + nginx | + +For detailed workflow configuration, parameters, installation, and usage examples, see the [Workflow Reference](https://github.com/openchoreo/sample-gitops/blob/main/namespaces/default/platform/workflows/README.md#build-and-release-workflows) in the sample-gitops repository. + +:::info Platform Engineer Configuration +GitOps repository details such as the repository URL, branch, container registry, and image naming are configured by platform engineers directly in the Workflow resource's `runTemplate`, not by developers in the WorkflowRun. Developers only need to provide build-specific parameters (e.g., Dockerfile path, build context) and source repository details. + +Workflow triggering is flexible. For example, if you need auto-build capabilities, you can follow a similar approach to [Auto Build](../../workflows/auto-build.mdx). +::: + +## Generating Resources with the CLI + +During the release phase, workflows use three `occ` CLI commands sequentially to generate the GitOps resources: + +### 1. Create Workload + +Creates or updates the Workload resource with the container image reference and endpoint configuration from the workload descriptor: + +```bash +occ workload create \ + --mode file-system \ + --root-dir \ + --project \ + --component \ + --image \ + --descriptor # optional +``` + +### 2. Generate ComponentRelease + +Generates an immutable ComponentRelease snapshot from the Component, Workload, ComponentType, and Trait definitions: + +```bash +occ componentrelease generate \ + --mode file-system \ + --root-dir \ + --project \ + --component \ + --name \ + --output-path +``` + +### 3. Generate ReleaseBinding + +Generates a ReleaseBinding that binds the ComponentRelease to the target Environment: + +```bash +occ releasebinding generate \ + --mode file-system \ + --root-dir \ + --project \ + --component \ + --component-release +``` + +You can run these commands manually outside of workflows to generate resources in your GitOps repository. For the full list of flags and options, see the [CLI Reference](../../../reference/cli-reference.md). + +## See Also + +- [Bulk Promote](./bulk-promote.mdx) — Promote multiple components to an Environment at once +- [Auto Build](../../workflows/auto-build.mdx) — Trigger workflows automatically on Git push via webhooks +- [GitOps Overview](../overview.md) — Repository patterns and best practices +- [CLI Reference](../../../reference/cli-reference.md) — Complete `occ` command reference diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/bulk-promote.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/bulk-promote.mdx new file mode 100644 index 00000000..a42779df --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/automations/bulk-promote.mdx @@ -0,0 +1,80 @@ +--- +title: Bulk Promote Workflow +description: Generate ReleaseBindings to promote multiple components to an environment +sidebar_position: 2 +--- + +# Bulk Promote Workflow + +After building and releasing Components to an initial Environment (e.g., development), you often need to promote them to the next Environment (e.g., staging or production). Doing this one Component at a time is slow when a project has many Components. + +The Bulk GitOps Promote workflow generates or updates ReleaseBindings for multiple Components in a single operation. Unlike [build-and-release workflows](./build-and-release-workflows.mdx), it has no build phase. It operates purely on the GitOps repository to bind existing ComponentReleases to a target Environment. + +## How It Works + +```mermaid +flowchart TD + A[Clone GitOps Repo] --> B["Create Feature Branch (bulk-release/{scope}-{timestamp})"] + B --> C["Generate ReleaseBindings (occ releasebinding generate)"] + C --> D[Create Pull Request] + D --> E[Merge PR] + E --> F[GitOps Operator Syncs] + F --> G[Components Deployed to Target Environment] +``` + +The workflow clones your GitOps repository, uses the `occ releasebinding generate` command to create ReleaseBindings for all Components in scope, and opens a pull request. Once merged, your GitOps operator syncs the new bindings, deploying the Components to the target Environment. + +:::important ComponentReleases Required +Components must be built first using [build-and-release workflows](./build-and-release-workflows.mdx) before they can be promoted. The bulk promote workflow binds **existing** ComponentReleases to a new Environment. +::: + +## When to Use + +- **Coordinated multi-component promotions** — Promote all Components to staging at once +- **Production rollouts** — Promote an entire project to production +- **Initial Environment bootstrapping** — Create bindings for all Components in a new Environment + +For detailed workflow configuration, parameters, and installation instructions, see the [Workflow Reference](https://github.com/openchoreo/sample-gitops/blob/main/namespaces/default/platform/workflows/README.md#promotion-workflow) in the sample-gitops repository. + +## Generating ReleaseBindings with the CLI + +The workflow internally uses the `occ releasebinding generate` command. You can also run it manually or re-use it in your customized automations appropriately: + +### Promote all Components across all projects + +```bash +occ releasebinding generate --all \ + --mode file-system \ + --root-dir \ + --target-env \ + --use-pipeline +``` + +### Promote all Components in a specific project + +```bash +occ releasebinding generate --project \ + --mode file-system \ + --root-dir \ + --target-env \ + --use-pipeline +``` + +### Promote a specific Component + +```bash +occ releasebinding generate --project --component \ + --mode file-system \ + --root-dir \ + --target-env \ + --component-release # optional, defaults to latest +``` + +For the full list of flags and options, see the [CLI Reference](../../../reference/cli-reference.md). + +## See Also + +- [Build and Release Workflows](./build-and-release-workflows.mdx) — Automate container builds and GitOps releases +- [GitOps Overview](../overview.md) — Repository patterns and best practices +- [ReleaseBinding API Reference](../../../reference/api/platform/releasebinding.md) — ReleaseBinding resource specification +- [CLI Reference](../../../reference/cli-reference.md) — Complete `occ` command reference diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/overview.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/overview.md new file mode 100644 index 00000000..37fdb203 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/overview.md @@ -0,0 +1,400 @@ +--- +title: Overview +description: Learn how to use GitOps principles with OpenChoreo for declarative, versioned, and auditable infrastructure and application management. +sidebar_position: 1 +--- + +# GitOps with OpenChoreo + +OpenChoreo embraces GitOps principles by treating Git repositories as the single source of truth for both platform configuration and application deployments. This approach enables declarative, versioned, and auditable infrastructure and application management across multiple Environments and clusters. + +## GitOps Principles + +OpenChoreo implements GitOps through the four [OpenGitOps](https://opengitops.dev/) principles: + +1. **Declarative**: The desired state of the system is expressed declaratively through OpenChoreo CRDs and YAML manifests +2. **Versioned and Immutable**: Desired state is stored in Git, which enforces immutability, versioning, and retains a complete version history +3. **Pulled Automatically**: GitOps agents (such as Flux CD) automatically pull the desired state declarations from the Git repository +4. **Continuously Reconciled**: Software agents continuously observe the actual system state and attempt to apply the desired state + +## Repository Organization Patterns + +OpenChoreo is designed to work with any repository structure by adhering to core GitOps principles. Choose the pattern that best fits your team's size, structure, and governance requirements. + +### Cluster-Scoped and Namespace-Scoped Resources + +Many OpenChoreo platform resources have both cluster-scoped and namespace-scoped variants (see [Platform Abstractions](../../concepts/platform-abstractions.md) for details). This distinction has a direct impact on how you organize your GitOps repository: + +- **Cluster-scoped resources** (e.g., ClusterComponentType, ClusterTrait, ClusterWorkflow, ClusterDataPlane, ClusterWorkflowPlane, ClusterObservabilityPlane, ClusterAuthzRole, ClusterAuthzRoleBinding) are shared across all namespaces and organized under `platform-shared/`. +- **Namespace-scoped resources** (e.g., ComponentType, Trait, Workflow, DataPlane, WorkflowPlane, ObservabilityPlane, AuthzRole, AuthzRoleBinding) are specific to a namespace and organized under `namespaces//platform/`. + +The default setup uses cluster-scoped variants, which provide platform-wide defaults. Namespace-scoped variants are available when you need per-namespace customization. + +### Mono Repository + +A single repository containing all OpenChoreo resources - ideal for smaller teams or organizations where platform and development teams work closely together. + +```text +. +├── platform-shared/ # cluster-scoped resources (available to all namespaces) +│ ├── component-types/ # ClusterComponentType resources +│ │ ├── service.yaml +│ │ ├── webapp.yaml +│ │ └── scheduled-task.yaml +│ ├── traits/ # ClusterTrait resources +│ │ ├── persistent-volume.yaml +│ │ └── api-management.yaml +│ ├── workflows/ # ClusterWorkflow resources +│ │ ├── docker-with-gitops.yaml +│ │ └── bulk-gitops-release.yaml +│ ├── infra/ # Infrastructure plane resources +│ │ ├── data-planes/ # ClusterDataPlane resources +│ │ │ └── default.yaml +│ │ ├── workflow-planes/ # ClusterWorkflowPlane resources +│ │ │ └── default.yaml +│ │ └── observability-planes/ # ClusterObservabilityPlane resources +│ │ └── default.yaml +│ ├── authz/ # Cluster authorization resources +│ │ ├── roles/ # ClusterAuthzRole resources +│ │ │ ├── platform-admin.yaml +│ │ │ └── developer.yaml +│ │ └── role-bindings/ # ClusterAuthzRoleBinding resources +│ │ └── admin-binding.yaml +│ └── cluster-workflow-templates/ # Argo ClusterWorkflowTemplate CRDs +│ └── argo/ +│ ├── docker.yaml +│ └── bulk-gitops-release-template.yaml +│ +└── namespaces/ # namespace-scoped resources + └── / + ├── namespace.yaml + │ + ├── platform/ # platform-level resources (managed by platform team) + │ ├── infra/ + │ │ ├── deployment-pipelines/ + │ │ │ └── standard.yaml + │ │ ├── environments/ + │ │ │ ├── development.yaml + │ │ │ ├── staging.yaml + │ │ │ └── production.yaml + │ │ ├── data-planes/ # DataPlane resources + │ │ │ └── custom.yaml + │ │ ├── workflow-planes/ # WorkflowPlane resources + │ │ │ └── custom.yaml + │ │ └── observability-planes/ # ObservabilityPlane resources + │ │ └── custom.yaml + │ ├── component-types/ + │ │ ├── service.yaml + │ │ ├── webapp.yaml + │ │ └── scheduled-task.yaml + │ ├── traits/ + │ │ ├── persistent-volume.yaml + │ │ └── api-management.yaml + │ ├── component-workflows/ + │ │ └── docker-with-gitops.yaml + │ ├── workflows/ + │ │ └── bulk-gitops-release.yaml + │ ├── authz/ # Namespace authorization resources + │ │ ├── roles/ # AuthzRole resources + │ │ │ └── namespace-admin.yaml + │ │ └── role-bindings/ # AuthzRoleBinding resources + │ │ └── admin-binding.yaml + │ └── secret-references/ + │ └── database-secret-reference.yaml + │ + └── projects/ # application resources (managed by development teams) + └── / + ├── project.yaml + └── components/ + └── / + ├── component.yaml + ├── workload.yaml + ├── releases/ + │ └── --.yaml + └── release-bindings/ + ├── -development.yaml + └── -staging.yaml +``` + +### Multi Repository + +Separate repositories for platform configuration and application resources. This pattern is recommended for larger organizations where platform teams and development teams have different access controls, approval workflows, and release cadences. + +**Platform Configuration Repository** - Managed by platform engineers: + +```text +. +├── platform-shared/ # cluster-scoped resources (available to all namespaces) +│ ├── component-types/ # ClusterComponentType resources +│ │ ├── service.yaml +│ │ ├── webapp.yaml +│ │ └── scheduled-task.yaml +│ ├── traits/ # ClusterTrait resources +│ │ ├── persistent-volume.yaml +│ │ └── api-management.yaml +│ ├── workflows/ # ClusterWorkflow resources +│ │ ├── docker-with-gitops.yaml +│ │ └── bulk-gitops-release.yaml +│ ├── infra/ # Infrastructure plane resources +│ │ ├── data-planes/ # ClusterDataPlane resources +│ │ │ └── default.yaml +│ │ ├── workflow-planes/ # ClusterWorkflowPlane resources +│ │ │ └── default.yaml +│ │ └── observability-planes/ # ClusterObservabilityPlane resources +│ │ └── default.yaml +│ ├── authz/ # Cluster authorization resources +│ │ ├── roles/ # ClusterAuthzRole resources +│ │ │ ├── platform-admin.yaml +│ │ │ └── developer.yaml +│ │ └── role-bindings/ # ClusterAuthzRoleBinding resources +│ │ └── admin-binding.yaml +│ └── cluster-workflow-templates/ # Argo ClusterWorkflowTemplate CRDs +│ └── argo/ +│ ├── docker.yaml +│ └── bulk-gitops-release-template.yaml +│ +└── namespaces/ + └── / + ├── namespace.yaml + └── platform/ + ├── infra/ + │ ├── deployment-pipelines/ + │ │ └── standard.yaml + │ ├── environments/ + │ │ ├── development.yaml + │ │ ├── staging.yaml + │ │ └── production.yaml + │ ├── data-planes/ # DataPlane resources + │ │ └── custom.yaml + │ ├── workflow-planes/ # WorkflowPlane resources + │ │ └── custom.yaml + │ └── observability-planes/ # ObservabilityPlane resources + │ └── custom.yaml + ├── component-types/ + │ ├── service.yaml + │ ├── webapp.yaml + │ └── scheduled-task.yaml + ├── traits/ + │ ├── persistent-volume.yaml + │ └── api-management.yaml + ├── component-workflows/ + │ └── docker-with-gitops.yaml + ├── workflows/ + │ └── bulk-gitops-release.yaml + ├── authz/ # Namespace authorization resources + │ ├── roles/ # AuthzRole resources + │ │ └── namespace-admin.yaml + │ └── role-bindings/ # AuthzRoleBinding resources + │ └── admin-binding.yaml + └── secret-references/ + └── database-secret-reference.yaml +``` + +**Application Repository** - Managed by development teams: + +```text +. +└── namespaces/ + └── / + └── projects/ + └── / + ├── project.yaml + └── components/ + └── / + ├── component.yaml + ├── workload.yaml + ├── releases/ + │ └── --.yaml + └── release-bindings/ + ├── -development.yaml + └── -staging.yaml +``` + +**Benefits of Multi Repository:** + +- **Clear ownership boundaries** - Platform teams control infrastructure; development teams control applications +- **Independent access controls** - Different permissions and approval workflows per repository +- **Separate release cadences** - Platform changes can be reviewed and deployed independently from application changes +- **Reduced blast radius** - Changes to one repository don't affect the other +- **Easier compliance and auditing** - Clear separation for regulatory requirements + +:::tip Flexible Repository Structures +The patterns above are common starting points, but OpenChoreo is designed to work with **any repository structure** that fits your team's needs. Since OpenChoreo reconciles resources based on their content rather than their location, you have complete flexibility in how you organize your Git repositories. Other patterns you might consider: + +- **Repository per Project** - Each development team owns their Project in a dedicated repository +- **Repository per Component** - Individual Components managed in separate repositories for maximum isolation +- **Separate ReleaseBindings repository** - Keep ReleaseBindings in a dedicated repository for centralized deployment control +- **Environment-based repositories** - Separate repositories for production vs non-production configurations +- **Hybrid approaches** - Combine patterns based on team structure and security requirements + +Choose the structure that aligns with your team's governance policies, boundaries, and operational workflows. +::: + +:::note Cluster-Scoped vs Namespace-Scoped Resources in the Trees +The directory trees above show both cluster-scoped resources (under `platform-shared/`) and namespace-scoped resources (under `namespaces//platform/`). The default OpenChoreo setup uses cluster-scoped variants (e.g., ClusterComponentType, ClusterDataPlane) to provide platform-wide defaults. You only need namespace-scoped variants when you require per-namespace customization that overrides the cluster defaults. +::: + +## Best Practices + +### Repository Organization + +OpenChoreo's declarative nature means it works with any repository structure - resources are reconciled based on their content, not their location. However, following consistent patterns provides significant benefits: + +**Choose the right repository strategy** + +- Use a **mono repository** for smaller teams or when platform and development teams collaborate closely +- Use **multi repository** for larger teams requiring strict access controls and independent workflows +- See [Repository Organization Patterns](#repository-organization-patterns) for detailed structures + +**Organize cluster-scoped and namespace-scoped resources separately** + +- Keep cluster-scoped resources (ClusterComponentType, ClusterDataPlane, etc.) in `platform-shared/` — separate from namespace-scoped resources +- This separation makes it clear which changes affect the entire cluster vs a single namespace +- See [Cluster-Scoped and Namespace-Scoped Resources](#cluster-scoped-and-namespace-scoped-resources) for details + +**Use consistent directory structures** + +While OpenChoreo doesn't enforce directory layouts, consistent structure helps teams: + +- Quickly locate resources across projects +- Onboard new team members faster +- Apply automation and tooling uniformly + +### Configuration Management + +**OpenChoreo handles resource dependencies automatically** + +OpenChoreo resources don't require specific ordering or dependency management. The controllers reconcile resources based on their relationships, not their application order. + +**OpenChoreo supports multiple Environments natively** + +Unlike traditional Kubernetes GitOps where you need separate branches or Kustomize overlays per environment, OpenChoreo handles multi-environment deployments through its built-in resources ([`Environment`](../../reference/api/platform/environment.md), [`ComponentRelease`](../../reference/api/runtime/componentrelease.md), [`ReleaseBinding`](../../reference/api/platform/releasebinding.md)). You define your Component once and use **ReleaseBindings** to deploy it across Environments. + +**Consider Kustomize for operational concerns (optional)** + +While not required for environment management, tools like Kustomize can be useful for operational tasks. For example, when using Flux CD, you can use Flux Kustomization resources to inject the target namespace for all resources in a path: + +```yaml +# flux/platform-kustomization.yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: platform + namespace: flux-system +spec: + interval: 5m + path: ./namespaces/default/platform + prune: true + targetNamespace: default # inject namespace for all resources + sourceRef: + kind: GitRepository + name: my-gitops-repo +``` + +**Sync cluster-scoped resources before namespace-scoped resources** + +When using a GitOps operator, configure `platform-shared/` to sync before namespace-scoped resources. Cluster-scoped resources (e.g., ClusterComponentType, ClusterDataPlane) define platform-wide defaults that namespace-scoped resources may depend on. For example, with Flux CD you can use the `dependsOn` field to enforce ordering: + +```yaml +# flux/platform-shared-kustomization.yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: platform-shared + namespace: flux-system +spec: + interval: 5m + path: ./platform-shared + prune: true + sourceRef: + kind: GitRepository + name: my-gitops-repo +--- +# flux/platform-kustomization.yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: platform + namespace: flux-system +spec: + dependsOn: + - name: platform-shared + interval: 5m + path: ./namespaces/default/platform + prune: true + targetNamespace: default + sourceRef: + kind: GitRepository + name: my-gitops-repo +``` + +Note that the `platform-shared` Kustomization does not set `targetNamespace`, since cluster-scoped resources are not namespaced. + +### Version Control Practices + +- **Use pull requests for all changes** - Enable code review and maintain audit trails +- **Implement branch protection** - Require reviews for changes affecting production Environments +- **Tag releases** - Use semantic versioning for traceability and rollback capabilities +- **Write meaningful commit messages** - Document the intent behind configuration changes + +### Security Practices + +- **Never commit plaintext secrets** - Use SecretReference resources to reference external secret stores +- **Define Code Owners** - Use a `CODEOWNERS` file to protect critical files and directories by requiring review from designated owners before merging changes +- **Restrict access to `platform-shared/`** - Since changes to cluster-scoped resources affect all namespaces, use `CODEOWNERS` to require platform team review for any changes under `platform-shared/` + +## Secrets Management + +OpenChoreo integrates with the [External Secrets Operator (ESO)](https://external-secrets.io/) to provide secure, GitOps-friendly secrets management. Platform teams define [SecretReference](../../reference/api/platform/secretreference.md) resources to bring in secrets from external secret stores without committing plaintext secrets to Git. + +In a GitOps repository, SecretReference resources are typically organized under the platform-level directory (e.g., `namespaces//platform/secret-references/`), managed by the platform team alongside other infrastructure resources. + +For complete setup instructions, provider configuration, and usage examples, see the [Secret Management](../secret-management.mdx) guide. + +## Deployment Strategy + +OpenChoreo uses a two-resource model for deployments that enables GitOps-friendly, Environment-aware releases: + +| Resource | Purpose | +| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| [**ComponentRelease**](../../reference/api/runtime/componentrelease.md) | Immutable snapshot of a Component version (component type, workload, traits, configurations) | +| [**ReleaseBinding**](../../reference/api/platform/releasebinding.md) | Binds a ComponentRelease to an Environment with optional overrides | + +This separation allows the same ComponentRelease to be deployed across multiple Environments with Environment-specific configurations. To promote a Component, create a ReleaseBinding that references the same ComponentRelease in the target Environment. To roll back, update the ReleaseBinding to reference a previous ComponentRelease. + +For a hands-on walkthrough of this promotion workflow, see the [Using Flux CD](./using-flux-cd.mdx) tutorial. + +:::tip OpenChoreo CLI (`occ`) +The `occ` CLI simplifies common GitOps operations such as creating Workloads, generating ComponentReleases, managing ReleaseBindings, and automating promotions. See the [CLI Reference](../../reference/cli-reference.md) for available commands. +::: + +## Monitoring and Observability + +### GitOps Tool Monitoring + +GitOps operators provide built-in monitoring for sync status, drift detection, reconciliation metrics, and event logging. Refer to your tool's documentation for specific setup: + +- [Flux CD Monitoring](https://fluxcd.io/flux/monitoring/) + +### OpenChoreo Resource Monitoring + +OpenChoreo tracks the health of deployed resources through ReleaseBinding status conditions: + +| Condition | Description | +| ------------------ | ------------------------------------------------------------ | +| **ReleaseSynced** | Whether the RenderedRelease was successfully created/updated | +| **ResourcesReady** | Whether all resources in the DataPlane are healthy | +| **Ready** | Overall readiness of the deployment | + +Use `kubectl` to check deployment status: + +```bash +kubectl get releasebindings -A -o wide +kubectl describe releasebinding -n +``` + +## Next Steps + +Get started on GitOps with OpenChoreo: + +- [Using Flux CD](./using-flux-cd.mdx) - Configure Flux CD with OpenChoreo for GitOps-based deployments diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/using-flux-cd.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/using-flux-cd.mdx new file mode 100644 index 00000000..41e0d7d3 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/gitops/using-flux-cd.mdx @@ -0,0 +1,133 @@ +--- +title: Using Flux CD +description: Configure Flux CD with OpenChoreo for GitOps-based resource synchronization and deployments. +sidebar_position: 3 +--- + +# Using Flux CD + +[Flux CD](https://fluxcd.io/) is a set of continuous delivery tools that keeps Kubernetes clusters in sync with configuration sources like Git repositories. For OpenChoreo integration, Flux's **kustomize-controller** automatically applies OpenChoreo resources from Git to your cluster. + +When combined with OpenChoreo, Flux CD enables you to: + +- **Declaratively manage OpenChoreo resources** — Store Projects, Components, Workloads, and other resources in Git +- **Automate deployments** — Changes pushed to Git are automatically applied to your cluster +- **Maintain audit trails** — Git history provides a complete record of all changes +- **Enable GitOps workflows** — Use pull requests for review and approval before changes are applied + +## Flux Resources Overview + +To sync OpenChoreo resources from Git, you need two types of Flux resources: + +| Resource | Purpose | +| ----------------- | ---------------------------------------------------------------------------- | +| **GitRepository** | Defines the Git repository source that Flux monitors for changes | +| **Kustomization** | Defines which path in the repository to apply and how to reconcile resources | + +### GitRepository + +A `GitRepository` resource points Flux to your OpenChoreo configuration repository: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: openchoreo-gitops + namespace: flux-system +spec: + interval: 1m + url: https://github.com// + ref: + branch: main +``` + +For private repositories, add a secret reference: + +```yaml +spec: + secretRef: + name: git-credentials +``` + +### Kustomizations + +Create `Kustomization` resources to sync different parts of your repository. Use the `dependsOn` field to ensure resources are created in the correct order — cluster-scoped resources first, then platform resources, then application resources. + +```mermaid +flowchart TD + A["GitRepository (openchoreo-gitops)"] --> B["Kustomization (namespaces)"] + A --> C["Kustomization (platform-shared) ClusterComponentTypes, ClusterTraits, ClusterDataPlanes, ClusterWorkflows"] + B --> D["Kustomization (platform) Environments, DeploymentPipelines, ComponentTypes, Traits"] + C --> D + D --> E["Kustomization (projects) Projects, Components, Workloads, ComponentReleases, ReleaseBindings"] +``` + +**Cluster-scoped resources** (`platform-shared/`): + +```yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: openchoreo-platform-shared + namespace: flux-system +spec: + interval: 5m + path: ./platform-shared + prune: true + sourceRef: + kind: GitRepository + name: openchoreo-gitops +``` + +**Platform resources** (depends on namespaces and platform-shared): + +```yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: openchoreo-platform + namespace: flux-system +spec: + interval: 5m + path: ./namespaces//platform + prune: true + targetNamespace: + sourceRef: + kind: GitRepository + name: openchoreo-gitops + dependsOn: + - name: openchoreo-platform-shared +``` + +**Projects and Components** (depends on platform): + +```yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: openchoreo-projects + namespace: flux-system +spec: + interval: 5m + path: ./namespaces//projects + prune: true + targetNamespace: + sourceRef: + kind: GitRepository + name: openchoreo-gitops + dependsOn: + - name: openchoreo-platform +``` + +:::tip Flexible Kustomization Patterns +The structure above follows the [Mono Repository](./overview.md#mono-repository) pattern. You can define Kustomizations to match your team's workflow — per-project, per-component, per-environment, or any combination. OpenChoreo's resource model works with any pattern. +::: + +## Tutorial + +For a hands-on walkthrough that covers setting up Flux CD, building and deploying a multi-component application, and promoting across environments, follow the [GitOps with Flux CD tutorial](https://github.com/openchoreo/sample-gitops/blob/main/flux/README.md) in the sample-gitops repository. + +## See Also + +- [GitOps Overview](./overview.md) — Repository patterns and best practices +- [Flux CD Documentation](https://fluxcd.io/flux/) — Official Flux CD reference diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/identity-configuration.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/identity-configuration.mdx new file mode 100644 index 00000000..8a8d59a4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/identity-configuration.mdx @@ -0,0 +1,258 @@ +--- +title: Identity Provider Configuration +description: Configure identity providers for OpenChoreo. +sidebar_position: 3 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Identity Provider Configuration + +OpenChoreo supports standard OAuth2/OIDC compliant identity providers for user management and authentication. This guide covers the default identity provider setup and how to integrate your own OAuth2/OIDC compliant identity provider. + +## Overview + +OpenChoreo's authentication system supports: + +- **Flexible OAuth2/OIDC compliant identity provider configuration** for secure authentication +- **User and service account identity management** for different access patterns +- **JWT-based token validation** with audience claim verification +- **Multi-plane authentication** with consistent identity management across different OpenChoreo planes + +The identity provider configuration is managed through helm chart values during installation. + +## Default Identity Provider + +OpenChoreo ships with **ThunderID** as the default identity provider. ThunderID is a lightweight, OAuth2/OIDC compliant identity management platform that enables quick setup for development and testing environments. + +### Features + +ThunderID provides out-of-the-box: + +- OAuth2 and OIDC compliant authentication flows +- User and service account identity management +- JWT token issuance and validation +- Pre-configured OAuth applications for OpenChoreo components + +### Trying Out ThunderID + +ThunderID includes a console where you can manage users, applications, and OAuth clients. After deploying OpenChoreo, access the ThunderID console to configure additional identity settings: + +**Access ThunderID console:** + +- URL: `/console` +- Default credentials: + - Username: `admin` + - Password: `admin` + +:::note +The default ThunderID deployment is intended for development and testing. For production deployments, configure your own OAuth2/OIDC-compliant identity provider as described in the next section. +::: + +## Integrating Your Identity Provider + +OpenChoreo allows you to integrate your own OAuth2/OIDC compliant identity provider for production environments. This enables you to leverage your organization's existing identity management infrastructure for user authentication and service account management. + +:::note +If you installed ThunderID during your initial OpenChoreo installation, you can uninstall its Helm release once you have configured and verified your external identity provider. +::: + +### Prerequisites + +Before integrating your identity provider, ensure you have: + +1. An OAuth2/OIDC compliant identity provider accessible from your cluster +2. The following endpoints from your identity provider: + - OIDC Discovery endpoint (`.well-known/openid-configuration`) + - Authorization endpoint + - Token endpoint + - JWKS (JSON Web Key Set) endpoint +3. Knowledge of your provider's issuer and audience claim values + +### Configuration Steps + +OpenChoreo requires identity provider configuration across multiple planes. The following sections describe how to configure each plane during installation. + +#### Control Plane Configuration + +The Control Plane requires identity provider configuration for authenticating API requests and managing user sessions. Configure your identity provider's OIDC settings: + + + {`helm upgrade --install openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --create-namespace \\ + --reuse-values \\ + --set security.oidc.issuer="https://your-idp.example.com" \\ + --set security.oidc.wellKnownEndpoint="https://your-idp.example.com/.well-known/openid-configuration" \\ + --set security.oidc.jwksUrl="https://your-idp.example.com/.well-known/jwks.json" \\ + --set security.oidc.authorizationUrl="https://your-idp.example.com/oauth2/authorize" \\ + --set security.oidc.tokenUrl="https://your-idp.example.com/oauth2/token"`} + + +**Configuration Parameters:** + +- `security.oidc.issuer`: OIDC issuer URL (must match the `iss` claim in JWT tokens) +- `security.oidc.wellKnownEndpoint`: URL to OIDC provider's well-known configuration endpoint +- `security.oidc.jwksUrl`: URL to provider's JWKS endpoint for token signature verification +- `security.oidc.authorizationUrl`: Authorization endpoint for initiating login flow +- `security.oidc.tokenUrl`: Token exchange endpoint for obtaining access tokens +- `security.jwt.audience`: (Optional) Expected audience claim value in JWT tokens. When configured, audience validation is enabled. + +**Optional: JWT Audience Validation** + +If your identity provider includes an audience claim in JWT tokens, you can enable audience validation: + + + {`--set security.jwt.audience="your-audience-value"`} + + +:::note +Audience validation is only performed when `security.jwt.audience` is configured. The value must match the audience claim (`aud`) in the JWT tokens issued by your identity provider. +::: + +#### Observability Plane Configuration + +The Observability Plane validates JWT tokens when querying logs and metrics through the Observer API. Configure your identity provider's OIDC settings: + + + {`helm upgrade --install openchoreo-observability-plane ${versions.helmSource}/openchoreo-observability-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-observability-plane \\ + --create-namespace \\ + --reuse-values \\ + --set security.oidc.issuer="https://your-idp.example.com" \\ + --set security.oidc.jwksUrl="https://your-idp.example.com/.well-known/jwks.json"`} + + +**Configuration Parameters:** + +- `security.oidc.issuer`: OIDC issuer URL (must match the `iss` claim in JWT tokens) +- `security.oidc.jwksUrl`: URL to provider's JWKS endpoint for token signature verification +- `security.jwt.audience`: (Optional) Expected audience claim value in JWT tokens. When configured, audience validation is enabled. +- `security.oidc.jwksUrlTlsInsecureSkipVerify`: (Optional) Skip TLS certificate verification for JWKS endpoint + +**Optional: JWT Audience Validation** + +If your identity provider includes an audience claim in JWT tokens, you can enable audience validation: + + + {`--set security.jwt.audience="your-audience-value"`} + + +**Optional: Skip TLS Verification** + +For development or testing environments where your identity provider uses self-signed certificates, you can skip TLS verification: + + + {`--set security.oidc.jwksUrlTlsInsecureSkipVerify="true"`} + + +:::warning +Only use `jwksUrlTlsInsecureSkipVerify="true"` in development or testing environments. For production deployments, ensure your identity provider uses valid TLS certificates. +::: + +:::note +Different identity providers use different JWT claim names (for example, `roles` instead of `groups` for user groups). After configuring your identity provider, review the [Subject Types configuration](./authorization.md#subject-types) in the Authorization guide to ensure the claim mappings match the tokens your identity provider issues. +::: + +## OAuth Client Configurations + +After integrating your identity provider, configure OAuth applications/clients for OpenChoreo components that require authentication. Each component needs specific redirect URIs and scopes configured in your identity provider. + +The following components require OAuth client configuration: + +**Backstage (Developer Portal):** + +- For configuration steps, refer to the [Backstage Configuration](./backstage-configuration.mdx#authentication) guide + +**SRE Agent:** + +- For configuration steps, refer to the [SRE Agent Configuration](../ai/sre-agent.mdx#authentication-and-authorization) guide + +**CLI (occ):** + +- For configuration steps, refer to the [CLI Configuration](./cli-configuration.mdx#using-an-external-identity-provider) guide + +**Workload Publisher (CI Workflows):** + +- For configuration steps, see the [Workload Publishing Credentials](./workflows/workflow-workload-configuration.mdx) guide + +**Observer (uid-resolver):** + +- For configuration steps, refer to the [Observer External IDP Configuration](./observability-alerting.mdx#observer-external-idp-configuration) guide + +:::tip +Store sensitive values like client secrets using Kubernetes secrets rather than directly in helm values. Refer to the [Secret Management](./secret-management.mdx) guide for best practices. +::: + +## Obtaining Identity Provider Configuration + +Most OAuth2/OIDC compliant identity providers expose their configuration through a well-known endpoint. You can typically find all required URLs by accessing: + +``` +https://your-idp.example.com/.well-known/openid-configuration +``` + +This endpoint returns a JSON document containing: + +- `issuer`: The issuer identifier +- `authorization_endpoint`: Authorization URL +- `token_endpoint`: Token URL +- `jwks_uri`: JWKS URL + +Refer to your identity provider's documentation for specific instructions on: + +- Obtaining the well-known configuration endpoint +- Creating OAuth applications/clients +- Configuring redirect URIs +- Managing client credentials +- Setting up user groups and roles + +## Verification + +After configuring your identity provider, verify the setup: + +1. **Check Control Plane logs** for any authentication configuration errors: + + ```bash + kubectl logs -n openchoreo-control-plane --tail=50 + ``` + +2. **Test authentication flow** by accessing the Backstage UI and verifying you're redirected to your identity provider's login page + +3. **Verify token validation** by making authenticated API requests and checking that tokens are properly validated + +## Troubleshooting + +### Common Issues + +**Login redirect fails:** + +- Verify redirect URIs in your OAuth application match exactly (including protocol and port) +- Check that authorization and token URLs are accessible from the cluster +- Ensure DNS resolution works for your identity provider endpoints + +**Token validation errors:** + +- Ensure the `issuer` value matches the `iss` claim in JWT tokens +- Verify the JWKS URL is accessible and returns valid public keys +- Confirm the `audience` claim in tokens matches the configured value + +**Connection timeouts:** + +- Verify network connectivity from the cluster to your identity provider +- Check firewall rules and network policies +- Ensure TLS certificates are valid and trusted + +For additional support, refer to the [OpenChoreo GitHub issues](https://github.com/openchoreo/openchoreo/issues) or join the [CNCF Slack (#openchoreo)](https://slack.cncf.io/). + +## Next Steps + +After configuring your identity provider: + +- [Configure Authorization](./authorization.md) to set up roles, role bindings, and subject types that map JWT claims to OpenChoreo's authorization system +- [Configure Backstage](./backstage-configuration.mdx#authentication) OAuth client for the Backstage Portal +- [Set up Secret Management](./secret-management.mdx) for secure credential storage +- Review the [Control Plane](../reference/helm/control-plane.mdx) and [Observability Plane](../reference/helm/observability-plane.mdx) Helm references for all available configuration options diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.drawio b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.drawio new file mode 100644 index 00000000..813df1fe --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.drawio @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.svg b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.svg new file mode 100644 index 00000000..d6a58449 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/air-gapped-installation-overview.svg @@ -0,0 +1,4 @@ + + + +
Connected side
Upstream sources
Container Images
OCI Helm Charts
Remote Configuration Files
Staging host
helm template → images.txt
crane pull → image tarballs
helm pull → chart .tgz
curl → files
Air-gapped side
Operator workstation
carried-in tarballs
Private mirror registry
Kubernetes cluster(s)
OpenChoreo planes + workloads
Approved transfer medium
images.txt · image tarballs
chart .tgz · configuration files
AIR GAP
download
crane push
helm · kubectl
image pulls
Text is not SVG - cannot display
\ No newline at end of file diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/catalog-import-wizard.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/catalog-import-wizard.png new file mode 100644 index 00000000..a9669715 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/catalog-import-wizard.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/create-page.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/create-page.png new file mode 100644 index 00000000..c09950d0 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/create-page.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/custom-templates-in-scaffolder.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/custom-templates-in-scaffolder.png new file mode 100644 index 00000000..23686b4b Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/images/custom-templates-in-scaffolder.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/building-a-module.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/building-a-module.md new file mode 100644 index 00000000..bf254cf5 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/building-a-module.md @@ -0,0 +1,320 @@ +--- +title: Building a Module +description: A guide for module authors on how to create, package, and contribute new modules to extend OpenChoreo's platform capabilities. +sidebar_position: 2 +--- + +# Building a Module + +This guide is for platform engineers and community contributors who want to build a new module for OpenChoreo. As described in the [Modules overview](../overview), there are two types of modules: **OpenChoreo Modules** and **Curated Backstage Modules**. The process for building each is different. + +--- + +## Building an OpenChoreo Module + +OpenChoreo Modules extend the platform runtime at one of the defined extensibility areas: API Gateway, CI, Observability, or GitOps. + +### Prerequisites + +Before building an OpenChoreo module, you should be familiar with: + +- Kubernetes and Helm charts +- The OpenChoreo [architecture](../../../overview/architecture) and the plane you are targeting +- The specific extensibility area your module integrates with (API Gateway, CI, Observability, or GitOps) + +### What Is an OpenChoreo Module? + +An OpenChoreo module is a Helm chart that: + +1. **Installs the underlying tool** into the target Kubernetes cluster (data plane, workflow plane, or observability plane). +2. **Wires it into OpenChoreo integration contracts**, so the control plane and other components can interact with it correctly. +3. **Provides documentation** so operators know how to configure and use it. + +Modules are hosted in the [openchoreo/community-modules](https://github.com/openchoreo/community-modules) repository and are discoverable through the [OpenChoreo Modules Catalog](/modules). + +### Integration Requirements by Area + +Each extensibility area has specific integration requirements that your module must satisfy for OpenChoreo to work with it correctly. + +#### API Gateway Module + +An API Gateway module must provide a [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/) compliant implementation. OpenChoreo's control plane creates `Gateway` and `HTTPRoute` resources to route traffic, and expects a compatible gateway controller to fulfill them. + +**Requirements:** + +- Install a `GatewayClass` resource that identifies the gateway implementation. +- The gateway controller must accept `Gateway` resources and route traffic based on `HTTPRoute` objects created by OpenChoreo. +- Configure the gateway to be installed in the data plane namespace (by default `openchoreo-data-plane`). +- Document any additional configuration required for TLS termination, external access, and traffic policies. + +**Reference implementations**: [gateway-kong](https://github.com/openchoreo/community-modules/tree/main/gateway-kong) and [gateway-envoy-gateway](https://github.com/openchoreo/community-modules/tree/main/gateway-envoy-gateway). + +--- + +#### CI Module + +OpenChoreo currently uses **[Argo Workflows](https://argoproj.github.io/workflows/)** as its default and only natively supported CI engine. The `Workflow` CRD's `runTemplate` field directly embeds Argo Workflow specs (e.g., `apiVersion: argoproj.io/v1alpha1, kind: Workflow`), and there is no engine-agnostic CI module abstraction yet. + +Building a CI module today means creating `ClusterWorkflow` and `ClusterWorkflowTemplate` resources that define Argo Workflow templates, and installing Argo Workflows into the workflow plane cluster. + +**Requirements:** + +- Install Argo Workflows into the workflow plane cluster. +- Define `ClusterWorkflowTemplate` resources for individual workflow steps (checkout, build, push, etc.). +- Define `ClusterWorkflow` or `Workflow` resources with `runTemplate` containing an Argo Workflow spec that references your templates. + +:::note +Support for alternative workflow engines (e.g., Tekton Pipelines) would require controller-level changes and is not available as a drop-in module today. For CI systems outside the workflow plane, see [External CI Integration](../workflows/external-ci.mdx). +::: + +**Reference**: See [CI Governance](../workflows/ci-governance.md) for the workflow contract, and [Schema Syntax](../workflows/schema-syntax.md) for the workflow schema. + +--- + +#### Observability Modules + +There are 3 types of observability modules: logs, metrics, and tracing. Each module integrates a specific observability backend with the OpenChoreo platform. + +##### The Adapter Pattern + +OpenChoreo uses an **adapter pattern** to decouple the Observer from specific backend implementations. The Observer is the platform component responsible for serving observability data to the rest of the platform (e.g., the Backstage portal and the platform API). Rather than coupling the Observer directly to each backend's native query API, each observability module provides an **adapter** — a lightweight service that translates between the Observer's standardized API and the backend's native interface. + +```mermaid +flowchart LR + A[Observer] -->|Standardized API| B[Adapter] + B -->|Native Query API| C[Logs Backend] +``` + +The adapter is a component that must be written by the module author and deployed alongside the logging backend. When the Observer needs to retrieve logs, it makes HTTP requests to the adapter using a well-defined OpenAPI contract. The adapter receives these requests, queries the underlying logs backend using its native API or SDK, transforms the results into the standardized response format, and returns them to the Observer. + +This pattern provides several benefits: + +- **Backend independence** — The Observer does not need to know how to query each specific backend. Adding support for a new logging backend only requires writing a new adapter. +- **Stable contract** — The API contract between the Observer and the adapter is versioned and stable, so module authors can upgrade or replace their backend without affecting the rest of the platform. +- **Separation of concerns** — The adapter encapsulates all backend-specific logic (connection handling, query translation, authentication), keeping the Observer focused on aggregation and serving. + +##### Observability Logs Module + +A logs module must provide two components: + +1. **A log aggregation backend** — The storage and query engine for logs (e.g., OpenSearch, OpenObserve, Loki). +2. **A logging adapter** — A service that implements the [Logging Adapter API](../observability-logging-adapter-api) and acts as the bridge between the Observer and the log backend. + +The logging adapter must: + +- Implement the endpoints defined in the [Logging Adapter API specification](../observability-logging-adapter-api) +- Translate the standardized log query parameters (time range, search scope, log levels, search phrase) into the backend's native query format. +- Return log entries in the standardized response format, including structured metadata. + +The module's Helm chart should deploy both the backend and the adapter, and configure the adapter's service endpoint so the Observer can discover and communicate with it. + +Reference implementation: [observability-logs-openobserve module](https://github.com/openchoreo/community-modules/tree/main/observability-logs-openobserve) + +##### Observability Metrics Module + +Like the logs module, a metrics module follows the same adapter pattern. The module must provide two components: + +1. **A metrics backend** — The storage and query engine for metrics (e.g., Prometheus). +2. **A metrics adapter** — A service that implements the [Metrics Adapter API](../observability-metrics-adapter-api) and acts as the bridge between the Observer and the metrics backend. + +The metrics adapter must: + +- Implement the endpoints defined in the [Metrics Adapter API specification](../observability-metrics-adapter-api) +- Translate the standardized metrics query parameters (time range, search scope, metric names) into the backend's native query format. +- Return metrics data in the standardized response format, including metric metadata and data points. +- Support alert rule management endpoints for creating, updating, and deleting alert rules in the metrics backend. + +The module's Helm chart should deploy both the backend and the adapter, and configure the adapter's service endpoint so the Observer can discover and communicate with it. + +##### Observability Tracing Module + +Like the logs and metrics modules, a tracing module follows the same adapter pattern. The module must provide two components: + +1. **A trace aggregation backend** — The storage and query engine for traces (e.g., OpenSearch, Jaeger, Tempo). +2. **A tracing adapter** — A service that implements the [Tracing Adapter API](../observability-tracing-adapter-api) and acts as the bridge between the Observer and the trace backend. + +The tracing adapter must: + +- Implement the endpoints defined in the [Tracing Adapter API specification](../observability-tracing-adapter-api) +- Translate the standardized trace query parameters (time range, search scope, sort order) into the backend's native query format. +- Return traces, spans, and span details in the standardized response format, including span attributes and resource attributes. + +##### Unit Testing + +Observability modules that include adapters must have unit tests. The module's `Makefile` must include a `unit-test` target that: + +1. Runs the module's unit test suite. +2. Moves the coverage report to the repository root as `-coverage.out` (e.g., `observability-logs-openobserve-coverage.out`). + +For example, a Go-based module's `Makefile` would include: + +```makefile +MODULE_NAME := $(notdir $(CURDIR)) + +unit-test: + go test -coverprofile=coverage.out ./... + mv coverage.out ../$(MODULE_NAME)-coverage.out +``` + +The CI pipeline automatically discovers and runs `make unit-test` for every changed module that has a `Makefile` with a `unit-test` target. The coverage reports at the repository root are then uploaded to Codecov. + +--- + +#### GitOps Module + +A GitOps module installs a continuous delivery tool that manages workload synchronization from a Git repository. OpenChoreo's controllers produce declarative resource manifests and expect the GitOps engine to apply and reconcile them in the target cluster. + +**Requirements:** + +- Install the GitOps engine into the target cluster. +- The engine must support reconciling Kubernetes manifests from a Git repository. +- Provide a mechanism (CRD or API) through which OpenChoreo can configure sync targets (repository, path, branch, interval). +- Expose sync status for OpenChoreo to surface to operators. + +**Reference**: See the [Flux CD getting started guide](../../gitops/overview) for the existing integration pattern. + +--- + +### Publishing an OpenChoreo Module + +Once your module is ready, follow these steps to publish it. + +#### 1. Open a Pull Request to community-modules + +Fork the [openchoreo/community-modules](https://github.com/openchoreo/community-modules) repository and open a pull request with your module directory. Include in the PR description: + +- What tool the module integrates +- Which extensibility area it targets +- How to install and configure it +- Any known limitations or prerequisites + +#### 2. Add an Entry to the Ecosystem Catalog + +To make your module discoverable in the [Ecosystem Catalog](/ecosystem), add an entry to `src/data/marketplace-plugins.json` in the [openchoreo/openchoreo.github.io](https://github.com/openchoreo/openchoreo.github.io) repository: + +```json +{ + "id": "", + "group": "module", + "name": "", + "description": "", + "category": "", + "tags": ["", ""], + "logoUrl": "", + "author": "", + "sourceUrl": "", + "default": false, + "released": true +} +``` + +| Field | Description | +| ------------- | -------------------------------------------------------------------------------------------------- | +| `id` | Unique identifier for the module (lowercase, hyphenated) | +| `group` | Type of ecosystem item: `module`, `integration`, `workflow`, `component-type`, `agent`, or `skill` | +| `name` | Display name of the module | +| `description` | Short description of what the module does | +| `category` | Category for grouping: `API Gateway`, `CI`, `Observability`, `GitOps`, `AI`, `Database`, etc. | +| `tags` | Array of tags for searchability | +| `logoUrl` | URL to the tool's logo (SVG or PNG) | +| `author` | Author or organization name (typically `OpenChoreo` for community modules) | +| `sourceUrl` | Link to the module source code or documentation | +| `default` | Whether this module is a default/core module (`true` or `false`) | +| `released` | Whether the module is released and available (`true` or `false`) | + +#### 3. Write Documentation + +If your module requires configuration steps beyond Helm chart installation, contribute a documentation page to the [openchoreo/openchoreo.github.io](https://github.com/openchoreo/openchoreo.github.io) repository under `docs/platform-engineer-guide/`. + +At minimum, your module `README.md` should cover: + +- Prerequisites and compatibility requirements +- Installation steps with example Helm values +- Configuration options for integrating with OpenChoreo +- How to verify the module is working correctly + +--- + +## Building a Curated Backstage Module + +Curated Backstage Modules are Backstage plugins that have been validated and bundled into the OpenChoreo Backstage portal. Because Backstage plugins are compiled into the portal at build time, contributing a Curated Backstage Module requires forking the portal, adding the plugin, and building a custom portal image. + +### Prerequisites + +Before building a Curated Backstage Module, you should be familiar with: + +- [Backstage](https://backstage.io) architecture and plugin development +- React and TypeScript (for frontend plugins) +- Node.js package management (yarn) +- Docker image building and publishing + +### How Curated Backstage Modules Work + +The OpenChoreo Backstage portal is a standard Backstage application that ships with a curated set of plugins pre-installed. To add a new Backstage plugin as a Curated Backstage Module: + +1. Fork the [openchoreo/backstage-plugins](https://github.com/openchoreo/backstage-plugins) repository. +2. Install the desired Backstage plugin package into the portal. +3. Wire the plugin into the Backstage app configuration. +4. Build and publish your customized portal image. +5. Deploy using the updated image. + +### Step-by-Step Guide + +#### 1. Fork and Clone the Portal + +Fork the [openchoreo/backstage-plugins](https://github.com/openchoreo/backstage-plugins) repository and clone it locally: + +```bash +git clone https://github.com//backstage.git +cd backstage +yarn install +``` + +#### 2. Install the Plugin + +Install the Backstage plugin package you want to add. Most plugins consist of a frontend package, and some also have a backend package: + +```bash +# Frontend plugin +yarn --cwd packages/app add @backstage-community/ + +# Backend plugin (if applicable) +yarn --cwd packages/backend add @backstage-community/-backend +``` + +#### 3. Wire the Plugin + +Follow the plugin's installation instructions to register it with the Backstage app. This typically involves editing: + +- `packages/app/src/App.tsx` — to add frontend routes and components +- `packages/app/src/plugins.ts` — to register the plugin +- `packages/backend/src/index.ts` — to register backend features (if applicable) +- `app-config.yaml` — to add plugin-specific configuration + +#### 4. Build and Publish the Portal Image + +Build the Backstage portal and package it as a Docker image: + +```bash +yarn build:all +docker build -t //backstage: . +docker push //backstage: +``` + +#### 5. Deploy the Custom Portal + +Update your OpenChoreo Backstage deployment to use the new image. See [Backstage Configuration](../../backstage-configuration) for deployment details. + +### Contributing to the OpenChoreo Portal + +If you believe a plugin should be included in the official OpenChoreo Backstage portal, open a pull request against the [openchoreo/backstage-plugins](https://github.com/openchoreo/backstage-plugins) repository with the plugin integrated and a clear description of the use case it addresses. + +To make your module visible in the [Ecosystem Catalog](/ecosystem), also add an entry to `src/data/marketplace-plugins.json` in the [openchoreo/openchoreo.github.io](https://github.com/openchoreo/openchoreo.github.io) repository with `"category": "Backstage"`. + +## Getting Help + +If you have questions or need feedback on your module: + +- Join the [CNCF Slack (#openchoreo)](https://slack.cncf.io/) and reach out. +- Open a [GitHub Discussion](https://github.com/openchoreo/openchoreo/discussions) for design questions or architectural feedback. +- Browse existing modules in the [community-modules repository](https://github.com/openchoreo/community-modules) for reference implementations. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-logging-adapter-api.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-logging-adapter-api.mdx new file mode 100644 index 00000000..e5f92169 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-logging-adapter-api.mdx @@ -0,0 +1,15 @@ +--- +title: Logs Adapter API Reference +description: OpenAPI specification for the logs adapter that integrates a log backend with the OpenChoreo Observer. +sidebar_position: 4 +--- + +import SwaggerUI from "@site/src/components/SwaggerUI"; + +# Logging Adapter API Reference + +This is the OpenAPI specification that a logging adapter must implement to integrate with the OpenChoreo Observer. The Observer calls these endpoints to query logs and manage alert rules from the logging backend your module provides. + +For an overview of the adapter pattern and how it fits into the observability architecture, see [Building an Observability Module](../building-a-module#observability-modules). + + diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-metrics-adapter-api.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-metrics-adapter-api.mdx new file mode 100644 index 00000000..3d062eab --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-metrics-adapter-api.mdx @@ -0,0 +1,15 @@ +--- +title: Metrics Adapter API Reference +description: OpenAPI specification for the metrics adapter that integrates a metrics backend with the OpenChoreo Observer. +sidebar_position: 6 +--- + +import SwaggerUI from "@site/src/components/SwaggerUI"; + +# Metrics Adapter API Reference + +This is the OpenAPI specification that a metrics adapter must implement to integrate with the OpenChoreo Observer. The Observer calls these endpoints to query metrics and manage alert rules from the metrics backend your module provides. + +For an overview of the adapter pattern and how it fits into the observability architecture, see [Building an Observability Module](../building-a-module#observability-modules). + + diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-tracing-adapter-api.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-tracing-adapter-api.mdx new file mode 100644 index 00000000..66274121 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/observability-tracing-adapter-api.mdx @@ -0,0 +1,15 @@ +--- +title: Tracing Adapter API Reference +description: OpenAPI specification for the tracing adapter that integrates a trace backend with the OpenChoreo Observer. +sidebar_position: 5 +--- + +import SwaggerUI from "@site/src/components/SwaggerUI"; + +# Tracing Adapter API Reference + +This is the OpenAPI specification that a tracing adapter must implement to integrate with the OpenChoreo Observer. The Observer calls these endpoints to query traces, spans, and span details from the tracing backend your module provides. + +For an overview of the adapter pattern and how it fits into the observability architecture, see [Building an Observability Module](../building-a-module#observability-modules). + + diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/overview.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/overview.md new file mode 100644 index 00000000..8c434d88 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/modules/overview.md @@ -0,0 +1,112 @@ +--- +title: Modules Overview +description: Understand OpenChoreo's modular architecture and the extensibility areas that allow platform operators to customize their Internal Developer Platform. +sidebar_position: 1 +--- + +# Modules + +OpenChoreo is designed from the ground up as a modular Internal Developer Platform (IDP). Rather than coupling to a fixed set of tools, OpenChoreo defines clear integration points where operators can plug in the tools that best suit their organization. + +## What Are Modules? + +Modules are pluggable integrations that extend OpenChoreo platform capabilities at defined extensibility points. There are two main types of modules: + +### OpenChoreo Modules + +OpenChoreo Modules extend platform-defined extension points across OpenChoreo planes — the Data Plane, Workflow Plane, Observability Plane, and Control Plane. Each module integrates a third-party tool at one of these extension points, covering areas such as API Gateway, CI, Observability, and GitOps. Modules are packaged as Helm charts, making them straightforward to install and configure on any compatible Kubernetes cluster. + +OpenChoreo modules are hosted in the [openchoreo/community-modules](https://github.com/openchoreo/community-modules) repository. Some modules are used by default in the OpenChoreo installation, while others are **community** modules that operators can install to replace or supplement the defaults. + +### Curated Backstage Modules + +Curated Backstage Modules are Backstage plugins that have been validated and bundled into the OpenChoreo Backstage portal. These modules extend the developer portal experience with additional capabilities. + +Unlike OpenChoreo modules, Curated Backstage Modules are not installed independently - they are compiled into the portal itself. To add a Curated Backstage Module, you fork the [OpenChoreo Backstage portal](https://github.com/openchoreo/backstage-plugins), add the plugin, and build your own portal image. + +--- + +You can discover all available modules in the [OpenChoreo Modules Catalog](/modules). + +## Why a Modular Architecture? + +Internal Developer Platforms need to serve diverse organizations with different tool preferences, scaling requirements, and existing investments in specific tools and technologies. A prescriptive, monolithic platform forces operators into a single stack, even when parts of it conflict with tools they have already standardized on or built expertise around. + +OpenChoreo adopts a modular architecture for three key reasons: + +**No vendor lock-in** + +Platform critical capabilities like API gateway, CI, observability, and GitOps are all pluggable. Operators choose the tools they trust and can swap them as the ecosystem evolves without rebuilding their platform. + +**Lean by default, extensible on demand** + +OpenChoreo ships with sensible defaults (kgateway, Argo Workflows, OpenSearch, Flux CD) so you can get started immediately. But you can replace or supplement these defaults with alternatives that fit your specific needs, avoiding unnecessary complexity for teams that don't require it. + +**Community driven ecosystem** + +Modules are maintained independently of the core platform. The community can build, publish, and maintain integrations without requiring changes to OpenChoreo itself. This keeps the core platform focused and stable while allowing the ecosystem to grow organically. + +## Extensibility Areas + +OpenChoreo Modules and Curated Backstage Modules each target distinct extensibility areas. OpenChoreo Modules extend the capabilities of the OpenChoreo planes, while Curated Backstage Modules expand what the developer portal can offer. + +### OpenChoreo Module Areas + +The following areas correspond to functional planes in the platform where OpenChoreo modules can be plugged in. + +#### API Gateway + +The API Gateway layer routes external and internal traffic to components deployed in data planes. OpenChoreo supports any [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/) compliant implementation, giving operators the freedom to choose their preferred gateway technology. + +| | | +| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| **Default module** | [kgateway](https://kgateway.dev/) - a high-performance, Envoy-based gateway, pre-configured as part of the standard data plane installation | +| **Community modules** | Kong Ingress Controller, Envoy Gateway, Traefik, Apache APISIX, WSO2 API Platform | + +#### CI + +The Workflow Plane executes container image builds and automation tasks through the `Workflow` abstraction. Platform engineers define reusable Workflow templates with parameter schemas; developers provide build-specific values when creating WorkflowRuns. Workflows support governance via ComponentType's `allowedWorkflows` list, letting operators control which build processes components can use. + +| | | +| --------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| **Default module** | [Argo Workflows](https://argoproj.github.io/workflows/) - a Kubernetes-native workflow engine for building and automation | +| **External CI integration** | Any CI system (Jenkins, GitHub Actions, GitLab CI, etc.) can integrate via the [Workload API](../workflows/external-ci.mdx) | + +:::note +Argo Workflows is currently the only natively supported CI engine. The `Workflow` CRD's `runTemplate` directly embeds Argo Workflow specs. Support for alternative engines (e.g., Tekton Pipelines) would require controller-level changes and is not available as a drop-in module today. +::: + +See [CI Governance](../workflows/ci-governance.md) for details on governance, auto-build, and component-specific workflows. + +#### Observability + +The Observability Plane aggregates logs, traces, and metrics from across all planes. Each observability signal has its own pluggable module, so operators can mix and match backends independently. + +| Signal | Default module | Community modules | +| ------- | --------------------------------------- | --------------------------- | +| Logs | OpenSearch with Fluent Bit | OpenObserve, AWS CloudWatch | +| Tracing | OpenSearch with OpenTelemetry Collector | OpenObserve, AWS X-Ray | +| Metrics | Prometheus | AWS CloudWatch | + +#### GitOps + +The GitOps module handles continuous delivery, keeping deployed workloads in sync with declarative configuration stored in Git. OpenChoreo's reconciliation controllers work alongside the GitOps engine to detect drift and trigger re-deployments. + +| | | +| --------------------- | --------------------------------------------------------------- | +| **Default module** | [Flux CD](https://fluxcd.io/) - a CNCF graduated GitOps toolkit | +| **Community modules** | Argo CD | + +### Curated Backstage Module Area + +Curated Backstage Modules extend the OpenChoreo developer portal. The OpenChoreo Backstage portal ships with a curated set of built-in plugins, and operators can add more by forking the portal repository and bundling additional Backstage plugins. + +Any plugin from the [Backstage plugin marketplace](https://backstage.io/plugins) can be contributed as a Curated Backstage Module - examples include cost visibility plugins, incident management integrations, API documentation renderers, and internal tooling portals. + +See [Backstage Configuration](../../backstage-configuration) for details on setting up and customizing the developer portal. + +## Browsing Available Modules + +Visit the [OpenChoreo Modules Catalog](/modules) to browse all available modules by category, including their release status and links to installation guides. + +To contribute a new module or integrate a tool not yet in the catalog, see [Building a Module](../building-a-module). diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/multi-cluster-connectivity.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/multi-cluster-connectivity.mdx new file mode 100644 index 00000000..1c04a509 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/multi-cluster-connectivity.mdx @@ -0,0 +1,527 @@ +--- +title: Multi-Cluster Connectivity +description: Configure secure mTLS communication between OpenChoreo planes in multi-cluster deployments. +sidebar_position: 5 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import CodeBlock from "@theme/CodeBlock"; + +# Multi-Cluster Connectivity + +When deploying OpenChoreo across multiple Kubernetes clusters (e.g., separate Control Plane and Data Plane clusters), you must explicitly establish trust between them. This guide covers the step-by-step process of exchanging certificates to secure the WebSocket connection between planes. + +## Overview + +The OpenChoreo Control Plane runs a **Cluster Gateway** that listens for incoming WebSocket connections from remote planes (Data Plane, Workflow Plane, Observability Plane). This connection is secured using **Mutual TLS (mTLS)**. + +1. **Server Trust:** The remote plane must trust the Control Plane's CA certificate to verify the Cluster Gateway's identity. +2. **Client Authentication:** The remote plane's **Cluster Agent** generates its own client certificate using a local self-signed issuer. This certificate must be registered with the Control Plane to allow the connection. + +:::note +In multi-cluster deployments, the agent's client certificate is self-signed because the Control Plane's CA private key cannot be shared across clusters. The Control Plane trusts the agent by explicitly registering the agent's certificate in the DataPlane/WorkflowPlane/ObservabilityPlane CRD. +::: + +:::info[Internal API authentication] +Separately from the agent-facing WebSocket connection above, the Cluster Gateway also exposes an **internal API** on port `:8444` — used by `openchoreo-api` and the controller manager to proxy, `exec`, and stream logs into connected planes' Kubernetes APIs. It is reachable only from inside the Control Plane cluster (via the `cluster-gateway` Service) and is protected by its **own** mTLS, using a dedicated internal CA (`cluster-gateway-internal-ca`) that is deliberately separate from the agent CA, so a plane agent's certificate cannot authenticate to the internal API. cert-manager provisions the internal CA and the per-caller client certificates (for `openchoreo-api` and the controller manager) automatically — no manual certificate exchange is required. + +Enforcement is **on by default** (`clusterGateway.internalMtls.enabled=true`): callers must present a certificate signed by the internal CA, or they are rejected during the TLS handshake. Any tooling that reaches `:8444` from outside this Helm release (debugging scripts, `kubectl port-forward` workflows) needs such a certificate. Set `clusterGateway.internalMtls.enabled=false` to restore unauthenticated access — for local development only. +::: + +## Prerequisites + +- **Control Plane** installed in a primary cluster +- **Remote Cluster** (Data, Build, or Observability) where the remote plane will be installed +- `kubectl` context configured for both clusters + +Each remote cluster must have certain prerequisites installed **before** deploying a plane. The exact set depends on the plane type: + +| Component | Data Plane | Workflow Plane | Observability Plane | +| --------------------------------------------------------- | :--------: | :------------: | :-----------------: | +| [Gateway API CRDs](https://gateway-api.sigs.k8s.io/) | Yes | No | Yes | +| [cert-manager](https://cert-manager.io/) | Yes | Yes | Yes | +| [External Secrets Operator](https://external-secrets.io/) | Yes | Yes | Yes | +| [kgateway](https://kgateway.dev/) | Yes | No | Yes | + +See the [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) guide for install commands for each prerequisite. + +:::note[Secret stores on remote clusters] +The plane CRD `secretStoreRef` is resolved on the Control Plane cluster, so remote clusters don't need their own secret backend for that purpose. Individual workloads or modules on remote clusters may still need local secrets depending on your setup. See [Secret Management](./secret-management.mdx) for details. +::: + +## Step 0: Configure Cluster Gateway Certificate SANs + +Before extracting the CA, ensure the Control Plane's Cluster Gateway certificate includes the hostname or IP that remote agents will connect to. By default, the certificate only includes internal cluster DNS names. + +When installing or upgrading the Control Plane, add your public DNS name: + +```bash +helm upgrade --install openchoreo-control-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \ + --namespace openchoreo-control-plane \ + # ... other values ... + --set "clusterGateway.tls.dnsNames[0]=cluster-gateway.openchoreo-control-plane.svc" \ + --set "clusterGateway.tls.dnsNames[1]=cluster-gateway.openchoreo-control-plane.svc.cluster.local" \ + --set "clusterGateway.tls.dnsNames[2]=cluster-gateway.openchoreo.${DOMAIN}" +``` + +Or in a values file: + +```yaml +clusterGateway: + tls: + dnsNames: + - cluster-gateway.openchoreo-control-plane.svc + - cluster-gateway.openchoreo-control-plane.svc.cluster.local + - cluster-gateway.openchoreo.example.com # Your public DNS name +``` + +:::warning +The `serverUrl` hostname in Step 2 must match one of the DNS SANs (or IP SANs) in the Cluster Gateway certificate. If not, TLS verification will fail with a certificate error. +::: + +:::tip[Connecting by IP address] +If remote agents connect to the Cluster Gateway by IP address rather than a DNS name (common in local or lab setups), the IP must appear in the certificate's `ipAddresses` field, not `dnsNames`. X.509 validation rejects IP addresses in DNS SANs. + +The Helm chart currently only exposes `clusterGateway.tls.dnsNames`. To add an IP SAN, patch the Certificate resource after installation: + +```bash +kubectl patch certificate cluster-gateway-tls -n openchoreo-control-plane --type merge -p "{ + \"spec\": { + \"ipAddresses\": [\"${GATEWAY_IP}\"] + } +}" + +# Force reissuance +kubectl delete secret cluster-gateway-tls -n openchoreo-control-plane +kubectl wait --for=condition=Ready certificate/cluster-gateway-tls \ + -n openchoreo-control-plane --timeout=60s + +# Restart the gateway to pick up the new certificate +kubectl rollout restart deployment/cluster-gateway -n openchoreo-control-plane +``` + +::: + +#### Expose the Cluster Gateway + +The Cluster Gateway is fronted by two Services: + +- **`cluster-gateway`** — an internal `ClusterIP` Service reachable only from within the Control Plane cluster. It carries the internal API listener (`:8444`) and also serves in-cluster agents on `:8443`. +- **`cluster-gateway-external`** — the Service you expose to remote clusters. It publishes **only** the `:8443` WebSocket listener; the internal API (`:8444`) is deliberately absent, so exposing this Service can never publish the internal surfaces. + +Remote planes connect through `cluster-gateway-external`, which defaults to `ClusterIP`. For remote planes to connect, you need to expose it externally. + +**Option A: LoadBalancer service** (simplest for dedicated IPs) + +Set the service type to `LoadBalancer` in the control plane helm values. This applies to the external Service (`cluster-gateway-external`): + +```yaml +clusterGateway: + service: + type: LoadBalancer +``` + +After upgrading the helm release, get the external IP from the external Service: + +```bash +# Wait for the LoadBalancer to assign an external address (IP or hostname). +# Some cloud LoadBalancers expose an IP, others (e.g. AWS ELB/NLB) a hostname. +until GATEWAY_IP=$(kubectl get svc cluster-gateway-external -n openchoreo-control-plane \ + -o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}') \ + && [ -n "$GATEWAY_IP" ]; do + echo "Waiting for cluster-gateway-external to get an external address..." + sleep 5 +done +export GATEWAY_IP +echo "Cluster Gateway: wss://${GATEWAY_IP}:8443/ws" +``` + +**Option B: TLS passthrough via kgateway** (reuses the existing LoadBalancer) + +Route agent connections through the existing kgateway LoadBalancer using TLS passthrough: + +```yaml +clusterGateway: + tlsRoute: + enabled: true + hosts: + - host: cluster-gateway.openchoreo.example.com +``` + +This creates a TLSRoute that passes WebSocket connections through to the external Cluster Gateway Service (`cluster-gateway-external`) based on the SNI hostname. The hostname must match one of the `clusterGateway.tls.dnsNames` configured above. + +See the [Control Plane Helm Reference](../reference/helm/control-plane.mdx) for all `clusterGateway.*` parameters. + +## Step 1: Extract Control Plane CA + +The Control Plane generates a Certificate Authority (CA) used to sign the Cluster Gateway's serving certificate. Remote planes need this CA to verify they are connecting to the authentic Control Plane. + +Run this command against your **Control Plane cluster**: + +```bash +# Set your Control Plane context and namespace +export CP_CONTEXT="my-control-plane-cluster" +export CP_NAMESPACE="openchoreo-control-plane" + +# Extract the CA certificate from the Secret +export CP_CA_CERT=$(kubectl --context $CP_CONTEXT get secret cluster-gateway-ca \ + -n $CP_NAMESPACE -o jsonpath='{.data.ca\.crt}' | base64 -d) + +# Verify the output (should start with -----BEGIN CERTIFICATE-----) +echo "$CP_CA_CERT" | head -n 5 +``` + +:::warning +Extract the CA from the `cluster-gateway-ca` **Secret** (not the ConfigMap of the same name). The ConfigMap is populated by a one-shot Job (`cluster-gateway-ca-extractor`) that runs at install time. If the Job runs before the CA is ready, the ConfigMap may contain a placeholder instead of the real certificate. The Secret always contains the actual CA. +::: + +## Step 2: Install Remote Plane with CA + +When installing a remote plane (e.g., Data Plane), create a ConfigMap with the extracted CA certificate and point the Cluster Agent to that ConfigMap. This configures the agent to trust your Control Plane and use a locally-generated client certificate. + +**Example: Data Plane Installation** + +First, save the extracted CA certificate to a file: + +```bash +# Save the CA certificate to a file +echo "$CP_CA_CERT" > ./server-ca.crt +``` + +Then create the CA ConfigMap and install the Data Plane: + +```bash +# Set your Data Plane context +export DP_CONTEXT="my-data-plane-cluster" +export DOMAIN="example.com" + +kubectl --context $DP_CONTEXT create namespace openchoreo-data-plane --dry-run=client -o yaml | kubectl --context $DP_CONTEXT apply -f - +kubectl --context $DP_CONTEXT create configmap cluster-gateway-ca \ + --from-file=ca.crt=./server-ca.crt \ + -n openchoreo-data-plane \ + --dry-run=client -o yaml | kubectl --context $DP_CONTEXT apply -f - + +helm upgrade --install openchoreo-data-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-data-plane \ + --version \ + --kube-context $DP_CONTEXT \ + --namespace openchoreo-data-plane \ + --create-namespace \ + --set clusterAgent.enabled=true \ + --set clusterAgent.serverUrl="wss://cluster-gateway.openchoreo.${DOMAIN}/ws" \ + --set clusterAgent.tls.enabled=true \ + --set clusterAgent.tls.generateCerts=true \ + --set clusterAgent.tls.serverCAConfigMap=cluster-gateway-ca \ + --set clusterAgent.tls.caSecretName="" +``` + +### Key Parameters + +| Parameter | Description | +| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | +| `clusterAgent.serverUrl` | The public WebSocket URL of your Control Plane's Cluster Gateway (e.g., `wss://cluster-gateway.openchoreo.example.com/ws`) | +| `clusterAgent.tls.generateCerts` | Set to `true` to generate client certificates locally instead of copying from control plane | +| `clusterAgent.tls.serverCAConfigMap` | ConfigMap name containing the Control Plane CA certificate (`ca.crt`) used to verify the Cluster Gateway identity | +| `clusterAgent.tls.caSecretName` | Set to empty (`""`) to use a self-signed issuer for generating the agent's client certificate | + +:::info Why self-signed client certificates? +In multi-cluster deployments, the remote plane cannot access the Control Plane's CA private key (only the public certificate is available). Therefore, the agent generates its own client certificate using a local self-signed issuer. This certificate is then registered with the Control Plane in Step 4, establishing mutual trust. +::: + +## Step 3: Extract Agent Client CA + +After the remote plane is installed, cert-manager generates a self-signed CA and uses it to issue a client certificate for the Cluster Agent. You need to extract the **CA certificate** (not the leaf certificate) to register the plane with the Control Plane. + +Run this command against your **Remote Cluster** (Data/Build/Observability): + +```bash +# Set your Remote Plane context and namespace +export REMOTE_CONTEXT="my-data-plane-cluster" +export REMOTE_NAMESPACE="openchoreo-data-plane" + +# Wait for the certificate to be ready +kubectl --context $REMOTE_CONTEXT wait --for=condition=Ready \ + certificate/cluster-agent-dataplane-tls -n $REMOTE_NAMESPACE --timeout=120s + +# Extract the agent's CA certificate (used by the gateway to verify this agent) +export AGENT_CA=$(kubectl --context $REMOTE_CONTEXT get secret cluster-agent-tls \ + -n $REMOTE_NAMESPACE -o jsonpath='{.data.ca\.crt}' | base64 -d) + +# Verify the output (should start with -----BEGIN CERTIFICATE-----) +echo "$AGENT_CA" | head -n 5 +``` + +:::warning +Extract `ca.crt` from the `cluster-agent-tls` Secret, not `tls.crt`. The `ca.crt` field contains the self-signed CA that issued the agent's client certificate. The Cluster Gateway uses this CA to verify the agent's identity. Using `tls.crt` (the leaf certificate) will cause `websocket: bad handshake` errors because the gateway cannot build a trust chain. +::: + +:::tip +If the certificate is not ready, check the cert-manager logs and the Certificate resource status: + +```bash +kubectl --context $REMOTE_CONTEXT describe certificate cluster-agent-dataplane-tls -n $REMOTE_NAMESPACE +``` + +::: + +## Step 4: Register Plane in Control Plane + +Finally, register the remote plane by creating the appropriate CRD in the Control Plane cluster. You must embed the `AGENT_CA` extracted in Step 3. + +:::note[Cluster-scoped vs namespace-scoped plane resources] +OpenChoreo supports both namespace-scoped (`DataPlane`, `WorkflowPlane`, `ObservabilityPlane`) and cluster-scoped (`ClusterDataPlane`, `ClusterWorkflowPlane`, `ClusterObservabilityPlane`) variants. Cluster-scoped resources are visible to all namespaces and are simpler for single-tenant setups. The [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) guide uses the cluster-scoped variants. Use namespace-scoped variants when you need per-namespace isolation (e.g., different teams using different data planes). +::: + +**Example: Registering a Data Plane** + +```bash +# Create the DataPlane resource in the Control Plane +cat < \ + --kube-context $REMOTE_CONTEXT \ + --namespace openchoreo-workflow-plane \ + --create-namespace \ + --set clusterAgent.enabled=true \ + --set clusterAgent.serverUrl="wss://cluster-gateway.openchoreo.${DOMAIN}/ws" \ + --set clusterAgent.tls.enabled=true \ + --set clusterAgent.tls.generateCerts=true \ + --set clusterAgent.tls.serverCAConfigMap=cluster-gateway-ca \ + --set clusterAgent.tls.caSecretName="" +``` + +### Observability Plane + +```bash +kubectl --context $REMOTE_CONTEXT create namespace openchoreo-observability-plane --dry-run=client -o yaml | kubectl --context $REMOTE_CONTEXT apply -f - +kubectl --context $REMOTE_CONTEXT create configmap cluster-gateway-ca \ + --from-file=ca.crt=./server-ca.crt \ + -n openchoreo-observability-plane \ + --dry-run=client -o yaml | kubectl --context $REMOTE_CONTEXT apply -f - + +helm upgrade --install openchoreo-observability-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-observability-plane \ + --version \ + --kube-context $REMOTE_CONTEXT \ + --namespace openchoreo-observability-plane \ + --create-namespace \ + --set clusterAgent.enabled=true \ + --set clusterAgent.serverUrl="wss://cluster-gateway.openchoreo.${DOMAIN}/ws" \ + --set clusterAgent.tls.enabled=true \ + --set clusterAgent.tls.generateCerts=true \ + --set clusterAgent.tls.serverCAConfigMap=cluster-gateway-ca \ + --set clusterAgent.tls.caSecretName="" +``` + +## Step 5: Register Planes + +After installing each remote plane (Steps 2-3), register it with the Control Plane by creating the corresponding CRD. See [Step 4](#step-4-register-plane-in-control-plane) for the DataPlane example. + +### Register a Workflow Plane + +```bash +AGENT_CA=$(kubectl --context $REMOTE_CONTEXT get secret cluster-agent-tls \ + -n openchoreo-workflow-plane -o jsonpath='{.data.ca\.crt}' | base64 -d) + +cat < +{`# Required: Your new namespace name +export NAMESPACE_NAME="" + +# Optional: Name for a namespace-scoped DataPlane (only used in the isolation section below) + +export DATAPLANE_NAME="" + +# Optional: Context names if working with multiple clusters + +export CONTROL_PLANE_CONTEXT="" +export DATA_PLANE_CONTEXT="" +export WORKFLOW_PLANE_CONTEXT=""`} + + +## Namespace Creation + +To create a namespace, run: + + + {`kubectl create namespace $NAMESPACE_NAME +kubectl label namespace $NAMESPACE_NAME openchoreo.dev/control-plane=true`} + + +## Namespace Configuration + +### Mandatory Resources + +#### 1. Environments (At least 1) + +Environments represent deployment targets (e.g., development, staging, production). Each environment references a DataPlane or ClusterDataPlane. If you followed the getting-started guides, a `ClusterDataPlane` named `default` is already available cluster-wide. + +**Create environments manually** + + + {`kubectl apply -f - < + +**Create environments from samples** + +You can create multiple environments for a complete deployment pipeline. You can use samples with namespace and dataplane modifications. + + +{`# QA Environment +kubectl apply -f <(curl -s https://raw.githubusercontent.com/openchoreo/openchoreo/refs/heads/${versions.githubRef}/samples/platform-config/new-environments/qa-environment.yaml | yq eval ".metadata.namespace = \\"$NAMESPACE_NAME\\"" -) + +# Pre-production Environment + +kubectl apply -f <(curl -s https://raw.githubusercontent.com/openchoreo/openchoreo/refs/heads/${versions.githubRef}/samples/platform-config/new-environments/pre-production-environment.yaml | yq eval ".metadata.namespace = \\"$NAMESPACE_NAME\\"" -) + +# Production Environment + +kubectl apply -f <(curl -s https://raw.githubusercontent.com/openchoreo/openchoreo/refs/heads/${versions.githubRef}/samples/platform-config/new-environments/production-environment.yaml | yq eval ".metadata.namespace = \\"$NAMESPACE_NAME\\"" -)`} + + + +**Verification:** + + + {`kubectl get environment -n $NAMESPACE_NAME`} + + +#### 2. Deployment Pipeline (At least 1) + +A DeploymentPipeline defines the promotion path for releases across environments (e.g., dev → qa → pre-production → production). + +> Note: The following pipeline assumes an environment: `development` is already created on the namespace. If you want to create the `development` environment, run: + + + {`# Development Environment +kubectl apply -f <(curl -s https://raw.githubusercontent.com/openchoreo/openchoreo/refs/heads/${versions.githubRef}/samples/platform-config/new-environments/development-environment.yaml | yq eval ".metadata.namespace = \\"$NAMESPACE_NAME\\"" -)`} + + +**Create a deployment pipeline:** + + + {`kubectl apply -f - < + +**Verification:** + + + {`kubectl get deploymentpipeline -n $NAMESPACE_NAME +kubectl get deploymentpipeline default -n $NAMESPACE_NAME -o yaml`} + + +#### 3. Project (At least 1) + +A Project is a logical grouping of related components that share a deployment pipeline. + +**Create a project:** + + + {`kubectl apply -f - < + +**Verification:** + + + {`kubectl get project -n $NAMESPACE_NAME +kubectl get project default -n $NAMESPACE_NAME -o yaml`} + + +### Optional Resources + +These resources enhance OpenChoreo capabilities but are not required for basic deployments. + +:::note +If you followed the getting-started guides, cluster-scoped planes (ClusterDataPlane, ClusterWorkflowPlane, ClusterObservabilityPlane) are already registered and visible to all namespaces. You only need the namespace-scoped variants below if you want physical isolation for a specific namespace. +::: + +#### DataPlane (Namespace-scoped, for isolation) + +By default, namespaces use the ClusterDataPlane. Create a namespace-scoped DataPlane only when you need a dedicated data plane for a specific namespace. + + +{`# Extract client CA from data plane +DP_CA_CERT=$(kubectl --context \${DATA_PLANE_CONTEXT:-$(kubectl config current-context)} get secret cluster-agent-tls \\ + -n openchoreo-data-plane \\ + -o jsonpath='{.data.ca\\.crt}' | base64 -d) + +# Create namespace-scoped DataPlane resource + +kubectl apply -f - < + +**Verification:** + + + {`kubectl get dataplane -n $NAMESPACE_NAME`} + + +#### Workflow Plane (Optional) + +The Workflow Plane is required if developers need to build applications from source code. Without it, you can only deploy pre-built container images. If a ClusterWorkflowPlane is already registered, new namespaces can use it automatically. + +**Prerequisites:** + +- Container registry (local or external) + +**Setup:** + +See the [Container Registry Configuration](./container-registry-configuration.mdx) and [Auto-Build Configuration](./workflows/auto-build.mdx) guides for detailed setup instructions. + +**Namespace-scoped setup (for isolation):** + + +{`# Extract client CA from workflow plane +WP_CA_CERT=$(kubectl --context \${WORKFLOW_PLANE_CONTEXT:-$(kubectl config current-context)} get secret cluster-agent-tls \\ + -n openchoreo-workflow-plane \\ + -o jsonpath='{.data.ca\\.crt}' | base64 -d) + +# Create namespace-scoped WorkflowPlane resource + +kubectl apply -f - < + +**Verification:** + + + {`kubectl get workflowplane -n $NAMESPACE_NAME`} + + +#### Observability Plane (Optional) + +The Observability Plane provides centralized logging and monitoring for deployed components. If a ClusterObservabilityPlane is already registered, new namespaces can use it automatically. + +**Prerequisites:** + +- OpenSearch cluster (or similar log aggregation system) +- FluentBit (installed with data plane observability features) + +**Setup:** + +See the [Observability and Alerting](./observability-alerting.mdx) guide for detailed setup instructions. + +**Namespace-scoped setup (for isolation):** + + +{`# Extract client CA from observability plane +OP_CA_CERT=$(kubectl --context \${OBSERVABILITY_PLANE_CONTEXT:-$(kubectl config current-context)} get secret cluster-agent-tls \\ + -n openchoreo-observability-plane \\ + -o jsonpath='{.data.ca\\.crt}' | base64 -d) + +# Create namespace-scoped ObservabilityPlane resource + +kubectl apply -f - < +EOF`} + + + +:::note +`observerURL` must be a browser-reachable HTTPS URL — the portal fetches telemetry directly from the Observer. Use the Observer's gateway-exposed hostname and ensure `observer.cors.allowedOrigins` includes the portal origin. See [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) for example gateway and CORS configuration. +::: + +**Verification:** + + + {`kubectl get observabilityplane -n $NAMESPACE_NAME`} + + +#### Component Types, Workflows, and Traits (Namespace-scoped, for isolation) + +By default, new namespaces inherit ClusterComponentTypes, ClusterWorkflows, and ClusterTraits. Create namespace-scoped variants only when you need to customize or override them for a specific namespace. + + + {`# Copy a ClusterComponentType as a namespace-scoped ComponentType +kubectl get clustercomponenttype service -o yaml | \\ + yq eval ".kind = \\"ComponentType\\" | .metadata.namespace = \\"$NAMESPACE_NAME\\" | del(.metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp)" - | \\ + kubectl apply -f -`} + + +## Next Steps + +Once your namespace is prepared, you can: + +1. **Deploy and explore** - Follow the deployment guide + - [Deploy and Explore](../getting-started/deploy-and-explore.mdx) + - [Examples Catalog](../getting-started/examples-catalog.mdx) + +2. **Configure additional platform features** + - [Secret Management](./secret-management.mdx) - External secret store integration + - [Observability and Alerting](./observability-alerting.mdx) - Monitoring and alerts + +## Troubleshooting + +### DataPlane shows as "NotReady" + +Check the ClusterDataPlane or DataPlane status and conditions: + + +{`# For cluster-scoped (default): +kubectl get clusterdataplane $DATAPLANE_NAME +kubectl get clusterdataplane $DATAPLANE_NAME -o yaml | grep -A 20 "^status:" + +# For namespace-scoped: + +kubectl get dataplane $DATAPLANE_NAME -n $NAMESPACE_NAME +kubectl get dataplane $DATAPLANE_NAME -n $NAMESPACE_NAME -o yaml | grep -A 20 "^status:"`} + + + +Common issues: + +- **Invalid Kubernetes API server URL** (direct API mode) +- **Incorrect certificates or authentication credentials** (direct API mode) +- **Network connectivity issues** between control plane and data plane +- **PlaneID mismatch** (agent mode): The `planeID` in the ClusterDataPlane/DataPlane CR must match the `clusterAgent.planeID` Helm value +- **CA certificate mismatch** (agent mode): The client CA in the ClusterDataPlane/DataPlane CR must match the agent's certificate + +**For agent mode**, check agent logs: + + +{`# Data plane agent logs +kubectl logs -n openchoreo-data-plane -l app=cluster-agent --tail=30 + +# Control plane gateway logs + +kubectl logs -n openchoreo-control-plane -l app=cluster-gateway --tail=30 + +# Look for connection errors or certificate validation failures`} + + + +### Component Types or Workflows not appearing + +Check that cluster-scoped resources exist, or that namespace-scoped resources were created in the correct namespace: + + +{`# Check cluster-scoped resources (visible to all namespaces): +kubectl get clustercomponenttype,clusterworkflow + +# Check namespace-scoped resources: + +kubectl get componenttype,workflow -n $NAMESPACE_NAME`} + + + +### Pods stuck in Pending + +Check pod status and events: + + + {`kubectl describe pod -n `} + + +Common causes: + +- **Insufficient resources**: Increase RAM/CPU allocation to your cluster +- **PVC issues**: Check if storage provisioner is available +- **Image pull errors**: Verify image registry credentials and network connectivity + +### Environment cannot resolve DataPlane reference + +Verify the DataPlane name in the Environment spec matches an existing ClusterDataPlane or DataPlane: + + +{`# Check cluster-scoped (default): +kubectl get clusterdataplane + +# Check namespace-scoped: + +kubectl get dataplane -n $NAMESPACE_NAME + +# Check the environment's reference: + +kubectl get environment -n $NAMESPACE_NAME -o jsonpath='{.spec.dataPlaneRef}'`} + + + +### Project cannot find DeploymentPipeline + +Verify the DeploymentPipeline exists and the reference is correct: + + + {`kubectl get deploymentpipeline -n $NAMESPACE_NAME +kubectl get project -n $NAMESPACE_NAME -o jsonpath='{.spec.deploymentPipelineRef.name}'`} + + +## Related Documentation + +- [Resource Relationships](../concepts/resource-relationships.md) - Understanding OpenChoreo resource hierarchies +- [Deployment Topology](./deployment-topology.mdx) - Production deployment architectures +- [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx) - Setting up multi-cluster deployments +- [Container Registry Configuration](./container-registry-configuration.mdx) - External registry setup +- [Auto-Build Configuration](./workflows/auto-build.mdx) - Build system configuration +- [Observability and Alerting](./observability-alerting.mdx) - Logging and monitoring setup diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/observability-alerting.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/observability-alerting.mdx new file mode 100644 index 00000000..88b9f7ac --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/observability-alerting.mdx @@ -0,0 +1,646 @@ +--- +title: Observability & Alerting +description: Configure logging, metrics, tracing, and alerting for OpenChoreo. +sidebar_position: 9 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Observability & Alerting + +OpenChoreo provides an optional observability plane, which consists of a comprehensive observability stack +for monitoring applications deployed on the platform. The observability plane is designed in a modular architecture +so platform engineers can configure the observability plane to fit their needs, using the tools and technologies they are familiar with. + +The observability plane ships a selected set of modules by default when installed, +but platform engineers can replace or supplement the default modules with any community module. + +## Overview + +OpenChoreo's default observability architecture consists of: + +| Pillar | Components | +| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Logs** | A logs collector deployed to the data plane, and a logs storage deployed to the observability plane (defaults to observability-logs-opensearch module) | +| **Metrics** | A metrics collector deployed to the data plane, and a metrics storage deployed to the observability plane (defaults to observability-metrics-prometheus module) | +| **Traces** | A traces collector deployed to the data plane, and a traces storage deployed to the observability plane (defaults to observability-tracing-opensearch module) | + +All observability data is accessible through the **Observer API**, which provides a unified interface for querying logs, metrics, and traces. + +Alerting is a feature provided by the observability plane, which is integrated with logs and metrics modules to facilitate a unified alerting experience across the platform. + +## Architecture + +### Single-Cluster Setup + +In single-cluster mode, all planes run in the same Kubernetes cluster. +Observability data is collected directly from the data planes and workflow plane +via the agents deployed in the observability plane. + +```mermaid +--- +config: + layout: elk +--- +flowchart + subgraph ObservabilityPlane["Observability Plane"] + direction LR + FluentBit["Fluent Bit from Logs Module
(Collect logs)"] + OpenSearch["OpenSearch from Logs/Tracing Module
(Store logs & traces)"] + OTel["OpenTelemetry Collector from Tracing Module
(Collect traces)"] + GatewayIngress["Gateway Ingress"] + ObserverAPI["Observer API"] + LogsAdaptor["Adaptor from Logs Module"] + MetricsAdaptor["Adaptor from Metrics Module"] + TracingAdaptor["Adaptor from Tracing Module"] + OSAlerting["OpenSearch Alerting from Logs Module"] + PAM["Prometheus Alertmanager from Metrics Module"] + Prometheus["Prometheus from Metrics Module
(Collect & store metrics)"] + end + ObserverAPI -. Query logs .-> LogsAdaptor .-> OpenSearch + ObserverAPI -. Query metrics .-> MetricsAdaptor .-> Prometheus + OTel -. Publish traces .-> OpenSearch + FluentBit -. Publish logs .-> OpenSearch + ObserverAPI -. Query traces .-> TracingAdaptor .-> OpenSearch + ExternalClient(["Backstage/CLI/MCP"]) -- Query logs, metrics, traces, alerts, incidents --> GatewayIngress .-> ObserverAPI + ObserverAPI -- Send alert notifications --> AlertChannels(["Alert Channels
(SMTP, Slack)"]) + OSAlerting -. Notify log alerts .-> ObserverAPI + PAM -. Notify metric alerts .-> ObserverAPI +``` + +### Multi-Cluster Setup + +Multi-cluster mode is designed to run the observability plane on a dedicated cluster. +Data planes and workflow plane deploy local collectors from the respective observability modules that publish observability data +to the observability plane through the gateway ingress of the observability plane. + +```mermaid +--- +config: + layout: elk +--- +flowchart + subgraph ObservabilityPlane["Observability Plane Cluster"] + direction TB + Prometheus["Prometheus from Metrics Module
(Store metrics)"] + OpenSearch["OpenSearch from Logs Module
(Store logs & traces)"] + OTelCollector["OpenTelemetry Collector from Tracing Module
(Process traces)"] + ObserverAPI["Observer API"] + LogsAdaptor["Adaptor from Logs Module"] + MetricsAdaptor["Adaptor from Metrics Module"] + TracingAdaptor["Adaptor from Tracing Module"] + GatewayIngress["Gateway Ingress"] + OSAlerting["OpenSearch Alerting from Logs Module"] + PAM["Prometheus Alertmanager from Metrics Module"] + end + subgraph DataPlane["Data Plane Cluster"] + direction LR + OTelDP["OpenTelemetry Collector from Tracing Module
(Collect traces)"] + FluentBitDP["Fluent Bit from Logs Module
(Collect logs)"] + PrometheusAgentDP["Prometheus Agent from Metrics Module
(Collect metrics)"] + end + subgraph WorkflowPlane["Workflow Plane Cluster"] + FluentBitBP["Fluent Bit from Logs Module
(Collect logs)"] + end + GatewayIngress -.-> Prometheus & OpenSearch & OTelCollector + OTelCollector -.-> OpenSearch + ObserverAPI -. Query logs .-> LogsAdaptor .-> OpenSearch + ObserverAPI -. Query metrics .-> MetricsAdaptor .-> Prometheus + ObserverAPI -. Query traces .-> TracingAdaptor .-> OpenSearch + OSAlerting -. Notify log alerts .-> ObserverAPI + PAM -. Notify metric alerts .-> ObserverAPI + ObserverAPI -- Send alert notifications --> AlertChannels(["Alert Channels
(SMTP, Slack)"]) + DataPlane -- Publish logs, metrics, traces --> GatewayIngress + WorkflowPlane -- Publish logs --> GatewayIngress + ExternalClient(["Backstage/CLI/MCP"]) -- Query logs, metrics, traces, alerts, incidents --> GatewayIngress .-> ObserverAPI +``` + +In this setup: + +- **Data Plane** deploys Fluent Bit to collect logs, Prometheus Agent to collect metrics, and OpenTelemetry Collector to collect traces +- **Workflow Plane** deploys Fluent Bit to collect workflow run logs +- All collectors publish data through the **Gateway Ingress** in the Observability Plane +- The **Observer API** queries OpenSearch and Prometheus to serve unified observability data + +For detailed multi-cluster setup instructions, see [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx). + +## Prerequisites + +- OpenChoreo control plane installed +- Data plane and workflow plane (optional) installed to observe +- Observability plane installed (see [Installation](#installing-the-observability-plane)) + +## Installing the Observability Plane + +Refer to [Getting Started](../getting-started/try-it-out/on-k3d-locally.mdx#step-7-setup-observability-plane-optional) +or [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx#observability-plane) +for instructions on installing the observability plane in single-cluster or multi-cluster mode. + +--- + +## Observability + +### Logs + +OpenChoreo observability logs module collects container logs from all containers in the cluster, except for the logs collector containers. +Collected logs are enriched with Kubernetes metadata to support querying by OpenChoreo concepts (projects, components, environments, etc.). + +#### Querying Logs + +The Observer API provides a REST API for querying logs of a specific OpenChoreo component or a workflow run using OpenChoreo concepts as filters. +This can be accessed via the Backstage portal, OpenChoreo CLI or OpenChoreo MCP server. +Observer handles the authentication and authorization based on OpenChoreo user identity. + +--- + +### Metrics + +OpenChoreo observability metrics module collects metrics using for container resource metrics (CPU, memory) and HTTP request metrics (when instrumented via Hubble with Cilium CNI). +The metrics are also supported to be queried by OpenChoreo concepts (projects, components, environments, etc.). + +#### Querying Metrics + +The Observer API provides a REST API for querying metrics of a specific OpenChoreo component using OpenChoreo concepts as filters. +This can be accessed via the Backstage portal or the OpenChoreo MCP server. +Observer handles the authentication and authorization based on OpenChoreo user identity. + +--- + +### Traces + +OpenChoreo observability tracing module collects traces from applications that are instrumented to publish traces via [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/). +The traces are enriched with Kubernetes metadata to support querying by OpenChoreo concepts (projects, components, environments, etc.). + +#### Instrumenting Applications + +Applications must be instrumented to send traces to the OpenTelemetry Collector. Configure your application to send OTLP traces to one of the following endpoints when using single-cluster mode: + +| Protocol | Endpoint | +| -------- | -------------------------------------------------------------------------------------- | +| HTTP | `http://opentelemetry-collector.openchoreo-observability-plane.svc.cluster.local:4318` | +| gRPC | `opentelemetry-collector.openchoreo-observability-plane.svc.cluster.local:4317` | + +:::note +OpenTelemetry SDKs append `/v1/traces` to the HTTP endpoint automatically, so configure your application with the base URL above rather than including the path explicitly. +::: + +When using multi-cluster mode, the traces are published to the observability plane through the gateway ingress of the observability plane. Configure the applications accordingly. + +**Example: OpenTelemetry SDK Configuration (Go)** + +```go +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" +) + +exporter, _ := otlptracehttp.New(ctx, + otlptracehttp.WithEndpoint("opentelemetry-collector.openchoreo-observability-plane:4318"), + otlptracehttp.WithInsecure(), +) +``` + +#### Querying Traces + +The Observer API provides REST APIs for querying traces and spans using OpenChoreo concepts as filters. +This can be accessed via the Backstage portal or the OpenChoreo MCP server. +Observer handles the authentication and authorization based on OpenChoreo user identity. + +--- + +## Alerting + +OpenChoreo provides a unified alerting experience based on logs and resource usage metrics. +Alert rules are defined as traits on components and are automatically created for each environment by the control plane during component releases. +Alert notifications are configured as notification channels and are sent through the configured channels when an alert is triggered. + +### Alerting architecture + +The following diagram shows the end-to-end alerting flow across planes: + +```mermaid +--- +config: + layout: elk +--- +flowchart + subgraph controlPlane["ControlPlane"] + ComponentCR["Component"] + ReleaseBindingCR["ReleaseBinding"] + ReleaseCR["RenderedRelease"] + Trait["observabilityAlertRule Trait"] + end + + subgraph obsPlane["ObservabilityPlane"] + AlertRuleCR["ObservabilityAlertRule CR"] + OPController["Controller Manager"] + ObserverInternal["Observer API"] + LogsAdaptor["Adaptor from Logs Module"] + MetricsAdaptor["Adaptor from Metrics Module"] + OpenSearch["OpenSearch Alerting from Logs Module"] + PAM["Prometheus Alertmanager from Metrics Module"] + PromRule["PrometheusRule"] + Notifier["Alerts webhook handler"] + SREAgent["AI Root Cause Analysis"] + Incident["Incident"] + end + + ComponentCR -- consumes --> Trait + ReleaseBindingCR -- set environment overrides --> Trait + ComponentCR -- renders --> ReleaseCR + ReleaseBindingCR -- renders --> ReleaseCR + ReleaseCR -- applies --> AlertRuleCR + AlertRuleCR -- reconciles with --> OPController -- sync with --> ObserverInternal + ObserverInternal -- create/update/delete
log alert rule --> LogsAdaptor --> OpenSearch + ObserverInternal -- create/update/delete
metric alert rule -->MetricsAdaptor --> PAM --> PromRule + PAM --> |alertWebhook| MetricsAdaptor -- transform alert payload --> ObserverInternal + OpenSearch -->|alertWebhook| LogsAdaptor -- transform alert payload --> ObserverInternal + ObserverInternal --> Notifier + Notifier -->|notify| AlertsDest(["Email or webhook channels"]) + Notifier -->|optionally trigger| Incident + Notifier -- optionally trigger
(If incident is created) --> SREAgent +``` + +### Alert Rule Configuration (Developers) + +OpenChoreo ships a default trait named `observability-alert-rule` that can be used to define alert rules on components. +Platform engineers can define their own traits to provide platform-specific alert rules as required. + +In your `Component` definition, attach alert rules as traits: + +```yaml +traits: + - name: observability-alert-rule + kind: Trait + instanceName: high-error-rate-log-alert + parameters: + description: "Triggered when error logs count exceeds 50 in 5 minutes." + severity: "critical" + source: + type: "log" + query: "status:error" + condition: + window: 5m + interval: 1m + operator: gt + threshold: 50 +``` + +This trait will create an `ObservabilityAlertRule` CR with `spec.source` and `spec.condition` set from the parameters, and an `actions` block that can be customized per environment. + +### Environment-Specific Overrides (Platform Engineers) + +Environment-specific parameters for the alert rule (such as enabling/disabling the rule, choosing notification channels, and toggling incident/AI root cause analysis) are configured in the `ReleaseBinding` CR via `traitEnvironmentConfigs`: + +```yaml +spec: + traitEnvironmentConfigs: + high-error-rate-log-alert: + enabled: true + actions: + notifications: + channels: + - devops-email-notifications + incident: + enabled: true + triggerAiRca: false +``` + +This tells the control plane to: + +- enable the alert rule in this environment, +- send notifications to the `devops-email-notifications` `ObservabilityAlertsNotificationChannel`, and +- create incidents (without AI RCA) when the rule fires. + +### Alert Source Types + +| Type | Description | Use Case | +| -------- | --------------------- | ------------------------------------- | +| `log` | Log-based alerting | Error patterns, specific log messages | +| `metric` | Metric-based alerting | Resource utilization (CPU, memory) | + +### Alert Condition Operators + +| Operator | Description | +| -------- | --------------------- | +| `gt` | Greater than | +| `lt` | Less than | +| `gte` | Greater than or equal | +| `lte` | Less than or equal | +| `eq` | Equal to | + +### Notification Channels + +Configure notification channels to receive alerts. +Platform Engineers can configure notification channels per environment. +The first notification channel created in an environment is marked as the default channel. +The default channel is used by alert rules that don't specify a channel. + +OpenChoreo currently supports the following notification channel types: + +- **Email**: Sends alerts via SMTP email. +- **Webhook**: Sends alerts as HTTP POST requests to an external endpoint. + +#### Email Notification Channel Example + +Email templates support CEL expressions for dynamic content. +Available CEL variables for templates include: `${alertName}`, `${alertSeverity}`, `${alertDescription}`, +`${alertValue}`, `${alertTimestamp}`, `${alertThreshold}`, `${alertType}`, `${component}`, `${project}`, +`${environment}`, `${componentId}`, `${projectId}`, `${environmentId}`, and `${triggerAiRca}`. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: my-notification-channel + namespace: default +spec: + environment: development + isEnvDefault: true + type: email + emailConfig: + from: alerts@example.com + to: + - team@example.com + - oncall@example.com + smtp: + host: smtp.example.com + port: 587 + auth: + username: + secretKeyRef: + name: smtp-credentials + key: username + password: + secretKeyRef: + name: smtp-credentials + key: password + tls: + insecureSkipVerify: false + template: + subject: "[${alertSeverity}] ${alertName} Triggered" + body: | + Alert: ${alertName} + Severity: ${alertSeverity} + Time: ${alertTimestamp} + Description: ${alertDescription} + Component: ${component} + Project: ${project} + Environment: ${environment} +``` + +#### Webhook Notification Channel Example + +Use a webhook notification channel to deliver alerts to an HTTP endpoint +(for example, a custom incident management system, notification system such as Slack, or a chatops bridge). +The `payloadTemplate` can be templated using CEL expressions. If `payloadTemplate` is omitted, the full alert payload is sent as JSON. + +Available CEL variables for templates include: `${alertName}`, `${alertSeverity}`, `${alertDescription}`, +`${alertValue}`, `${alertTimestamp}`, `${alertThreshold}`, `${alertType}`, `${component}`, `${project}`, +`${environment}`, `${componentId}`, `${projectId}`, `${environmentId}`, `${alertIncidentEnabled}`, and `${alertTriggerAiRca}`. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: my-webhook-channel + namespace: default +spec: + environment: development + isEnvDefault: false + type: webhook + webhookConfig: + url: https://alerts.example.com/webhook + headers: + X-OpenChoreo-Source: + value: observer + Authorization: + valueFrom: + secretKeyRef: + name: webhook-token + key: token + payloadTemplate: | + { + "alertName": "${alertName}", + "alertSeverity": "${alertSeverity}", + "alertTimestamp": "${alertTimestamp}", + "alertDescription": "${alertDescription}" + } +``` + +### AI-Powered Root Cause Analysis + +When incident creation and AI RCA are enabled for an alert rule (via `actions.incident.enabled: true` and `actions.incident.triggerAiRca: true`), OpenChoreo's SRE Agent automatically analyzes the incident and generates a root cause analysis report. + +Platform engineers configure the SRE Agent deployment via the observability plane Helm chart (`rca.*` values), and enable AI RCA for an alert rule through trait environment configs and `ReleaseBinding` overrides. + +See [SRE Agent](../ai/sre-agent.mdx) for configuration details. + +### Viewing Alerts and Incidents + +Once alert rules are in place and notifications are configured, OpenChoreo also persists alert events and incidents in the observability plane. +You can query them via the Observer API. This can be accessed via the Backstage portal or the OpenChoreo MCP server. +Observer handles the authentication and authorization based on OpenChoreo user identity. + +For a full, end-to-end walkthrough of defining alert rules, configuring channels, and triggering alerts, refer to the [Component Alerts sample](https://github.com/openchoreo/openchoreo/tree/main/samples/component-alerts). + +### Configuring Alert Storage + +Alert entries and incidents are persisted in a storage backend. The Observer supports two backends: **SQLite** (default) and **PostgreSQL**. + +#### SQLite (Default) + +By default, alert entries and incidents are stored in an SQLite database backed by a `ReadWriteOnce` PersistentVolumeClaim. This is the simplest option and requires no external database. + +```yaml +observer: + alertStoreBackend: sqlite # default + alertStoreSqliteSize: 128Mi # PVC size for the SQLite database + replicas: 1 # must be 1 with SQLite (ReadWriteOnce PVC) + secretName: observer-secret # Secret with OPENSEARCH_USERNAME, OPENSEARCH_PASSWORD, UID_RESOLVER_OAUTH_CLIENT_SECRET +``` + +:::note +When using the SQLite backend, `observer.replicas` must be `1` because the PVC uses `ReadWriteOnce` access mode. Attempting to set a higher replica count will cause the Helm install to fail. +Also, the deployment strategy is set to `Recreate` to avoid multiple pods running at the same time. +::: + +#### PostgreSQL + +For production deployments that require high availability or horizontal scaling, configure the Observer to use a PostgreSQL backend. This allows running multiple Observer replicas. + +**Step 1: Create a PostgreSQL database for the Observer.** + +Provision a PostgreSQL database (e.g., `openchoreo_observer`) and create a dedicated user with read/write access to it. + +**Step 2: Add `ALERT_STORE_DSN` to the existing `observer-secret`.** + +The `ALERT_STORE_DSN` value must be a standard PostgreSQL connection URL: + +``` +postgresql://:@:/?sslmode= +``` + +Update the `ExternalSecret` named `observer-secret` in the `openchoreo-observability-plane` namespace to include `ALERT_STORE_DSN`: + +```yaml +data: + - secretKey: ALERT_STORE_DSN + remoteRef: + key: +``` + +**Step 3: Upgrade the Helm release with the updated values.** + +```yaml +observer: + alertStoreBackend: postgresql + secretName: observer-secret + replicas: 2 # can scale beyond 1 with PostgreSQL +``` + +Apply the updated values with `helm upgrade`. + +For all available alert storage configuration options, see the [Observability Plane Helm Reference](../reference/helm/observability-plane.mdx#observer). + +## Observer External IDP Configuration + +By default, OpenChoreo configures ThunderID as the identity provider for the Observer with a pre-configured OAuth client. +If you are using an external identity provider, configure the uid-resolver as described below. + +The uid-resolver is a sub-component of the Observer service that resolves component/project/environment identities +by calling the OpenChoreo control plane API. It uses the OAuth2 `client_credentials` grant to authenticate as a service account when making those calls. + +### Step 1: Create an OAuth Client in Your Identity Provider + +Create an OAuth 2.0 client with the following settings in your identity provider: + +- **Grant type**: `client_credentials` +- **Client ID**: Choose a name (e.g., `openchoreo-observer-resource-reader-client`) +- **Scopes**: No specific scopes are required by default. Set this only if your identity provider requires + a non-empty scope for the `client_credentials` grant (e.g., `"api:///.default"` for Azure AD). + +### Step 2: Store the OAuth Client Secret + +Store the client secret so the Observer can access it. For example, if you are using OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- \ + env BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root \ + bao kv put secret/observer-oauth-client-secret value="" +``` + +Add `UID_RESOLVER_OAUTH_CLIENT_SECRET` to the existing `observer-secret` ExternalSecret in the `openchoreo-observability-plane` namespace: + +```bash +kubectl patch externalsecret observer-secret -n openchoreo-observability-plane --type=json \ + -p '[{"op":"add","path":"/spec/data/-","value":{"secretKey":"UID_RESOLVER_OAUTH_CLIENT_SECRET","remoteRef":{"key":"observer-oauth-client-secret","property":"value"}}}]' +``` + +### Step 3: Configure the Observability Plane + +Update your Helm values with the OAuth client ID and the token endpoint of your identity provider: + +```yaml +security: + oidc: + tokenUrl: "" + +observer: + oauthClientId: "" + secretName: "observer-secret" +``` + +For environments that use self-signed certificates on the identity provider's token endpoint, also set: + +```yaml +security: + oidc: + uidResolverTlsInsecureSkipVerify: "true" +``` + +:::warning +Only set `uidResolverTlsInsecureSkipVerify: "true"` in development or testing environments. +For production deployments, ensure your identity provider uses valid TLS certificates. +::: + +Apply the changes using `helm upgrade` with your updated values. + +### Step 4: Grant Control Plane Access + +The Observer uses the `observer-resource-reader` role to read resource metadata (projects, components, environments, namespaces) from the control plane API. +The API matches the `sub` claim in the issued JWT to identify the caller, so the new client must be granted the `observer-resource-reader` role via a bootstrap authorization mapping. + +Add the following to your Control Plane values override, replacing `` with the same client ID used in Step 1: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: observer-resource-reader-binding + kind: ClusterAuthzRoleBinding + system: true + roleMappings: + - roleRef: + name: observer-resource-reader + kind: ClusterAuthzRole + entitlement: + claim: sub + value: "" + effect: allow +``` + +:::warning +When overriding the `bootstrap.mappings` array, the entire array is replaced. Make sure to include all other default bindings you want to keep. +See the [Authorization Configuration](./authorization.md#customizing-bootstrap-roles-and-bindings) guide for details. +::: + +--- + +## Configuration Reference + +### Key Helm Values + +| Value | Default | Description | +| ------------------------------------------ | ------- | ---------------------------------------------------- | +| `observability-logs-opensearch.enabled` | `false` | Enable OpenSearch based community module for logs | +| `observability-metrics-prometheus.enabled` | `false` | Enable Prometheus based community module for metrics | +| `observability-tracing-opensearch.enabled` | `false` | Enable OpenSearch based community module for traces | +| `rca.enabled` | `false` | Enable AI SRE Agent | + +For complete configuration options, see the [Observability Plane Helm Reference](../reference/helm/observability-plane.mdx). + +--- + +## Troubleshooting + +### Alert Not Firing + +1. Verify the alert rule status after a component is deployed: + + ```bash + kubectl get observabilityalertrules -n + kubectl describe observabilityalertrule -n + ``` + + Alert Rule Status should reflect if the alert rule was properly synced with the observability backend. + If alert rule is not available, check the `release`, `releasebinding`, `componentrelease` status to verify if the alert rule was properly applied to the observability plane. + +2. Check the Observer logs for alert processing errors: + + ```bash + kubectl logs -n openchoreo-observability-plane deployment/observer + ``` + +--- + +## Related Documentation + +- [SRE Agent](../ai/sre-agent.mdx) - AI-powered root cause analysis +- [Deployment Topology](./deployment-topology.mdx) - Multi-plane architecture overview +- [Multi-Cluster Connectivity](./multi-cluster-connectivity.mdx) - Connecting planes across clusters +- [Observability Plane Helm Reference](../reference/helm/observability-plane.mdx) - Complete Helm configuration options diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/resource-types.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/resource-types.md new file mode 100644 index 00000000..be15c94b --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/resource-types.md @@ -0,0 +1,301 @@ +--- +title: Authoring ResourceTypes +description: Learn how to author ResourceTypes and ClusterResourceTypes in OpenChoreo +--- + +# Authoring ResourceTypes + +This guide covers how to create custom [ResourceTypes](../reference/api/platform/resourcetype.md) and [ClusterResourceTypes](../reference/api/platform/clusterresourcetype.md) in OpenChoreo. A ResourceType is the platform-engineer-defined template that governs how a managed-infrastructure resource (database, queue, cache, object store) is provisioned on the data plane and exposed to consumers. + +## What is a ResourceType? + +A ResourceType plays the same role for managed infrastructure that a ComponentType plays for code components: it captures the manifests the platform emits, the parameters developers can supply, the environment-specific overrides bindings can apply, and the named outputs consumers wire into their containers. + +Platform engineers use ResourceTypes to: + +- Publish reusable provisioning templates (Postgres, NATS, Valkey, S3 buckets, Crossplane claims) +- Define what developers can configure through a schema +- Define what consumers can wire into their workloads through declared outputs +- Set retention defaults so accidental deletes do not destroy stateful data + +Developers reference a ResourceType from `Resource.spec.type` and supply parameter values. Each `ResourceReleaseBinding` then renders the template per environment, applies the rendered manifests to the data plane, and surfaces the resulting outputs back through `status.outputs`. + +OpenChoreo ships example ClusterResourceTypes (`postgres`, `valkey`, `nats`) under `samples/getting-started/cluster-resource-types/` for local development and to demonstrate the pattern. These samples back stateful infrastructure with in-cluster StatefulSets and are not intended for production use; platform engineers should author their own templates targeting production-grade provisioners (Crossplane, ACK, native cloud operators). + +### ClusterResourceType + +A **ClusterResourceType** is the cluster-scoped variant of ResourceType. Use it for templates intended to be shared platform-wide; namespace-scoped ResourceTypes are available when a template should be available only within a specific namespace. + +ClusterResourceTypes share the same spec structure as ResourceTypes; only scope differs. + +**Key concepts:** + +- `parameters` / `environmentConfigs` — Define what developers can configure on a Resource, and what bindings can override per environment +- `resources` — Kubernetes manifest templates the provisioner emits on the data plane (rendered through CEL) +- `outputs` — Named values that consuming workloads bind to environment variables and file mounts +- `retainPolicy` — Default deletion behavior (`Delete` or `Retain`) for bindings of this type + +## ResourceType Example + +The example below defines a simple Valkey (Redis-protocol) cache backed by a StatefulSet. It exposes three outputs—`host`, `port`, and `password`—that workloads can consume through `dependencies.resources[]`. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceType +metadata: + name: valkey-cache + namespace: default +spec: + # Developer-facing parameters; captured in the ResourceRelease snapshot. + parameters: + openAPIV3Schema: + type: object + properties: + version: + type: string + enum: ["7", "8"] + default: "8" + + # Per-environment overrides applied through ResourceReleaseBinding. + environmentConfigs: + openAPIV3Schema: + type: object + properties: + memory: + type: string + default: "128Mi" + + # Default retention. Per-environment override available on bindings. + retainPolicy: Delete + + # Named outputs that consuming workloads wire into containers. + outputs: + - name: host + value: "${metadata.name}.${metadata.namespace}.svc.cluster.local" + - name: port + value: "6379" + - name: password + secretKeyRef: + name: "${metadata.name}-creds" + key: password + + # Kubernetes manifests rendered onto the data plane. + resources: + - id: password-secret + template: + apiVersion: v1 + kind: Secret + metadata: + name: ${metadata.name}-creds + namespace: ${metadata.namespace} + labels: ${metadata.labels} + type: Opaque + stringData: + # Real templates generate this on the data plane (for example via + # an ExternalSecret + Password generator) so the literal never + # transits the control plane. See the example `valkey` sample for + # the full pattern. + password: "change-me" + + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + selector: + app: ${metadata.name} + ports: + - name: valkey + port: 6379 + targetPort: 6379 + + - id: statefulset + readyWhen: "${applied.statefulset.status.readyReplicas == applied.statefulset.status.replicas && applied.statefulset.status.replicas > 0}" + template: + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + serviceName: ${metadata.name} + replicas: 1 + selector: + matchLabels: + app: ${metadata.name} + template: + metadata: + labels: + app: ${metadata.name} + spec: + containers: + - name: valkey + image: valkey/valkey:${parameters.version}-alpine + resources: + limits: + memory: ${environmentConfigs.memory} + env: + - name: VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: ${metadata.name}-creds + key: password + args: + - --requirepass + - $(VALKEY_PASSWORD) + ports: + - containerPort: 6379 + name: valkey +``` + +Real-world templates also generate credentials on the data plane (for example through an ExternalSecret backed by a Password generator) so secret material never reaches the control plane. The example templates under `samples/getting-started/cluster-resource-types/` (`postgres`, `valkey`, `nats`) demonstrate the full pattern. They use in-cluster StatefulSets for the underlying infrastructure and are intended for local development; production templates typically target a managed-provisioner abstraction (Crossplane, ACK, native cloud operator) instead. + +## Outputs + +Outputs are the contract between the ResourceType and the workloads that consume it. Each output is identified by a unique `name` and picks exactly one of three source kinds: + +| Source kind | When to use | What transits to the control plane | +| ----------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| `value` | Non-sensitive data (host, port, region, database name, composed connection URLs) | The resolved literal value. Stored on the binding's `status.outputs[].value`. | +| `secretKeyRef` | Sensitive credentials (passwords, tokens, private keys) | Only `{name, key}` of the data-plane Secret. The underlying value never leaves the data plane. | +| `configMapKeyRef` | Non-sensitive runtime configuration sourced from a data-plane ConfigMap (CA bundles, locale settings) | Only `{name, key}` of the data-plane ConfigMap. | + +`value`, `secretKeyRef.name`, `secretKeyRef.key`, `configMapKeyRef.name`, and `configMapKeyRef.key` all support `${...}` CEL templating. The CEL context includes `applied..status.*`—use this to surface fields populated by the provisioner (for example a Crossplane claim's `status.connectionDetails`). + +Consumers reference outputs by name through `Workload.spec.dependencies.resources[].envBindings` and `fileBindings` (see the [Resource Dependencies developer guide](../developer-guide/dependencies/resources.md)). Outputs declared on the ResourceType but not requested by a consumer are simply unused; outputs requested by a consumer but missing on the ResourceType surface as a `ResourceDependenciesPending` reason on the consuming `ReleaseBinding`. + +## How Developers Consume a ResourceType + +Developers create a **Resource** that references the ResourceType, providing parameter values that conform to the declared schema. They then declare a dependency from a Workload to the Resource and bind the outputs they need: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-cache + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ResourceType + name: valkey-cache + parameters: + version: "8" +--- +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: doclet-document + namespace: default +spec: + owner: + projectName: doclet + componentName: doclet-document + container: + image: ghcr.io/openchoreo/samples/doclet-document:latest + dependencies: + resources: + - ref: doclet-cache + envBindings: + host: REDIS_HOST + port: REDIS_PORT + password: REDIS_PASSWORD +``` + +To deploy the Resource into an environment, a platform engineer or GitOps process creates a `ResourceReleaseBinding`. The binding pins a specific `ResourceRelease`, targets an Environment, supplies per-environment overrides through `resourceTypeEnvironmentConfigs`, and optionally overrides the `retainPolicy`: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: doclet-cache-production + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-cache + environment: production + resourceRelease: doclet-cache-abc12345 # advanced via `occ resource promote` + retainPolicy: Retain + resourceTypeEnvironmentConfigs: + memory: "2Gi" +``` + +The binding controller renders the ResourceType template with the combined Resource parameters and environment overrides, produces a `RenderedRelease` applied to the data plane, and resolves declared outputs into `status.outputs` so consuming workloads can read them. + +## CEL Surface for Resource Templates + +Resource templates and output expressions have access to the following CEL context. The available bindings depend on which field is being evaluated: + +| Context | In resource `template` | In `includeWhen` | In `readyWhen` | In `outputs` | Description | +| ---------------------- | :--------------------: | :--------------: | :------------: | :----------: | ----------------------------------------------------------------------------------------- | +| `metadata.*` | yes | yes | yes | yes | Platform-injected naming, namespace, resource/project/env UIDs, labels, annotations | +| `parameters.*` | yes | yes | yes | yes | Values from `Resource.spec.parameters` after schema defaulting | +| `environmentConfigs.*` | yes | yes | yes | yes | Values from `ResourceReleaseBinding.spec.resourceTypeEnvironmentConfigs` after defaulting | +| `environment.*` | yes | yes | yes | yes | Per-environment surface including the merged effective gateway for this environment | +| `dataplane.*` | yes | yes | yes | yes | Target DataPlane attributes (secret store, raw gateway, observability ref) | +| `gateway.*` | yes | yes | yes | yes | Effective gateway (Environment-level override merged onto DataPlane-level default) | +| `applied..*` | no | no | yes | yes | Status of resources that were applied to the data plane—reference by template `id` | + +`applied..*` is not available during rendering (the manifests have not been applied yet) but is available in `readyWhen` and `outputs` because both run after the data plane reports back. Use `applied..status.*` in outputs to surface provider-populated fields, such as a Crossplane claim's connection details or a StatefulSet's observed pod count. + +The `${...}` wrapper is required on `includeWhen`, `readyWhen`, and `outputs[].value`. Inside resource templates, both `${...}` interpolation (which substitutes a value into a string) and `${...}` whole-field replacement (when the entire field value is a `${...}` expression) are supported—same shape as ComponentType templates. + +## includeWhen and readyWhen + +Each resource template entry supports two optional CEL fields that shape its lifecycle: + +**`includeWhen`** is a boolean expression evaluated at render time. When it returns `false`, the entry is omitted from the rendered output and any previously-applied object is garbage-collected from the data plane. Common uses: + +- `${parameters.tlsEnabled}` — conditionally emit a Certificate/Issuer for TLS +- `${environmentConfigs.adminEnabled && has(gateway.ingress.external)}` — only emit the admin UI when explicitly enabled and the environment has external ingress + +**`readyWhen`** is a boolean expression evaluated after the rendered object has been applied. When it returns `true`, the entry contributes positively to the binding's `ResourcesReady` condition. When unset, the binding falls back to the per-Kind health heuristics in `RenderedRelease` (replica counts, condition probes). Use `readyWhen` when the default heuristic does not match your provisioner's signal: + +- `${applied.claim.status.conditions.exists(c, c.type == 'Ready' && c.status == 'True')}` — a Crossplane claim's `Ready` condition +- `${applied.statefulset.status.readyReplicas == applied.statefulset.status.replicas && applied.statefulset.status.replicas > 0}` — explicit StatefulSet quorum + +Both fields must evaluate to a boolean and must be wrapped in `${...}`. + +## retainPolicy + +`retainPolicy` on the ResourceType sets the default deletion behavior for bindings of that type. Two values: + +- **`Delete`** (default) — When a `ResourceReleaseBinding` is deleted, the binding controller removes the emitted data-plane manifests as part of finalization. +- **`Retain`** — The binding's finalizer holds when deleted, preserving the underlying data-plane state until the policy is flipped back to `Delete`. + +Per-environment bindings can override the type-level default through `ResourceReleaseBinding.spec.retainPolicy`. Production environments typically opt into `Retain` for non-recoverable infrastructure (databases, persistent volumes) while dev and staging keep the default `Delete`. + +## Syntax Systems + +ResourceTypes reuse the same syntax systems documented in the Component Types guide: + +| Syntax | Purpose | Used In | +| ---------------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------- | +| [Templating](./component-types/templating-syntax.md) | Dynamic value generation using CEL expressions | `resources[].template`, `includeWhen`, `readyWhen`, `outputs[]` fields | +| [Schema](./component-types/schema-syntax.md) | Parameter validation and defaults | `parameters.openAPIV3Schema` and `environmentConfigs.openAPIV3Schema` | + +Patching (Trait-only) and CEL-based validation rules do not apply to ResourceTypes. + +## CEL Reference + +- **[Context Variables](../reference/cel/context-variables.md)** — `metadata`, `parameters`, `environmentConfigs`, `dataplane`, `gateway`, `applied` +- **[Built-in Functions](../reference/cel/built-in-functions.md)** — `oc_omit()`, `oc_merge()`, `oc_generate_name()`, `oc_dns_label()` +- **[Configuration Helpers](../reference/cel/helper-functions.md)** — helpers for working with configs and secrets + +## Next Steps + +- **[Resource Dependencies (developer guide)](../developer-guide/dependencies/resources.md)** — How developers wire ResourceType outputs into containers + +## Related Resources + +- [ResourceType API Reference](../reference/api/platform/resourcetype.md) — Full CRD specification +- [ClusterResourceType API Reference](../reference/api/platform/clusterresourcetype.md) — Cluster-scoped variant +- [Resource API Reference](../reference/api/application/resource.md) — Developer-facing CRD +- [ResourceReleaseBinding API Reference](../reference/api/platform/resourcereleasebinding.md) — Per-environment binding diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/secret-management.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/secret-management.mdx new file mode 100644 index 00000000..da3b8231 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/secret-management.mdx @@ -0,0 +1,285 @@ +--- +title: Secret Management +description: Manage secrets and sensitive configuration in OpenChoreo. +sidebar_position: 8 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Secret Management + +OpenChoreo integrates with [External Secrets Operator (ESO)](https://external-secrets.io/) to synchronize secrets from external secret stores into Kubernetes. This integration allows you to: + +- **Bring your own secret store**: Use any ESO-supported backend (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, and many more) +- **Use existing External Secrets setup**: If you already have ESO deployed, OpenChoreo can work with your existing `ClusterSecretStore` configurations +- **Centralized secret management**: Manage all secrets in your preferred external store and let ESO sync them to Kubernetes + +## Installing External Secrets Operator + +ESO must be installed as a standalone prerequisite before installing any OpenChoreo plane charts. Install it in its own namespace: + +```bash +helm upgrade --install external-secrets oci://ghcr.io/external-secrets/charts/external-secrets \ + --namespace external-secrets \ + --create-namespace \ + --version 2.0.1 \ + --set installCRDs=true +``` + +Wait for ESO to be ready: + +```bash +kubectl wait --for=condition=available deployment/external-secrets -n external-secrets --timeout=180s +``` + +:::tip Multi-Cluster +For multi-cluster deployments, install ESO in each cluster where you need secret synchronization. +::: + +## Using Your Existing External Secrets Setup + +If you already have External Secrets Operator deployed in your cluster with a configured `ClusterSecretStore`, you can skip enabling ESO in the OpenChoreo charts and simply reference your existing store. + +Configure your DataPlane to use your existing SecretStore: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: DataPlane +metadata: + name: default + namespace: my-namespace +spec: + secretStoreRef: + name: your-existing-secret-store + # ... other configuration +``` + +## Configuring a ClusterSecretStore + +To connect ESO to your secret backend, create a `ClusterSecretStore` resource. For provider-specific configuration (authentication methods, endpoints, etc.), refer to the official ESO provider documentation: + +- **[HashiCorp Vault](https://external-secrets.io/latest/provider/hashicorp-vault/)** +- **[AWS Secrets Manager](https://external-secrets.io/latest/provider/aws-secrets-manager/)** +- **[GCP Secret Manager](https://external-secrets.io/latest/provider/google-secrets-manager/)** +- **[Azure Key Vault](https://external-secrets.io/latest/provider/azure-key-vault/)** + +**Example structure:** + +```yaml +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: my-secret-store +spec: + provider: + # Provider-specific configuration +``` + +## Development Setup (OpenBao) + +For development and testing, [OpenBao](https://openbao.org/) (an open-source Vault fork) provides a lightweight secret backend that runs in-cluster. Install it in dev mode: + +```bash +helm upgrade --install openbao oci://ghcr.io/openbao/charts/openbao \ + --namespace openbao \ + --create-namespace \ + --version 0.4.0 \ + --set server.image.tag=2.4.4 \ + --set injector.enabled=false \ + --set server.dev.enabled=true \ + --set server.dev.devRootToken=root \ + --wait --timeout 300s +``` + +After OpenBao is running, configure Kubernetes auth and create the `ClusterSecretStore`. See the [getting started guide](../getting-started/try-it-out/on-k3d-locally.mdx#openbao-secret-backend) for the full setup steps. + +To write secrets into OpenBao: + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/my-secret key=value +' +``` + +:::note +ESO must already be installed in the cluster before creating the `ClusterSecretStore`. +::: + +## Alternative Backends + +To use a different secret backend, create a `ClusterSecretStore` named `default` with your provider's configuration. All OpenChoreo planes reference this single store, so changing the backend is a single resource swap. See the ESO provider documentation for provider-specific setup. + +## Creating ExternalSecrets + +Create `ExternalSecret` resources to sync specific secrets from your backend. For complete documentation on ExternalSecret configuration, see the [ESO documentation](https://external-secrets.io/latest/api/externalsecret/). + +**Example:** + +```yaml +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: app-secrets + namespace: my-app +spec: + refreshInterval: 1h + secretStoreRef: + name: my-secret-store + kind: ClusterSecretStore + target: + name: app-secrets + creationPolicy: Owner + data: + - secretKey: database-url + remoteRef: + key: my-app/database + property: url +``` + +## Platform Secrets + +These secrets are used by OpenChoreo infrastructure components: + +| Secret | Purpose | Plane | +| -------------------------- | ------------------------------- | ---------- | +| `backstage-backend-secret` | Backstage session encryption | Control | +| `thunder-client-secret` | OAuth client secret | Control | +| `cluster-gateway-ca` | Root CA for plane communication | Control | +| `cluster-agent-tls` | Agent mTLS certificates | All | +| `registry-credentials` | Container registry auth | Build/Data | + +## Managing Secrets through the UI and CLI + +OpenChoreo provides a Secret Management API that lets developers and platform engineers create, view, update, and delete secrets through Backstage or the `occ` CLI without writing raw `Secret` or `SecretReference` YAML. The control plane stores a `SecretReference` and pushes the secret value into the target plane's external secret store on behalf of the user. + +### Enabling the Feature + +The Secret Management API and the Backstage UI for secrets are gated by the `features.secretManagement.enabled` flag on the `openchoreo-control-plane` Helm chart. The flag is **disabled by default**. The k3d single-cluster install and the quick-start install enable it out of the box; for any other deployment you need to turn it on explicitly. + +Enable it on an existing control-plane release: + + + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set features.secretManagement.enabled=true`} + + +When enabled: + +- The Secret Management API is exposed by the OpenChoreo API server. The `occ secret` command group (`create`, `get`, `list`, `update`, `delete`) becomes available to clients. +- Backstage shows the **Secrets** tab under **Settings**, where users can browse secrets in a namespace and create new ones (generic, Docker registry, TLS, git credentials). +- Secret values are transmitted **through the control plane** when the user creates, updates, or views a secret. The control plane writes the value to the target plane's external secret store and stores only a `SecretReference` in the control plane; it does not persist the secret value itself. + +When disabled, the API rejects secret write requests and the Backstage Secrets tab is hidden. Users can still manage secrets directly by applying `SecretReference` and `ExternalSecret` YAML to the target cluster. + +### Using the CLI + +Create a secret with `occ secret create`. The `--target-plane` flag selects the plane whose external secret store will receive the value, and `--category` distinguishes generic secrets from git credentials. + +```bash +# Generic Opaque secret +occ secret create generic db-creds \ + --namespace acme-corp \ + --target-plane DataPlane/dp-prod \ + --from-literal=username=admin \ + --from-literal=password=s3cret + +# Git credentials for private repository builds +occ secret create generic github-pat \ + --namespace acme-corp \ + --target-plane ClusterWorkflowPlane/default \ + --category git-credentials \ + --from-literal=username=git \ + --from-literal=password=ghp_xxx +``` + +See the [CLI Reference](../reference/cli-reference.md#secret) for the full command surface, including `docker-registry`, `tls`, and the `update --replace` flow. + +### Using the Backstage UI + +1. Open **Settings → Secrets** in Backstage. +2. Select the namespace from the dropdown. +3. Click **Create Secret** and choose a category (generic or git credentials). +4. Enter the key/value pairs or upload files. Submit. + +Secret Management page in Backstage + +The created secret appears in the same list and can be referenced from any component in that namespace by its name. + +### How It Works + +When a user creates a secret through Backstage or `occ`: + +1. The client calls the OpenChoreo API server with the secret name, namespace, target plane, category, and the secret data. +2. The API server creates a `SecretReference` in the control plane recording the name, namespace, target plane, category label (`openchoreo.dev/secret-type`), and `spec.template.type` (e.g. `kubernetes.io/basic-auth`). The control plane does not store the secret value. +3. The API server connects to the target plane and writes a `Kubernetes Secret` together with a `PushSecret` into the plane's `openchoreo-kv-` namespace. +4. `PushSecret` reads the local Kubernetes Secret and pushes its contents to the configured external secret store (Vault, OpenBao, AWS Secrets Manager, etc.) through the `ClusterSecretStore`. +5. Workloads on the plane consume the secret by creating an `ExternalSecret` that pulls the value back from the external store via the same `ClusterSecretStore` and materializes a Kubernetes Secret in their own namespace. + +```mermaid +flowchart LR + user(["User / Backstage / occ"]) + + subgraph CP["Control Plane"] + api["OpenChoreo
API Server"] + sr["SecretReference
(metadata only)"] + end + + subgraph WP["Target Plane"] + subgraph KVNS["ns: openchoreo-kv-<ns>"] + srcSecret["Kubernetes Secret
(source)"] + pushSecret["PushSecret"] + end + css["ClusterSecretStore"] + store[("External Secret Store
Vault / OpenBao / etc.")] + end + + user -- "1. Create secret request" --> api + api -- "2. Store SecretReference" --> sr + api -- "3. Write K8s Secret + PushSecret" --> KVNS + pushSecret -- "reads" --> srcSecret + pushSecret -- "4. push via" --> css + css --> store +``` + +Updates and deletes follow the same path: `occ secret update` / `occ secret delete` calls the API server, which mutates or removes the source `Kubernetes Secret` and `PushSecret` in `openchoreo-kv-`. The external store reflects the change on the next `PushSecret` reconcile. + +## Troubleshooting + +### Check ExternalSecret Status + +```bash +kubectl get externalsecret -A +kubectl describe externalsecret -n +``` + +### Check ClusterSecretStore Status + +```bash +kubectl get clustersecretstore +kubectl describe clustersecretstore +``` + +### Check ESO Logs + +```bash +kubectl logs -n external-secrets deployment/external-secrets +``` + +For detailed troubleshooting guidance, see the [ESO troubleshooting documentation](https://external-secrets.io/latest/guides/troubleshooting/). + +## Next Steps + +- [Deployment Topology](./deployment-topology.mdx): Configure SecretStore references in planes +- [External Secrets Operator Documentation](https://external-secrets.io/): Complete ESO reference diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/overview.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/overview.mdx new file mode 100644 index 00000000..63a29c12 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/overview.mdx @@ -0,0 +1,115 @@ +--- +title: Overview +description: The OpenChoreo upgrade policy, the standard upgrade process, and per-version upgrade guides. +sidebar_position: 1 +--- + +# Upgrading OpenChoreo + +This section covers how to upgrade an OpenChoreo installation to a newer version. Each minor-version transition has its own guide describing anything version-specific you need to be aware of. Read the guide for the version you are upgrading to, then follow the standard process below for anything it does not override. + +## Upgrade policy + +**Upgrade one minor version at a time.** OpenChoreo supports upgrading only from one minor version to the immediately following minor version. To move across several minors, step through each one in order. + +- Patch releases within the same minor (for example `v1.1.0` to `v1.1.2`) are always safe and need no special procedure. +- Minor upgrades (for example `v1.1` to `v1.2`) may introduce breaking changes and have a dedicated guide below. +- To go from `v1.0` to `v1.2`, first upgrade `v1.0` to `v1.1`, then `v1.1` to `v1.2`. Do not skip the intermediate minor. + +Skipping a minor version is not supported and may leave CRDs, controllers, and stored resources in an inconsistent state. + +## Before you upgrade + +1. **Review the guide** for the target version (below) and the release notes. +2. **Back up critical data** — OpenChoreo CRDs and resources, and any OpenSearch or container-registry data: + + ```bash + kubectl get projects,components,dataplanes,workflowplanes -A -o yaml > openchoreo-backup.yaml + ``` + +3. **Test in a non-production environment** first. +4. **Plan for downtime** if the target version's guide calls for it. + +## Standard upgrade process + +Unless the target version's guide says otherwise, every upgrade follows the same shape: for each plane you run, apply the target version's CRDs, then run `helm upgrade`. Upgrade the planes in order — **control plane first**, then data, workflow, and observability. + +Replace `` below with the target chart version (each per-version guide states it). + +:::warning Helm does not upgrade CRDs +OpenChoreo ships its CustomResourceDefinitions in the `crds/` directory of each Helm chart. By [Helm's design](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/), CRDs there are installed on `helm install` but **never modified by `helm upgrade`**. You must apply CRD changes manually **before** running `helm upgrade`. +::: + +### Apply updated CRDs + +For every plane you are about to upgrade, pull the target chart and apply its CRDs with server-side apply (example shown for the control plane): + +```bash +helm pull oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \ + --version --untar --untardir ./charts + +kubectl apply --server-side --force-conflicts \ + -f ./charts/openchoreo-control-plane/crds/ +``` + +- `--server-side` is required because CRD manifests routinely exceed the 256 KB annotation limit of client-side apply (`metadata.annotations: Too long`). +- `--force-conflicts` transfers ownership of the changed fields from the `helm` field manager to `kubectl`; this is safe because Helm never writes `crds/` after install. +- Repeat for `openchoreo-data-plane`, `openchoreo-workflow-plane`, and `openchoreo-observability-plane` if you run them. Each chart ships only the CRDs it owns. + +### Upgrade each plane + +```bash +helm upgrade openchoreo-control-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \ + --version --namespace openchoreo-control-plane --reset-then-reuse-values +``` + +Repeat for each plane you run, in order. + +:::tip Why `--reset-then-reuse-values`? +Plain `--reuse-values` reuses **all** values from the last release, including the old chart's defaults, so new defaults introduced in the target chart are never picked up (often surfacing as nil-pointer errors during templating). `--reset-then-reuse-values` resets to the new chart's defaults first, then re-layers your previously set values on top, so new defaults are honored while your overrides are preserved. +::: + +On multi-cluster installations, run each plane's upgrade against its own cluster with `--kube-context` (Helm) and `--context` (kubectl), applying that plane's CRDs to the same cluster first. + +### Verify + +```bash +helm list -A # releases and chart versions +kubectl get pods -n openchoreo-control-plane \ + -o jsonpath='{.items[*].spec.containers[*].image}' # pod images (repeat per plane) +kubectl get crds | grep openchoreo # installed CRD versions +``` + +### Rollback + +```bash +helm history openchoreo-control-plane -n openchoreo-control-plane +helm rollback openchoreo-control-plane -n openchoreo-control-plane +``` + +:::caution CRDs are not rolled back automatically +`helm rollback` does not revert CRD changes. If a release introduced breaking CRD schema changes, re-apply the previous release's CRDs manually before rolling back the chart. CRDs newly added in the failed release remain in the cluster; they are inert if no controller reconciles them, and can be deleted once no custom resources of that kind exist. +::: + +## Upgrade guides + +Follow the guide that matches your upgrade, one minor at a time: + +- **[v1.1 to v1.2](./v1.1-to-v1.2.mdx)** — introduces the project release lifecycle and the required `Project.spec.type` field; includes a staged CRD migration on the control plane. +- **[v1.0 to v1.1](./v1.0-to-v1.1.mdx)** — no backward-incompatible changes; the standard process plus observability-module version bumps. + +## Version compatibility + +| OpenChoreo Version | Kubernetes Version | Helm Version | +| ------------------ | ------------------ | ------------ | +| 0.7.x | 1.32+ | 3.12+ | +| 0.6.x | 1.31+ | 3.12+ | +| 0.5.x | 1.30+ | 3.12+ | + +## Getting help + +If you encounter issues during an upgrade: + +1. Check the [FAQ](../../reference/faq.md). +2. Review pod logs for errors. +3. Open an issue on [GitHub](https://github.com/openchoreo/openchoreo/issues). diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.0-to-v1.1.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.0-to-v1.1.mdx new file mode 100644 index 00000000..db8b6976 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.0-to-v1.1.mdx @@ -0,0 +1,105 @@ +--- +title: v1.0 to v1.1 +description: Upgrade an OpenChoreo installation from v1.0 to v1.1. +sidebar_position: 3 +--- + +# Upgrading from v1.0 to v1.1 + +There are no backward-incompatible CRD or API changes in v1.1. Follow the [standard upgrade process](./overview.mdx#standard-upgrade-process) — apply each plane's updated CRDs, then `helm upgrade` the control, data, workflow, and observability planes in order — using chart version `1.1.x`. + +The notes below cover the version-specific steps that apply only when upgrading **from v1.0**. + +## Observability plane + +### Observer deployment strategy + +:::warning May cause a Helm upgrade failure +Since v1.0.0 the Observer deployment's rolling strategy is set conditionally based on the alert store backend. If you use `sqlite` as the alert store backend (the default), patch the deployment **before** upgrading the observability plane to avoid a Helm upgrade failure: + +```bash +kubectl patch deployment observer -n openchoreo-observability-plane \ + -p '{"spec":{"strategy":{"type":"Recreate","rollingUpdate":null}}}' +``` + +::: + +### Community module versions + +If you use the default logs, metrics, and traces modules at the versions from the OpenChoreo v1.0.0 documentation, upgrade them to the versions compatible with v1.1 as well. + +- Observability Logs OpenSearch module: v0.3.11 -> v0.4.1 + +```bash +helm upgrade --install observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.4.1 \ + --reset-then-reuse-values \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" \ + --set adapter.openSearchSecretName="opensearch-admin-credentials" +``` + +- Observability Traces OpenSearch module: v0.3.11 -> v0.4.2 + +```bash +helm upgrade --install observability-traces-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-tracing-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.4.2 \ + --reset-then-reuse-values \ + --set openSearch.enabled=false \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" +``` + +:::warning Reindex old tracing data +Observability Traces OpenSearch module v0.4.0 uses a new index template that indexes `resource.openchoreo.dev/namespace` and uses it for queries. Since the old template did not index this field, traces query endpoints may return empty results after the upgrade. To fix this, reindex your old tracing data to the new index template: + +```bash +curl -fsSL https://raw.githubusercontent.com/openchoreo/community-modules/refs/heads/main/observability-tracing-opensearch/scripts/upgrade-to-0-4-1.sh | bash +``` + +::: + +- Observability Metrics Prometheus module: v0.2.5 -> v0.6.1 + +```bash +helm upgrade --install observability-metrics-prometheus \ + oci://ghcr.io/openchoreo/helm-charts/observability-metrics-prometheus \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.1 \ + --reset-then-reuse-values \ + --set adapter.image.tag="" +``` + +## Multi-cluster: stale `kube-prometheus-stack` values on the data plane + +:::warning Data plane upgrade from v1.0.0 +The v1.0.0 multi-cluster Data Plane values file included `kube-prometheus-stack` configuration. This subchart was removed in later versions; metrics collection is now handled by the standalone community module. + +When upgrading from v1.0.0, the stored Helm values still contain `kube-prometheus-stack` configuration. `--reset-then-reuse-values` reapplies these against the new chart schema, causing: + +``` +UPGRADE FAILED: values don't meet the specifications of the schema(s): +- at '': additional properties 'kube-prometheus-stack' not allowed +``` + +Check whether your stored values contain the stale key: + +```bash +helm get values openchoreo-data-plane -n openchoreo-data-plane --kube-context $DP_CONTEXT +``` + +If the output includes `kube-prometheus-stack`, use `--reset-values` with your multi-cluster values file instead of `--reset-then-reuse-values` for the Data Plane upgrade: + +```bash +helm upgrade openchoreo-data-plane ... --kube-context $DP_CONTEXT \ + --reset-values \ + --values +``` + +`--reset-values` discards all previously stored values (including the stale `kube-prometheus-stack` key) and uses the new chart's defaults. The `--values` flag reapplies your multi-cluster overrides (for example `clusterAgent.serverUrl`, `gateway.tls.enabled: false`), which are required for the Data Plane to function correctly. Single-cluster deployments are not affected. +::: diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.1-to-v1.2.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.1-to-v1.2.mdx new file mode 100644 index 00000000..c486e3a6 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/upgrades/v1.1-to-v1.2.mdx @@ -0,0 +1,520 @@ +--- +title: v1.1 to v1.2 +description: Upgrade an OpenChoreo installation from v1.1 to v1.2 across all planes, including the Project.spec.type migration on the control plane. +sidebar_position: 3 +--- + +# Upgrading from v1.1 to v1.2 + +This guide covers upgrading an OpenChoreo installation from v1.1 to v1.2 across every plane. Review the [upgrade overview](./overview.mdx) — including the upgrade policy and backup recommendations — before you begin, and upgrade the **control plane first**. + +:::warning Breaking change on the control plane +v1.2 introduces the project release lifecycle (`ProjectType`, `ClusterProjectType`, `ProjectRelease`, `ProjectReleaseBinding`) and makes `Project.spec.type` a required, immutable field. Upgrading the control plane requires a **staged migration** — do not run a plain `helm upgrade` on the control plane. See [Upgrading the Control Plane](#upgrading-the-control-plane). The data and workflow planes upgrade normally. +::: + +## Prerequisites + +- `kubectl` access to the cluster(s) with permission to manage CRDs. +- `jq` and `yq` (v4) on the machine running the upgrade. +- The extracted v1.2 charts for the planes you run, for the CRDs under each chart's `crds/` directory. At minimum the control-plane chart is required for the migration: + + ```bash + helm pull oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane --version 1.2.0 --untar + ``` + + This unpacks the chart into `./openchoreo-control-plane/`, which the commands below reference. Pull the `openchoreo-data-plane`, `openchoreo-workflow-plane`, and `openchoreo-observability-plane` charts the same way if you have those planes installed. + +- A maintenance window. Nothing may perform full-object writes to `Project` resources while the field is being backfilled (see step 0 of the control-plane migration). + +Every command targets the current kubeconfig context. To target a different cluster, add `--context ` to each `kubectl` command and `--kube-context ` to each `helm` command, and set `-n ` where a plane's namespace is not the default. + +### Gateway API and kgateway + +v1.1 runs Gateway API **v1.4.1 (experimental channel)** and kgateway **v2.2.1**; v1.2 aligns on Gateway API **v1.5.1 (standard channel)** and kgateway **v2.3.1**. Do this for each plane you will upgrade. You can complete it upfront as a prerequisite: + +- **Single-cluster**: do this once, on the **control plane**. The data plane and observability plane reuse the control plane's gateway controller and the cluster's (cluster-scoped) Gateway API CRDs, so they need no separate action. +- **Multi-cluster**: do this on **each plane** you run — the **control plane**, **data plane**, and **observability plane** since each cluster has its own gateway controller and Gateway API CRDs. + +#### Gateway API CRDs + +The control-plane and observability-plane releases include a `TLSRoute` rendered at `gateway.networking.k8s.io/v1alpha2`. In the v1.5.1 standard channel `TLSRoute` is served at `v1` only, so once you apply the v1.5.1 CRDs, `helm upgrade` can no longer decode the current release manifest and fails with `no matches for kind "TLSRoute" in version "gateway.networking.k8s.io/v1alpha2"`. Keep `v1alpha2` served across the upgrade so Helm can read the old manifest; the v1.2 chart then re-renders the route at `v1`. + +On each cluster you are upgrading (see above): + +```bash +# Apply the v1.5.1 standard CRDs (this stops serving TLSRoute v1alpha2)... +kubectl apply --server-side --force-conflicts \ + -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml + +# ...then re-serve v1alpha2 so `helm upgrade` can still decode the current release manifest. +idx=$(kubectl get crd tlsroutes.gateway.networking.k8s.io -o json \ + | jq '.spec.versions | map(.name == "v1alpha2") | index(true)') +kubectl patch crd tlsroutes.gateway.networking.k8s.io --type=json \ + -p "[{\"op\": \"replace\", \"path\": \"/spec/versions/${idx}/served\", \"value\": true}]" +``` + +After the plane upgrade succeeds, its release references only `TLSRoute/v1`. You may then re-apply the standard CRDs to return `v1alpha2` to `served: false` (optional cleanup — the extra served version is otherwise harmless): + +```bash +kubectl apply --server-side --force-conflicts \ + -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml +``` + +:::note Data plane +The data plane serves no `TLSRoute`, so it never needs the `v1alpha2` re-serve step. Where the data plane runs its own gateway controller (multi-cluster), upgrade its Gateway API CRDs to v1.5.1 only if the API gateway module you run supports Kubernetes Gateway API 1.5. If it does not, skip the data-plane Gateway API upgrade and keep the data plane on Kubernetes Gateway API 1.4 — check your module's supported version in the [API Gateway modules](https://openchoreo.dev/ecosystem/?category=API+Gateway) in the Ecosystem Catalog. +::: + +#### kgateway + +Upgrade kgateway on each cluster you are upgrading (see above). Add `-n ` for the plane (`openchoreo-control-plane`, `openchoreo-data-plane`, or `openchoreo-observability-plane`): + +```bash +helm upgrade kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \ + --version v2.3.1 -n + +helm upgrade kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \ + --version v2.3.1 --reset-values -n + +kubectl rollout status deployment/kgateway -n --timeout=120s +``` + +`--reset-values` drops the v1.1 `KGW_ENABLE_GATEWAY_API_EXPERIMENTAL_FEATURES` flag, which v1.2 no longer needs now that `TLSRoute` is GA in the standard channel. If you are keeping a plane on Gateway API 1.4 (see the data plane note above), keep the flag with `--reuse-values` instead. + +## Upgrading the Control Plane + +The control plane carries this release's breaking change. Instead of the standard "apply CRDs, then `helm upgrade`" flow, the control plane upgrade is a staged migration that keeps reconciliation working while `Project.spec.type` is backfilled across existing projects. + +### What breaks + +v1.2 adds a required, immutable field to `Project`: + +```yaml +spec: + type: # NEW: required, immutable + kind: ClusterProjectType # defaults to ProjectType if omitted + name: default +``` + +Existing `Project` objects in etcd do not have `spec.type`. CRD schema validation runs on every write, including status-subresource writes, so once the strict v1.2 CRD is installed, any write to a `Project` that lacks `spec.type` is rejected with a required-field error. The still-running v1.1 controller updates `Project` status on every reconcile, which means installing the strict CRD before backfilling the field breaks reconciliation for every existing project. + +The upgrade therefore stages the CRD change: first install a relaxed `Project` CRD (identical to v1.2 except `spec.type` is optional), backfill `spec.type` on all projects, verify, then install the strict CRD set and upgrade the control plane. + +### Are you affected? + +Any project that predates v1.2 lacks `spec.type`. List them: + +```bash +kubectl get projects.openchoreo.dev -A -o json \ + | jq -r '.items[] | select(.spec.type == null) | "\(.metadata.namespace)/\(.metadata.name)"' +``` + +If this prints nothing, every project already carries `spec.type` and you can skip the backfill (steps 1 and 2). If it prints project names, follow every step in order. + +### How deployed state carries over + +In v1.2, a project is deployed to an environment only where a `ProjectReleaseBinding` exists for the (project, environment) tuple. The controller never creates bindings; clients do. For projects created on v1.1 no client ever did, so this upgrade creates them. + +Step 5 creates **unpinned** bindings (`spec.projectRelease` left empty). Pinning is handled by the v1.2 Project controller's seeding contract: on first reconcile it resolves `spec.type`, cuts a `ProjectRelease` snapshot, records it in `status.latestRelease`, and fills the pin on any binding of the project whose pin is empty. A set pin is never touched; advancing it later is a promotion action (occ, GitOps, kubectl edit). You cannot pin bindings by hand because release names embed a server-computed hash. + +By default step 5 creates one binding per environment in the project's deployment pipeline. This matches v1.1 behavior, where a component could be promoted to any pipeline environment without a project-level gate. If you would rather a project deploy to only some of its environments, create bindings for just those environments (see [step 5](#step-5-create-projectreleasebindings-for-existing-projects)); a component can then reach the remaining environments only after the project is promoted there. + +### Why this is safe for running workloads + +The `ProjectReleaseBinding` controller computes the namespace name with the same function and the same inputs as the v1.1 `ReleaseBinding` controller: `dp-{orgNamespace}-{project}-{env}-{hash}`. After the upgrade, the binding's `RenderedRelease` server-side-applies a `Namespace` manifest with exactly the name your workloads already run in. The existing namespace is adopted, not replaced. Components and component bindings are untouched throughout. Only control-plane reconciliation pauses during the upgrade window; running workloads on data planes are not affected by the migration steps. + +One behavior change to be aware of: in v1.1 the `RenderedRelease` controller implicitly created the cell namespace (`dp-{orgNamespace}-{project}-{env}-{hash}`). v1.2 removes that. The namespace is now part of the project's released manifests, applied through the `ProjectReleaseBinding`. For migrated projects the namespace is created through the project release manifest, which adopts the existing namespace, so nothing changes. For projects created after the upgrade, component deployments wait until the project is released to the environment. + +### Migration steps + +#### Step 0: Pause writers to Project resources + +The v1.1 controller manager and openchoreo-api use typed clients that do not know `spec.type`. Any full-object spec update they perform after the backfill (for example a project update through the v1.1 API or console) serializes the spec without the field and silently erases it while the relaxed CRD is in place. Scale them down until step 6 resumes them: + +```bash +kubectl -n openchoreo-control-plane scale deployment controller-manager openchoreo-api --replicas=0 +``` + +Confirm both deployments have no running pods before continuing: + +```bash +kubectl -n openchoreo-control-plane get pods -l 'app.kubernetes.io/name in (controller-manager, openchoreo-api)' +``` + +**GitOps users:** if `Project` manifests are managed by Flux or ArgoCD, suspend syncing for them now. See [GitOps installations](#gitops-installations) to update GitOps repositories. + +#### Step 1: Install the relaxed (migration) Project CRD + +Generate a relaxed CRD from the v1.2 chart by removing `type` from the spec's required list, then apply it server-side. Nothing else changes; in particular the immutability rule (`self == oldSelf`) stays, because CEL transition rules on an optional field are skipped when the field is absent from the old object, so the unset-to-set backfill in step 2 still passes. + +```bash +yq 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.required[] | select(. == "type"))' \ + openchoreo-control-plane/crds/openchoreo.dev_projects.yaml > projects-crd-relaxed.yaml + +kubectl apply --server-side --force-conflicts -f projects-crd-relaxed.yaml +``` + +The apply uses `--server-side` because the generated CRD exceeds the client-side-apply annotation size limit. It passes `--force-conflicts` because on a v1.1 cluster the CRD fields are owned by the `helm` field manager from the original install, and server-side apply refuses to overwrite another manager's fields without it. Taking ownership is intended and safe: Helm never writes `crds/` on `helm upgrade`, so no later Helm operation contends for the fields, and Update-based writers (Helm, controllers) bypass field-ownership checks entirely. + +After this step, existing projects remain valid and writable, and `spec.type` is accepted when present. + +#### Step 2: Backfill spec.type on all existing projects + +:::warning +If any project should use a (Cluster)ProjectType other than `default`, patch it manually **before** running the generic backfill below. `spec.type` is immutable once set: once the backfill stamps `default` on a project, moving it to a different type requires deleting and recreating the project. + +```bash +kubectl patch projects.openchoreo.dev -n --type merge \ + -p '{"spec":{"type":{"kind":"ClusterProjectType","name":""}}}' +``` + +::: + +Patch every remaining project that lacks `spec.type` to reference the default `ClusterProjectType` shipped with v1.2. Preview first, then apply: + +```bash +# Preview: list the projects that would be patched +kubectl get projects.openchoreo.dev -A -o json \ + | jq -r '.items[] | select(.spec.type == null) | "\(.metadata.namespace)/\(.metadata.name)"' + +# Apply +kubectl get projects.openchoreo.dev -A -o json \ + | jq -r '.items[] | select(.spec.type == null) | [.metadata.namespace, .metadata.name] | @tsv' \ + | while IFS=$'\t' read -r ns name; do + echo "Patching ${ns}/${name}" + kubectl patch projects.openchoreo.dev "$name" -n "$ns" --type merge \ + -p '{"spec":{"type":{"kind":"ClusterProjectType","name":"default"}}}' + done +``` + +**Verification gate.** Do not proceed until this prints nothing: + +```bash +kubectl get projects.openchoreo.dev -A -o json \ + | jq -r '.items[] | select(.spec.type == null) | "\(.metadata.namespace)/\(.metadata.name)"' +``` + +#### Step 3: Install the full v1.2 CRD set + +Apply every CRD from the extracted v1.2 chart. This replaces the relaxed `Project` CRD with the strict one (`spec.type` required) and installs the new CRDs (`projecttypes`, `clusterprojecttypes`, `projectreleases`, `projectreleasebindings`) plus any other CRD changes in the release. Helm does not upgrade files under `crds/` on `helm upgrade`, so this manual apply is required regardless of the breaking change. + +```bash +kubectl apply --server-side --force-conflicts -f openchoreo-control-plane/crds/ +``` + +`--force-conflicts` is required for the same reason as in step 1: every pre-existing CRD is still field-managed by `helm`. The strict schema is enforced on writes only; the backfilled objects already satisfy it. + +#### Step 4: Apply the default ClusterProjectType + +The `default` ClusterProjectType is the target of every backfilled `spec.type` reference. It provisions only the namespace per environment: + +```bash +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/v1.2.0/samples/getting-started/cluster-project-types/default.yaml +``` + +Apply it before upgrading the control plane. The new Project controller watches `ClusterProjectType` and recovers if it arrives late, but applying it first avoids a wave of transient `ProjectTypeNotFound` conditions on startup. Apply any custom (Cluster)ProjectTypes referenced in step 2 now as well. + +#### Step 5: Create ProjectReleaseBindings for existing projects + +For each project, this resolves its deployment pipeline, expands the environments from `spec.promotionPaths` (sources and targets, deduplicated, in pipeline order), and creates one unpinned binding named `{project}-{env}` per environment. It skips any (project, environment) tuple that already has a binding, so it is idempotent and coexists with bindings authored via GitOps. + +```bash +kubectl get projects.openchoreo.dev -A -o json \ + | jq -r '.items[] | [.metadata.namespace, .metadata.name, (.spec.deploymentPipelineRef.name // "")] | @tsv' \ + | while IFS=$'\t' read -r ns project pipeline; do + if [ -z "$pipeline" ]; then + echo "skip ${ns}/${project}: no deploymentPipelineRef"; continue + fi + + # Environments in promotion-path order, deduplicated + envs="$(kubectl get deploymentpipelines.openchoreo.dev "$pipeline" -n "$ns" -o json \ + | jq -r '.spec.promotionPaths[]? | (.sourceEnvironmentRef.name, (.targetEnvironmentRefs[]?.name))' \ + | awk '!seen[$0]++')" + + # A while/read loop (not `for env in $envs`) so word splitting is by + # line in both bash and zsh; zsh does not split unquoted $envs. + while IFS= read -r env; do + [ -n "$env" ] || continue + # Skip if a binding for this (project, environment) already exists + if kubectl get projectreleasebindings.openchoreo.dev -n "$ns" -o json \ + | jq -e --arg p "$project" --arg e "$env" \ + 'any(.items[]; .spec.owner.projectName == $p and .spec.environment == $e)' >/dev/null; then + echo "skip (${project}, ${env}): binding already exists"; continue + fi + + echo "Creating ProjectReleaseBinding ${ns}/${project}-${env}" + cat <` or disable ArgoCD auto-sync). +2. Add `spec.type` to every `Project` manifest in the source repository, mirroring what step 2 applies in-cluster: + + ```yaml + spec: + type: + kind: ClusterProjectType + name: default + ``` + +3. Add `ProjectReleaseBinding` manifests to the repository. Instead of piping each manifest to `kubectl create` in step 5, redirect it to a file (one document per binding, separated by `---`) and commit it: + + ```bash + printf -- '---\n' >> project-release-bindings.yaml + cat <> project-release-bindings.yaml + apiVersion: openchoreo.dev/v1alpha1 + kind: ProjectReleaseBinding + ... + EOF + ``` + + Manifests that omit `spec.projectRelease` are safe under GitOps: the controller seeds the pin server-side and, under server-side apply, a manifest that does not set the field never contends for it. To drive promotion from Git instead, set `spec.projectRelease` explicitly; the controller then never touches it. + +4. Resume syncing after step 6, once the source of truth includes both changes. + +### Rolling back the control plane + +Before step 3, rollback is trivial: scale the v1.1 deployments back up (step 6's scale command). The relaxed CRD is a superset of the v1.1 schema and the backfilled `spec.type` values are inert to the v1.1 controller. + +After step 6, roll back with `helm rollback` and re-apply the relaxed `Project` CRD from step 1 (not the v1.1 CRD: re-applying a schema without `spec.type` would prune the backfilled field on the next write and forfeit the migration work). Leave the new CRDs and their objects in place; they are inert without the v1.2 controllers. The v1.1 `RenderedRelease` controller restores implicit namespace creation, so workloads keep functioning either way. + +### Control plane failure modes + +| Symptom | Cause | Fix | +| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| `Apply failed with N conflicts: conflicts with "helm"` on a CRD apply | v1.1 CRDs are field-managed by `helm` from the original install | Apply with `--force-conflicts` (steps 1 and 3 already do); safe because Helm never writes `crds/` after install | +| `helm upgrade` fails with `no endpoints available for service "controller-manager-webhook-service"` | Writers still scaled to 0 from step 0; the admission webhooks have no backend | Run step 6's scale-up, wait for the rollout, re-run the upgrade (re-upgrading a FAILED release is safe) | +| `spec.type: Required value` on project writes | Step 3 ran before the backfill completed | Re-apply the relaxed CRD from step 1, finish step 2, re-run step 3 | +| `spec.type cannot be changed after creation` during backfill | Project already has a different `spec.type` set | Intentional; immutable once set. Skip it, or recreate the project if the type is wrong | +| Project shows `ProjectTypeNotFound` after upgrade | Step 4 skipped or the referenced type named differently | Apply the missing (Cluster)ProjectType; the controller recovers via its watch | +| Binding stays unpinned after upgrade | Project controller has not cut the release yet, or the project's type is unresolvable | Check the project's conditions; fix the type reference, the controller seeds the pin on the next reconcile | +| Binding missing for an environment | Environment not in the pipeline's promotion paths, or bindings were created for a subset of environments | Re-run step 5 (idempotent) or create the binding manually / via occ | +| GitOps sync fails on Project manifests | Source manifests lack `spec.type` | Add `spec.type` to the manifests in the source repository | +| A project lost `spec.type` between steps 2 and 3 | A v1.1 writer performed a full-object update during the window | Re-run step 2; keep writers scaled down (step 0) | +| `helm upgrade` fails: `no matches for kind "TLSRoute" in version "gateway.networking.k8s.io/v1alpha2"` | Gateway API CRDs were upgraded to v1.5.1 standard (which stops serving `TLSRoute v1alpha2`), but the current release manifest still references it | Re-serve `v1alpha2` before upgrading — see [Gateway API and kgateway](#gateway-api-and-kgateway) | + +## Upgrading the other planes + +The data, workflow, and observability planes have no backward-incompatible changes in v1.2. Upgrade each plane you run with the [standard upgrade process](./overview.mdx#standard-upgrade-process) — apply the plane's updated CRDs, then `helm upgrade` with `--version 1.2.0 --reset-then-reuse-values` — after the control plane is on v1.2. + +Make sure the [Gateway API and kgateway](#gateway-api-and-kgateway) prerequisites are done for each plane you upgrade. The observability plane renders a `TLSRoute` and needs the `v1alpha2` re-serve; the data plane does not, and its Gateway API upgrade is conditional on the API gateway module (see that section). + +:::warning Observability plane now requires explicit control-plane URLs +v1.2 removes the `localhost` defaults the observability-plane chart previously shipped for the URLs the Observer uses to reach the control plane. Those fields now carry `.invalid` placeholders guarded by a chart-side validation gate, so `helm upgrade` fails before rendering: + +``` +Error: UPGRADE FAILED: execution error at (openchoreo-observability-plane/templates/validate.yaml:1:4): Placeholder domains found. Set real URLs for: + - observer.controlPlaneApiUrl contains placeholder domain (.invalid) + - observer.extraEnvs contains placeholder domain (.invalid) (e.g. OBSERVER_BASE_URL) +``` + +This affects **only** installations that relied on the old defaults. If you set these values explicitly at v1.1 install time, `--reset-then-reuse-values` carries them forward and the upgrade proceeds unchanged. If you did not, supply real values on upgrade. +The same change also cleared the default CORS origins (`cors.allowedOrigins`) on these APIs to `[]`: which does not fail the upgrade, but it disables CORS, so any browser client that calls the Observer cross-origin — for example the OpenChoreo Backstage Console — is blocked until you restore the origins. +For a single-cluster or local install, all three fields take the values the v1.1 chart used to default to: + +| Field | v1.1 default | If left unset in v1.2 | +| ------------------------------------------ | -------------------------------------------- | ---------------------------------------------------------------------- | +| `observer.controlPlaneApiUrl` | `http://api.openchoreo.localhost:8080` | Upgrade fails (placeholder gate) | +| `observer.extraEnvs` → `OBSERVER_BASE_URL` | `http://observer.openchoreo.localhost:11080` | Upgrade fails (placeholder gate) | +| `observer.cors.allowedOrigins` | `["http://openchoreo.localhost:8080"]` | Upgrade succeeds, but CORS is disabled and browser clients are blocked | + +```bash +helm upgrade openchoreo-observability-plane \ + oci://ghcr.io/openchoreo/helm-charts/openchoreo-observability-plane \ + --version 1.2.0 --reset-then-reuse-values -n openchoreo-observability-plane \ + -f - <<'EOF' +observer: + controlPlaneApiUrl: "http://api.openchoreo.localhost:8080" + extraEnvs: + - name: OBSERVER_BASE_URL + value: "http://observer.openchoreo.localhost:11080" + - name: AUTHZ_TIMEOUT + value: "30s" + cors: + allowedOrigins: + - "http://openchoreo.localhost:8080" +EOF +``` + +Replace the hostnames and origins with the values valid for your deployment; the sample restores the previous single-cluster defaults, and in a multi-cluster install the URLs must be routable from the observability plane to the control plane while `allowedOrigins` must list the origins your browser clients are served from. +If you enable the RCA or FinOps agents, add their `openchoreoApiUrl` and `cors.allowedOrigins` under `rca` and `finOpsAgent` too; the URLs are gated the same way and the CORS defaults were cleared identically. +::: + +### Community module versions + +If you use the default logs, metrics, and traces modules at the versions from the OpenChoreo v1.1 documentation, upgrade them to the versions compatible with v1.2 as well. + +- Observability Logs OpenSearch module: v0.4.1 -> v0.5.3 + +```bash +helm upgrade --install observability-logs-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-logs-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.5.3 \ + --reset-then-reuse-values \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" \ + --set adapter.openSearchSecretName="opensearch-admin-credentials" +``` + +- Observability Metrics Prometheus module: v0.6.1 -> v0.6.2 (replace the LoadBalancer service with ClusterIP) + +```bash +helm upgrade --install observability-metrics-prometheus \ + oci://ghcr.io/openchoreo/helm-charts/observability-metrics-prometheus \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.2 \ + --reset-then-reuse-values +``` + +- Observability Traces OpenSearch module: v0.4.2 -> v0.6.0 + +```bash +helm upgrade --install observability-traces-opensearch \ + oci://ghcr.io/openchoreo/helm-charts/observability-tracing-opensearch \ + --create-namespace \ + --namespace openchoreo-observability-plane \ + --version 0.6.0 \ + --reset-then-reuse-values \ + --set openSearch.enabled=false \ + --set openSearchSetup.openSearchSecretName="opensearch-admin-credentials" +``` + +- Observability Events OTEL Collector module: (new in v1.2) + +v1.2 adds the persisted Kubernetes events feature, served by a new `observability-events-otel-collector` module. It is not part of any existing release, so an in-place upgrade does not add it — install it explicitly. +The example below stores events in the same OpenSearch backend the other modules use, authenticating with the `opensearch-admin-credentials` secret: + +```bash +helm upgrade --install observability-events-otel-collector \ + oci://ghcr.io/openchoreo/helm-charts/observability-events-otel-collector \ + --namespace openchoreo-observability-plane --version 0.1.1 \ + -f - <<'EOF' +collector: + extraEnv: + - name: OPENSEARCH_USERNAME + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: username + - name: OPENSEARCH_PASSWORD + valueFrom: + secretKeyRef: + name: opensearch-admin-credentials + key: password +extraExtensions: + basicauth/opensearch: + client_auth: + username: ${env:OPENSEARCH_USERNAME} + password: ${env:OPENSEARCH_PASSWORD} +exporters: + opensearch: + logs_index: "k8s-events" + logs_index_time_format: "yyyy-MM-dd" + http: + endpoint: "https://opensearch:9200" + tls: + insecure_skip_verify: true + auth: + authenticator: basicauth/opensearch +pipelineExporters: + - opensearch +EOF +``` + +## Verifying and rolling back + +Verify the control-plane migration with the checks in [step 7](#step-7-post-upgrade-verification), and verify the remaining planes as described in the [standard process](./overview.mdx#verify). + +For rollback: the control plane has version-specific caveats — see [Rolling back the control plane](#rolling-back-the-control-plane). Roll back the other planes with the standard [rollback](./overview.mdx#rollback) steps. diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/auto-build.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/auto-build.mdx new file mode 100644 index 00000000..37a996af --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/auto-build.mdx @@ -0,0 +1,89 @@ +--- +title: Auto Build +description: Configure automatic builds when code is pushed to your Git repository. +--- + +# Auto Build + +Auto Build enables automatic component builds when code is pushed to a Git repository. Instead of manually triggering builds, you can configure components to build automatically whenever changes are pushed to the repository. + +## Prerequisites + +Before configuring auto-build, ensure you have: + +1. OpenChoreo installed and running +2. Workflow plane installed in your OpenChoreo cluster +3. A Component created in OpenChoreo pointing to a Git repository +4. Access to create webhooks in your Git repository + +## Configuration + +### Step 1: Create the Webhook Secret + +Create a Kubernetes secret to store the webhook secret that will be used to validate incoming webhooks: + +```bash +# Generate a random secret +WEBHOOK_SECRET=$(openssl rand -hex 32) +echo "Your webhook secret: $WEBHOOK_SECRET" + +# Create the Kubernetes secret +kubectl create secret generic git-webhook-secrets \ + -n openchoreo-control-plane \ + --from-literal=github-secret="$WEBHOOK_SECRET" + +# Verify the secret was created +kubectl get secret git-webhook-secrets -n openchoreo-control-plane +``` + +:::warning Important +Save the `$WEBHOOK_SECRET` value. You will need it when configuring the webhook in your Git provider. +::: + +### Step 2: Configure the Webhook in Your Git Provider + +Create a webhook in your Git provider that points to OpenChoreo's webhook endpoint. OpenChoreo uses a single unified endpoint (`/api/v1alpha1/autobuild`) for all Git providers — the provider is identified automatically from the request headers sent by the Git provider (e.g. `X-GitHub-Event` for GitHub, `X-Event-Key` for Bitbucket). + +The following example shows how to configure this in GitHub: + +1. Go to your repository +2. Navigate to **Settings** > **Webhooks** > **Add webhook** +3. Configure the webhook: + +| Field | Value | +| ---------------- | ------------------------------------------------------------- | +| **Payload URL** | `https:///api/v1alpha1/autobuild` | +| **Content type** | `application/json` | +| **Secret** | The `$WEBHOOK_SECRET` you generated in Step 1 | +| **Which events** | Select "Just the push event" | +| **Active** | Checked | + +4. Click **Add webhook** + +GitHub will send a test ping event. You should see a green checkmark if the webhook was delivered successfully. + +### Step 3: Enable Auto-Build on Components + +Developers enable auto-build on their Components by setting `autoBuild: true`. See the [developer Auto-Build guide](../../developer-guide/workflows/ci/auto-build.md) for the Component configuration and field reference. + +### Step 4: Verify + +After a developer enables auto-build on a Component and pushes code, verify a WorkflowRun is created: + +```bash +kubectl get workflowrun +``` + +## Local Development Testing + +For local testing with a development cluster, you can use ngrok to expose your local OpenChoreo instance to receive webhooks from your Git provider: + +```bash +ngrok http --host-header=api.openchoreo.localhost 8080 +``` + +Use the ngrok HTTPS URL as your webhook payload URL: + +``` +https://abc123xyz.ngrok-free.app/api/v1alpha1/autobuild +``` diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/ci-governance.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/ci-governance.md new file mode 100644 index 00000000..87fcd2ab --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/ci-governance.md @@ -0,0 +1,244 @@ +--- +title: CI Governance +description: Configure CI workflow labels, schema extensions, and ComponentType governance for component builds +--- + +# CI Governance + +CI workflows (also called component workflows) are [Workflows](./overview.md) that integrate with OpenChoreo's component system to provide automated builds. This page covers how to configure CI-specific labels, schema extensions, and governance rules. + +For creating workflows, see [Creating Workflows](./creating-workflows.mdx). For the developer perspective on using CI workflows, see [CI Workflows](../../developer-guide/workflows/ci/overview.md). + +## CI Workflow Requirements + +A Workflow becomes a CI workflow when: + +1. **It carries `openchoreo.dev/workflow-type: "component"`** label — Required for UI and CLI to categorize the workflow +2. **A Component references it** via `Component.spec.workflow.name` +3. **It is listed in `ComponentType.spec.allowedWorkflows`** — This is how you control which workflows are available for components of a given type + +There is no separate CRD: CI workflows are just Workflows that are allowed by a ComponentType and referenced by Components. + +## Labels and Schema Extensions + +### `openchoreo.dev/workflow-type` label + +Required for workflows intended to be used by Components. The UI and CLI use this label to identify and categorize a workflow as a CI workflow. + +```yaml +metadata: + labels: + openchoreo.dev/workflow-type: "component" +``` + +### Vendor extension fields for Auto-Build and UI + +CI workflows must annotate specific `openAPIV3Schema` fields with `x-openchoreo-component-parameter-repository-*` vendor extensions. These extensions tell OpenChoreo which parameter fields correspond to repository settings, enabling the auto-build feature (triggered by Git webhooks) and UI integration. + +| Extension | Purpose | Required | +| -------------------------------------------------------- | --------------------------------------- | -------- | +| `x-openchoreo-component-parameter-repository-url` | Identifies the Git repository URL field | No | +| `x-openchoreo-component-parameter-repository-branch` | Identifies the Git branch field | No | +| `x-openchoreo-component-parameter-repository-commit` | Identifies the Git commit SHA field | No | +| `x-openchoreo-component-parameter-repository-app-path` | Identifies the application path field | No | +| `x-openchoreo-component-parameter-repository-secret-ref` | Identifies the secret reference field | No | + +Add `true` to each extension on the corresponding schema field: + +```yaml +parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + x-openchoreo-component-parameter-repository-url: true + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + x-openchoreo-component-parameter-repository-secret-ref: true + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + x-openchoreo-component-parameter-repository-branch: true + commit: + type: string + default: "" + description: "Git commit SHA or reference (optional, defaults to latest)" + x-openchoreo-component-parameter-repository-commit: true + appPath: + type: string + default: "." + description: "Path to the application directory within the repository" + x-openchoreo-component-parameter-repository-app-path: true +``` + +:::tip +The field structure (nesting, names) is flexible — OpenChoreo discovers the fields by walking the schema tree for these extensions, regardless of where they are placed. These extensions are **required if you use auto-build** (Git webhook-triggered builds), and optional otherwise to enable richer UI behavior. +::: + +## WorkflowRun Labels + +When a WorkflowRun is created for a component, it carries labels that link it to the component: + +```yaml +metadata: + labels: + openchoreo.dev/component: greeter-service + openchoreo.dev/project: default +``` + +These labels are accessible in the Workflow CR's CEL expressions: + +- `${metadata.labels['openchoreo.dev/component']}` — Component name +- `${metadata.labels['openchoreo.dev/project']}` — Project name + +## Architecture + + + +## Governance via ComponentTypes + +Platform engineers control which CI workflows are available for components using ComponentType's `allowedWorkflows` field. This is the primary governance mechanism for CI workflows. + +### How It Works + +1. **Platform Engineer defines `allowedWorkflows`** in a ComponentType +2. **When a developer creates a Component**, they must reference a workflow in `spec.workflow.name` +3. **The Component controller validates** that the referenced workflow is in the ComponentType's `allowedWorkflows` list +4. **If validation fails**, the Component enters a Failed state with a condition explaining the error + +### allowedWorkflows Field + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterComponentType +metadata: + name: backend +spec: + # Restrict components to using only these ClusterWorkflows + allowedWorkflows: + - kind: ClusterWorkflow + name: dockerfile-builder + - kind: ClusterWorkflow + name: gcp-buildpacks-builder +``` + +Each entry has two fields: + +- **`kind`** — `ClusterWorkflow` (cluster-scoped) or `Workflow` (namespace-scoped). Defaults to `ClusterWorkflow`. +- **`name`** — Name of the workflow resource. + +Only Workflows listed in `allowedWorkflows` can be referenced by Components of this type. + +### Governance Patterns + +**Pattern 1: Single Workflow (Strict)** + +```yaml +spec: + allowedWorkflows: + - kind: ClusterWorkflow + name: dockerfile-builder +``` + +**Pattern 2: Multiple Workflows (Developer Choice)** + +```yaml +spec: + allowedWorkflows: + - kind: ClusterWorkflow + name: dockerfile-builder + - kind: ClusterWorkflow + name: gcp-buildpacks-builder + - kind: Workflow + name: custom-react-builder +``` + +**Pattern 3: Language-Specific Workflows** + +```yaml +spec: + allowedWorkflows: + - kind: ClusterWorkflow + name: dockerfile-builder # For compiled languages + - kind: ClusterWorkflow + name: gcp-buildpacks-builder # For interpreted languages +``` + +### Validation and Error Handling + +#### Component-level validation + +When a Component references a workflow that's not in `allowedWorkflows`, the Component controller rejects it: + +```yaml +conditions: + - type: Ready + status: False + reason: WorkflowNotAllowed + message: "Workflow 'custom-workflow' is not in ComponentType 'backend' allowedWorkflows" +``` + +The Component will not proceed to creating WorkflowRuns until the workflow is either added to `allowedWorkflows` or changed to one that is allowed. + +#### WorkflowRun-level validation + +When a WorkflowRun is created with component labels (`openchoreo.dev/component` and `openchoreo.dev/project`), the WorkflowRun controller performs additional validations before execution: + +| Validation | Condition Reason | Description | +| -------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------- | +| Both labels required | `ComponentValidationFailed` | If one of `openchoreo.dev/project` or `openchoreo.dev/component` is set, both must be present | +| Component exists | `ComponentValidationFailed` | The referenced Component must exist in the same namespace | +| Project label matches | `ComponentValidationFailed` | The `openchoreo.dev/project` label must match the Component's owner project | +| ComponentType exists | `ComponentValidationFailed` | The Component's ComponentType (or ClusterComponentType) must exist | +| Workflow allowed | `ComponentValidationFailed` | The workflow referenced by the WorkflowRun must be in the ComponentType's `allowedWorkflows` | +| Workflow matches component | `ComponentValidationFailed` | If the Component has `spec.workflow` configured, the WorkflowRun must reference the same workflow | +| Workflow exists | `WorkflowNotFound` | The referenced Workflow or ClusterWorkflow must exist in the cluster | +| WorkflowPlane available | `WorkflowPlaneNotFound` | A WorkflowPlane must be available for the workflow | + +All `ComponentValidationFailed` conditions are permanent failures. `WorkflowPlaneNotFound` is transient and retried automatically. + +### Benefits of This Governance Model + +1. **Security** — Platform engineers ensure only approved build processes are used +2. **Consistency** — All components of a type follow the same build patterns +3. **Compliance** — Easy to enforce organizational policies (e.g., "all builds must scan for vulnerabilities") +4. **Flexibility** — Different component types can have different allowed workflows +5. **Developer Experience** — Clear error messages when trying to use disallowed workflows + +## Default CI Workflows + +OpenChoreo ships with four default ClusterWorkflow CRs and their supporting ClusterWorkflowTemplates: + +| ClusterWorkflow | Build CWT | Description | +| ----------------------------- | --------------------------- | ------------------------------------------------------------- | +| `dockerfile-builder` | `containerfile-build` | Build with a provided Dockerfile/Containerfile/Podmanfile | +| `gcp-buildpacks-builder` | `gcp-buildpacks-build` | Supports Go, Java, Node.js, Python, and .NET applications | +| `paketo-buildpacks-builder` | `paketo-buildpacks-build` | Supports Java, Node.js, Python, Go, .NET, Ruby, PHP, and more | +| `ballerina-buildpack-builder` | `ballerina-buildpack-build` | Builds applications written in Ballerina | + +## What's Next + +- [Workload Publishing Credentials](./workflow-workload-configuration.mdx) — Configure OAuth for CI workflow authentication +- [Auto Build](./auto-build.mdx) — Set up Git webhook-triggered builds +- [Schema Syntax](./schema-syntax.md) — Detailed reference for workflow parameter schemas diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/creating-workflows.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/creating-workflows.mdx new file mode 100644 index 00000000..33adb18d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/creating-workflows.mdx @@ -0,0 +1,633 @@ +--- +title: Creating Workflows +description: Step-by-step guide for creating custom Workflows in OpenChoreo +--- + +import { CardGrid, Card } from "@site/src/components/common/CardGrid"; + +# Custom Workflows + +Custom workflows allow Platform Engineers to define reusable pipelines. This step-by-step guide walks you through creating a Workflow. + +## Prerequisites + +Before diving in, you'll need: + + + + Understanding of ClusterWorkflowTemplates and Workflows. + https://argo-workflows.readthedocs.io/en/latest/ + + + Experience writing custom resources with apiVersion,{" "} + kind, metadata, and spec. + + + WorkflowPlane installed with Argo Workflows. + + + +## Overview + +Custom workflows allow Platform Engineers to define reusable pipelines. These workflows leverage Argo Workflows in the workflow plane and are made available to developers through Workflow resources. + + + +
+
+ + Argo Cluster Workflow Template + PE write +
+
The step definitions (clone, scan, execute, push). This is where your actual workflow logic lives.
+ +
+ + Argo Workflow + Auto-generated +
+
Rendered in Workflow Plane: Automatically generated at runtime when the control plane instantiates your Workflow. Created directly in the workflow plane cluster from the Argo Workflow defined in your Control Plane Workflow resource.
+
+ +
+ + +
+
+ + Workflow (Template) + PE write +
+
Defines what parameters exist, which are for developers vs. system-provided, and embeds an Argo Workflow that references your ClusterWorkflowTemplates.
+ +
+ + Workflow Run (Instance) + Developer create +
+
Renders the argo workflow defined in the Workflow and applies it to the Workflow Plane.
+
+ +
+
+ +To create custom workflows, follow these steps: + +1. **Create ClusterWorkflowTemplate** in the workflow plane (defines the actual workflow steps) +2. **Define Argo Workflow** structure that references the ClusterWorkflowTemplate (defines parameters and workflow configuration) +3. **Create Workflow** in the control plane (defines the schema and embeds the Argo Workflow template) + +## Step 1: Create Argo ClusterWorkflowTemplate + +The ClusterWorkflowTemplate defines the actual Argo Workflow steps that will execute in the workflow plane. Our default ClusterWorkflowTemplates provide a good reference as a starting point. You can copy existing steps and add additional steps as needed. + +Learn more about cluster workflow templates: https://argo-workflows.readthedocs.io/en/latest/cluster-workflow-templates/ + +- Platform Engineers can write individual steps including cloning source code, trivy scans, tests, etc. +- For example, the `checkout-source` step includes the logic to detect the Git provider, authenticate to private repositories, and checkout specific commits or branches. +- Platform Engineers can decide which parameters to expose in the ClusterWorkflowTemplate to make it more reusable. Common parameters include git-revision, image name, image tag, etc. +- You can use different parameter syntax in the ClusterWorkflowTemplate: +- `{{inputs.parameters.git-revision}}` - Accesses an input parameter passed to this template from another step. +- `{{workflow.parameters.component-name}}` - Accesses a global workflow parameter passed from the Argo Workflow (see [Argo Workflows documentation](https://argo-workflows.readthedocs.io/en/latest/walk-through/steps/)). +- `{{steps.checkout-source.outputs.parameters.git-revision}}` - Accesses an output parameter named `git-revision` from a previous step named `checkout-source`. + +### Example: A Docker Build ClusterWorkflowTemplate + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ClusterWorkflowTemplate +metadata: + name: docker # CWT name referenced by your Workflow +spec: + templates: + - name: build-image # Step template name + inputs: + parameters: + - name: git-revision # From previous step (checkout) + container: + image: ghcr.io/openchoreo/podman-runner:v1.0 + command: + - sh + - -c + args: + - |- + set -e + + # Setup variables from workflow parameters + WORKDIR="/mnt/vol/source" + IMAGE="{{workflow.parameters.image-name}}:{{workflow.parameters.image-tag}}-{{inputs.parameters.git-revision}}" + DOCKER_CONTEXT="{{workflow.parameters.docker-context}}" + DOCKERFILE_PATH="{{workflow.parameters.dockerfile-path}}" + + # Configure container storage (podman) + mkdir -p /etc/containers + cat > /etc/containers/storage.conf < +
+
1️⃣
+
+ Hard-coded Parameters +

Who: Platform Engineers

+

Example: trivy-scan: "true"

+

Values defined and locked in the Workflow definition. Used for consistent, non-negotiable settings.

+
+
+ +
+
+ 2️⃣ +
+
+ Developer-provided Parameters +

+ Who: Developers +

+

+ Examples: repo-url, branch,{" "} + timeout +

+

+ Values provided when creating or triggering workflows. Flexible inputs + configured per workflow run. +

+
+
+ +
+
3️⃣
+
+ System-generated Parameters +

Who: OpenChoreo

+

Examples: workflowRunName, namespaceName, externalRefs

+

Automatically injected from runtime context. Managed entirely by the platform.

+
+
+ + +After identifying these three types of parameters, you can create the Workflow, which is an OpenChoreo Custom Resource (CR). + +## Step 3: Define Workflow + +### 3.1 Define the Schema with Parameters + +The Workflow schema defines which parameters are exposed to developers. + +:::tip +The schema uses standard [OpenAPI v3 JSON Schema](https://swagger.io/specification/) format under `openAPIV3Schema`. See the [Workflow API Reference](../../reference/api/platform/workflow.md) for full details and examples. +::: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: google-cloud-buildpacks + namespace: acme + +spec: + # Type 2: Developer-provided parameters (exposed to developers) + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + commit: + type: string + default: "" + description: "Git commit SHA (optional, defaults to latest)" + appPath: + type: string + default: "." + description: "Path to application directory" + timeout: + type: string + default: "30m" + description: "Workflow execution timeout" + resourceCpu: + type: string + default: "1" + description: "CPU resource request" + trivyScan: + type: boolean + default: true + description: "Enable security scanning" + + # Type 1: Hard-coded parameters (defined by Platform Engineers) + # Note: These are defined in the runTemplate, not in the schema +``` + +### 3.2 Attach the Argo Workflow Template + +Link the Argo Workflow from Step 2 to the Workflow by embedding it in the `runTemplate` field. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: google-cloud-buildpacks + namespace: acme + +spec: + # Type 2: Developer-provided parameters (exposed to developers) + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + secretRef: + type: string + default: "" + description: "Secret reference for Git credentials" + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + timeout: + type: string + default: "30m" + description: "Workflow execution timeout" + resourceCpu: + type: string + default: "1" + description: "CPU resource request" + + # Embed the Argo Workflow from Step 2 + # Uses CEL expressions (${...}) to inject parameters + runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + + metadata: + # Type 3: System-generated - Unique workflow run name + name: ${metadata.workflowRunName} + # Type 3: System-generated - Workflow plane namespace + namespace: ${metadata.namespace} + spec: + arguments: + parameters: + # Type 3: System-generated parameters from workflow run labels + - name: component-name + value: ${metadata.labels['openchoreo.dev/component']} + - name: project-name + value: ${metadata.labels['openchoreo.dev/project']} + + # Type 3: System-generated parameters + - name: image-name + value: ${metadata.namespaceName}-${metadata.workflowRunName} + + # Type 2: Developer-provided parameters + - name: repo-url + value: ${parameters.repository.url} + - name: branch + value: ${parameters.repository.revision.branch} + - name: timeout + value: ${parameters.timeout} + - name: resource-cpu + value: ${parameters.resourceCpu} + - name: git-secret-name + value: ${parameters.repository.secretRef} + + # Type 1: Hard-coded parameters (locked by Platform Engineers) + - name: trivy-scan + value: "true" + - name: registry + value: "ghcr.io" + + # Auto-created by OpenChoreo with necessary permissions + serviceAccountName: workflow-sa + + # Entry point for the workflow execution + entrypoint: build-workflow + + # Pipeline definition with steps + templates: + - name: build-workflow + steps: + # Step 1: Checkout source code from repository + - - name: checkout-source + templateRef: + name: checkout-source # References ClusterWorkflowTemplate + clusterScope: true + template: checkout + + # Step 2: Build container image + - - name: build-image + ... +``` + +### 3.3 Define Additional Resources (Optional) + +You might need Secrets, ConfigMaps, or other Custom Resources to be created in the workflow plane for your workflow steps. Define them in the `resources` field: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: google-cloud-buildpacks + namespace: acme + +spec: + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + required: + - url + properties: + url: + type: string + description: "Git repository URL" + # ... + + # Embed the Argo Workflow (from previous section) + runTemplate: + # ... + + # Additional resources created in workflow plane namespace + # Available to Argo Workflow during execution + resources: + - id: git-secret + # Create ExternalSecret for Git credentials + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${metadata.workflowRunName}-git-secret + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + kind: ClusterSecretStore + name: ${workflowplane.secretStore} + target: + name: ${metadata.workflowRunName}-git-secret + creationPolicy: Owner + template: + type: Opaque + data: + - secretKey: username + remoteRef: + key: git-credentials + property: username + - secretKey: password + remoteRef: + key: git-credentials + property: token +``` + +### 3.4 Define External References (Optional) + +External references allow your Workflow to resolve and access external Custom Resources (like `SecretReference`) at runtime. This is useful for: + +- **Dynamic credential resolution** - Reference secrets managed externally +- **Conditional resource creation** - Only create resources when needed +- **Reusable credential patterns** - Access secrets across multiple workflow runs + +#### How External References Work + +External references are resolved by OpenChoreo **before** the Workflow is instantiated. You can access the full referenced object and its fields in your expressions. + +#### Example: Using a SecretReference + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: docker-with-secrets + namespace: acme + +spec: + parameters: + openAPIV3Schema: + type: object + properties: + repository: + type: object + properties: + secretRef: + type: string + default: "" + description: "SecretReference for Git credentials" + + # Declare external references that will be resolved + externalRefs: + - id: git-secret-reference # Unique identifier for this reference + apiVersion: openchoreo.dev/v1alpha1 + kind: SecretReference # Only SecretReference is supported currently + name: ${parameters.repository.secretRef} # Name comes from parameter + + # Use external refs in runTemplate resources + runTemplate: ... + + # Additional resources using external reference data + resources: + - id: git-credentials + # Only create if secretRef was provided + includeWhen: ${has(parameters.repository.secretRef) && parameters.repository.secretRef != ""} + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${metadata.workflowRunName}-git-secret + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + kind: ClusterSecretStore + name: ${workflowplane.secretStore} + target: + name: ${metadata.workflowRunName}-git-secret + creationPolicy: Owner + # Access the secret template type from external reference + template: + type: ${externalRefs['git-secret-reference'].spec.template.type} + # Map secret data from external reference + data: | + ${externalRefs['git-secret-reference'].spec.data.map(secret, { + "secretKey": secret.secretKey, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) ? secret.remoteRef.property : oc_omit() + } + })} +``` + +#### Accessing External Reference Data + +Once resolved, you can access the external reference in your expressions: + +```yaml +# Access the entire spec of the external reference +${externalRefs['git-secret-reference'].spec} + +# Access specific fields +${externalRefs['git-secret-reference'].spec.template.type} + +# Iterate over array fields +${externalRefs['git-secret-reference'].spec.data} + +# Use in conditional logic +${has(externalRefs['git-secret-reference']) && externalRefs['git-secret-reference'].spec.enabled} +``` + +#### Key Points + +- **ID is required** - Each external reference must have a unique `id` +- **Name can be parameterized** - Use `${parameters.*}` or `${metadata.*}` in the name +- **Graceful missing handling** - If the `name` evaluates to empty, the reference is silently skipped +- **Full object access** - Both the external reference object and its `.spec` are accessible +- **Conditional creation** - Use `includeWhen` to conditionally create resources based on external refs + +:::info +For more details on external references and SecretReferences, see the [Workflow API Reference](../../reference/api/platform/workflow.md). +::: + +## See Also + +- [Running Workflows](./running-workflows.md) — How to trigger and monitor WorkflowRuns +- [Workflow API Reference](../../reference/api/platform/workflow.md) — Full resource specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/external-ci.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/external-ci.mdx new file mode 100644 index 00000000..be14c417 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/external-ci.mdx @@ -0,0 +1,604 @@ +--- +title: External CI Integration +description: Integrate any external CI pipeline with OpenChoreo via the Workload API +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# External CI Integration + +Any external CI pipeline can integrate with OpenChoreo by calling the Workload API. Instead of using OpenChoreo's built-in CI (Argo Workflows), you can use your existing CI infrastructure to build container images and trigger deployments. + +## Overview + +OpenChoreo supports two approaches for building components: + +1. **Built-in CI** - Argo Workflows managed by OpenChoreo +2. **External CI** - Your own CI pipeline builds images and creates workloads via API + +The integration point is a single REST endpoint: + +``` +POST /api/v1/namespaces/{namespaceName}/workloads +Authorization: Bearer +Content-Type: application/json +``` + +The request body specifies Workload CR in JSON format. Any external CI pipeline that can build an image and make this API call can integrate with OpenChoreo. For the full schema and examples, see the [Workload API Reference](../../reference/api/application/workload.md). + +This guide covers the External CI approach, where: + +- Your CI pipeline builds the container image +- Your CI calls the OpenChoreo API to create/update workloads +- OpenChoreo handles deployment, scaling, and observability + +:::note +Steps 1–3 cover wiring an external CI pipeline to the Workload API, with worked examples for both **Jenkins** and **GitHub Actions** — the same approach applies to any CI tooling. Steps 4 and 5 cover surfacing build status back in the Backstage portal for **Jenkins** and **GitHub Actions** respectively; follow whichever matches your CI. +::: + +## Prerequisites + +- OpenChoreo installed and running +- Access to your identity provider (ThunderID IDP or configured OIDC provider) +- Your CI system (Jenkins, GitHub Actions, or any other) configured and accessible +- Container registry accessible to both CI and OpenChoreo cluster + +## Step 1: Create a Service Account + +External CI needs OAuth2 client credentials to obtain JWT tokens for authenticating with the OpenChoreo API. + +### Using ThunderID IDP (Default) + +If you're using the bundled ThunderID IDP, create an OAuth2 application through the ThunderID console. + +:::info +See [Identity Configuration](../identity-configuration.mdx) for ThunderID access details and default credentials. +::: + +#### 1. Create an OAuth2 Application + +1. Open the ThunderID console at `/console` +2. Log in with your admin credentials (default: `admin` / `admin`) +3. Create a new application and select **Backend Service** (server-to-server APIs) as the application type +4. Copy the **Client ID** and **Client Secret** and store them securely in your CI system's secret store (e.g., Jenkins credentials or GitHub Actions secrets) + +#### 2. Verify Token Generation + +You can test the credentials by exchanging them for an access token: + +```bash +curl -X POST "/oauth2/token" \ + -u ":" \ + -d "grant_type=client_credentials" +``` + +:::tip +For long-running CI pipelines, configure a longer token validity period in the application settings within the ThunderID console. +::: + +### Using Other Identity Providers + +If you've configured a different OIDC provider, create a service account following your provider's documentation. The token must include claims that OpenChoreo can validate against your security configuration. + +## Step 2: Create Component with External CI + +When creating a new component in Backstage: + +1. Navigate to **Create** in Backstage +2. Select your component type +3. For **Deployment Source**, choose **"External CI"** +4. Optionally configure your CI system (Jenkins or GitHub Actions) for build visibility +5. Complete the wizard + +The component is created without a workload. Your CI pipeline will create workloads when builds complete. + +## Step 3: Configure Your CI Pipeline + +### Jenkins + +Store the following as Jenkins credentials before using this pipeline: + +| Credential ID | Type | Description | +| ----------------------- | ---------------------- | --------------------------------------------------------------- | +| `workflows-credentials` | Username with password | Client ID (username) and Client Secret (password) from Step 1 | +| `thunder-url` | Secret text | ThunderID IDP URL (e.g., `https://thunder.example.com`) | +| `openchoreo-api-url` | Secret text | OpenChoreo API URL (e.g., `https://api.openchoreo.example.com`) | + +```groovy +pipeline { + agent any + + environment { + NAMESPACE = 'default' + PROJECT = 'my-project' + COMPONENT = 'my-service' + REGISTRY = 'registry.example.com' + } + + stages { + stage('Build & Push') { + steps { + script { + env.IMAGE = "${REGISTRY}/${COMPONENT}:${BUILD_NUMBER}" + sh "docker build -t ${env.IMAGE} ." + sh "docker push ${env.IMAGE}" + } + } + } + + stage('Deploy to OpenChoreo') { + steps { + withCredentials([ + usernamePassword( + credentialsId: 'workflows-credentials', + usernameVariable: 'CLIENT_ID', + passwordVariable: 'CLIENT_SECRET' + ), + string(credentialsId: 'thunder-url', variable: 'THUNDER_URL'), + string(credentialsId: 'openchoreo-api-url', variable: 'OPENCHOREO_API_URL') + ]) { + sh ''' + # Get access token + TOKEN=$(curl -sf -X POST "${THUNDER_URL}/oauth2/token" \ + -d "grant_type=client_credentials" \ + -d "client_id=${CLIENT_ID}" \ + -d "client_secret=${CLIENT_SECRET}" \ + | jq -r '.access_token') + + # Create/update workload + curl -sf -X POST \ + "${OPENCHOREO_API_URL}/api/v1/namespaces/${NAMESPACE}/workloads" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\\"containers\\":{\\"main\\":{\\"image\\":\\"${IMAGE}\\"}}}" + ''' + } + } + } + } +} +``` + +### GitHub Actions + +The same two API calls work from a GitHub Actions workflow: build and push the image, then **register the Workload** with OpenChoreo. Store the OAuth client credentials and API/IDP URLs as [repository or organization secrets](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) before using this workflow: + +| Secret | Description | +| -------------------------- | --------------------------------------------------------------- | +| `OPENCHOREO_CLIENT_ID` | Client ID from [Step 1](#step-1-create-a-service-account) | +| `OPENCHOREO_CLIENT_SECRET` | Client Secret from [Step 1](#step-1-create-a-service-account) | +| `THUNDER_URL` | ThunderID IDP URL (e.g., `https://thunder.example.com`) | +| `OPENCHOREO_API_URL` | OpenChoreo API URL (e.g., `https://api.openchoreo.example.com`) | + +```yaml +name: Build and deploy to OpenChoreo + +on: + push: + branches: [main] + +env: + NAMESPACE: default + PROJECT: my-project + COMPONENT: my-service + REGISTRY: registry.example.com + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build & push image + run: | + IMAGE="${REGISTRY}/${COMPONENT}:${GITHUB_SHA::7}" + echo "IMAGE=${IMAGE}" >> "${GITHUB_ENV}" + docker build -t "${IMAGE}" . + docker push "${IMAGE}" + + - name: Register the workload with OpenChoreo + env: + CLIENT_ID: ${{ secrets.OPENCHOREO_CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.OPENCHOREO_CLIENT_SECRET }} + THUNDER_URL: ${{ secrets.THUNDER_URL }} + OPENCHOREO_API_URL: ${{ secrets.OPENCHOREO_API_URL }} + run: | + set -euo pipefail + + # 1. Get an access token (client_credentials grant) + TOKEN=$(curl -sf -X POST "${THUNDER_URL}/oauth2/token" \ + -d "grant_type=client_credentials" \ + -d "client_id=${CLIENT_ID}" \ + -d "client_secret=${CLIENT_SECRET}" \ + | jq -r '.access_token') + + # 2. Build the Workload CR payload (image only; add endpoints and + # configurations here, or generate it from a workload.yaml — see note below) + WORKLOAD_NAME="${COMPONENT}" + cat > workload-cr.json < workflowrun-updated.json + curl -sf -X PUT \ + "${OPENCHOREO_API_URL}/api/v1/namespaces/${NAMESPACE}/workflowruns/${RUN_NAME}" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d @workflowrun-updated.json +``` + +:::note +Steps 2–4 above are exactly what the built-in `generate-workload` workflow template does. For the full payload shape (endpoints, configurations), generating the CR from a `workload.yaml` descriptor with `occ workload create`, and the meaning of the `openchoreo.dev/workload` and `openchoreo.dev/workload-from-source` annotations, see [Workload Generation](./workload-generation.md) and the [Workload API Reference](../../reference/api/application/workload.md). +::: + +## Step 4: Enable Jenkins Visibility in Backstage + +OpenChoreo Backstage includes a built-in Jenkins plugin that displays build status and history directly in the portal. + +### Enable Jenkins Plugin (Administrator) + +The Jenkins plugin is always installed. Enabling it requires two things: storing the Jenkins API key in the Backstage secret, and setting the connection details via Helm values. + +#### Store the Jenkins API Key + +The API key is read from the `jenkins-api-key` key in the Backstage credentials secret (referenced by `backstage.secretName`). Add it the same way other Backstage secrets are managed. + + + + +If you followed the [k3d setup](../../getting-started/try-it-out/on-k3d-locally.mdx) or [on your environment](../../getting-started/try-it-out/on-your-environment.mdx) guide, the `jenkins-api-key` is already present in your `ClusterSecretStore` and `ExternalSecret` with a placeholder value. Update it in your secret provider with a real Jenkins API token. + +For OpenBao (default local dev setup), update the secret value: + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/backstage-jenkins-api-key value="your-real-jenkins-api-key" +' +``` + +Then trigger the `ExternalSecret` to sync the updated value: + +```bash +kubectl annotate externalsecret backstage-secrets \ + -n openchoreo-control-plane \ + force-sync=$(date +%s) --overwrite +``` + +Restart Backstage to pick up the new secret: + +```bash +kubectl rollout restart deployment/backstage -n openchoreo-control-plane +``` + + + + +If you manage the Backstage secret directly without External Secrets Operator: + +```bash +kubectl create secret generic backstage-secrets \ + -n openchoreo-control-plane \ + --from-literal=backend-secret="your-backend-secret" \ + --from-literal=client-secret="your-client-secret" \ + --from-literal=jenkins-api-key="your-real-jenkins-api-key" \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +Restart Backstage to pick up the new secret: + +```bash +kubectl rollout restart deployment/backstage -n openchoreo-control-plane +``` + + + + +#### Enable Jenkins in Helm Values + +Set the Jenkins base URL and username. The API key is picked up from the secret automatically. + +```yaml +backstage: + externalCI: + jenkins: + enabled: true + baseUrl: "https://jenkins.example.com" + username: "admin" +``` + +### Add Jenkins Annotation to Components + +Once the plugin is enabled, add the Jenkins annotation to your components to display build status. + +1. Navigate to your component in Backstage +2. Click the context menu (**...**) and select **Edit Annotations** +3. Add the annotation: `jenkins.io/job-full-name` = `/job/my-org/job/my-service` +4. Click **Save** + +### What You'll See + +When configured correctly: + +- **Overview Page**: A Jenkins status card appears showing recent build status +- **Jenkins Tab**: A dedicated tab shows detailed build history and logs + +:::note +You can also configure Jenkins annotations during component creation by selecting Jenkins in the wizard. +::: + +### Troubleshooting Jenkins Visibility + +**Jenkins tab shows but API calls fail:** + +- Check `baseUrl` and `username` are correct in Helm values +- Verify the `jenkins-api-key` value in your Backstage secret is a valid Jenkins API token +- Ensure Jenkins is accessible from the Kubernetes cluster +- Verify the job path in the annotation matches the actual Jenkins job + +**Jenkins status cards not showing on Overview:** + +- Cards only appear when the entity has a Jenkins annotation +- If an external CI annotation is present, it replaces the OpenChoreo Workflows card +- Check browser console for any JavaScript errors + +## Step 5: Enable GitHub Actions Visibility in Backstage + +OpenChoreo Backstage includes a built-in GitHub Actions plugin that displays `workflow_run` history directly in the portal. Once configured, a Component's **CI/CD** tab lists recent runs for the annotated repository. + +:::info Two GitHub credentials are involved +The GitHub Actions card authenticates **each portal user** through a GitHub **OAuth App** — this is how a user who can see a private repository on GitHub sees its runs in the portal. The optional backend token in [section 5.4](#54-optional-provision-a-github-backend-token) is a _separate_ credential used only by Backstage backend plugins (catalog ingestion, scaffolder, TechDocs); it is **not** what the card reads. Set up the OAuth App first — without it the card cannot fetch runs even with a valid token. +::: + +### 5.1 Create a GitHub OAuth App + +In GitHub, go to **Settings → Developer settings → OAuth Apps → New OAuth App** (use an organization-owned App for shared portals): + +| Field | Value | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| Homepage URL | Your portal base URL, e.g. `http://openchoreo.localhost:8080` | +| Authorization callback URL | `/api/auth/github/handler/frame`, e.g. `http://openchoreo.localhost:8080/api/auth/github/handler/frame` | + +Record the **Client ID** and generate a **Client secret**. For GitHub Enterprise Server, create the OAuth App on your GHES instance instead of github.com. + +:::warning +The callback URL must match the portal base URL **exactly** (scheme, host, and port). A mismatch makes GitHub reject the login with a `redirect_uri` error. +::: + +### 5.2 Store the OAuth credentials + +The OAuth client secret is read from the `github-oauth-client-secret` key in the Backstage credentials secret (referenced by `backstage.secretName`). Add it the same way other Backstage secrets are managed. + + + + +If you followed the [k3d setup](../../getting-started/try-it-out/on-k3d-locally.mdx) or [on your environment](../../getting-started/try-it-out/on-your-environment.mdx) guide, `backstage-secrets` is owned by External Secrets Operator (`creationPolicy: Owner`). Do **not** patch the Kubernetes Secret directly — ESO overwrites it on the next sync. Seed the values into your secret backend and map them through the `ExternalSecret` instead. + +Seed the OpenBao KV (the convention is `secret/backstage-`, value under the `value` property): + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/backstage-github-oauth-client-secret value="your-real-client-secret" +' +``` + +:::warning +The client secret is sensitive. Read it into a variable rather than pasting it inline — inline values land in your shell history and in the `kubectl exec` process args (visible via `ps` and audit logs). Rotate any secret exposed that way. +::: + +Add the key to the `backstage-secrets` `ExternalSecret` so ESO maps it onto the Kubernetes Secret. `/spec/data/-` appends, so run this **once** — re-running duplicates the entry: + +```bash +kubectl patch externalsecret backstage-secrets -n openchoreo-control-plane --type=json -p='[ + {"op":"add","path":"/spec/data/-","value":{"secretKey":"github-oauth-client-secret","remoteRef":{"key":"backstage-github-oauth-client-secret","property":"value"}}} +]' +``` + +Force a re-sync rather than waiting for the `refreshInterval`: + +```bash +kubectl annotate externalsecret backstage-secrets \ + -n openchoreo-control-plane \ + force-sync=$(date +%s) --overwrite +``` + + + + +If you manage `backstage-secrets` directly (no External Secrets Operator), add the key to that Secret. Export the value first so the command is copy-paste-safe: + +```bash +export GH_OAUTH_CLIENT_SECRET="your-real-client-secret" + +kubectl -n openchoreo-control-plane patch secret backstage-secrets --type=json -p='[ + {"op":"add","path":"/data/github-oauth-client-secret","value":"'"$(printf %s "$GH_OAUTH_CLIENT_SECRET" | base64 | tr -d '\n')"'"} +]' +``` + + + + +### 5.3 Enable GitHub Actions in Helm Values + +Set the integration on and pass the OAuth **Client ID** (the client _secret_ comes from the Secret you stored in 5.2). The chart then renders the `auth.providers.github` block and the `integrations.github` config automatically. + + + + +```bash +helm upgrade --install openchoreo-control-plane \ + oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane --version 0.0.0-latest-dev \ + --namespace openchoreo-control-plane \ + --set backstage.externalCI.githubActions.enabled=true \ + --set backstage.externalCI.githubActions.oauth.clientId="your-oauth-client-id" \ + --reset-then-reuse-values +``` + + + + +```bash +helm upgrade --install openchoreo-control-plane \ + oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane --version 0.0.0-latest-dev \ + --namespace openchoreo-control-plane \ + --set backstage.externalCI.githubActions.enabled=true \ + --set backstage.externalCI.githubActions.host="ghe.example.com" \ + --set backstage.externalCI.githubActions.apiBaseUrl="https://ghe.example.com/api/v3" \ + --set backstage.externalCI.githubActions.oauth.clientId="your-oauth-client-id" \ + --reset-then-reuse-values +``` + + + + +Restart Backstage to pick up the new configuration: + +```bash +kubectl rollout restart deployment/backstage -n openchoreo-control-plane +``` + +### 5.4 (Optional) Provision a GitHub backend token + +Skip this unless you also use the Backstage **backend** GitHub integration (catalog ingestion, scaffolder git operations, TechDocs). The Actions card itself does not need it — it uses the per-user OAuth flow above. + +- **For github.com:** create a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new) scoped to the relevant repositories with `Actions: Read` and `Metadata: Read` permissions. +- **For org-wide / production:** create a [GitHub App](https://docs.github.com/en/apps/creating-github-apps), install it on the org, and pass the installation token — App tokens scale better and don't expire with the user that created them. +- **For GHES:** create the token on your GHES instance (the `host`/`apiBaseUrl` from 5.3 already point Backstage at it). + +Store it under the `github-actions-token` key the same way as 5.2 (OpenBao path `secret/backstage-github-actions-token`, or a direct Secret patch on `/data/github-actions-token`). The key is declared `optional: true` on the Deployment, so Backstage starts whether or not it is present. + +### Add the GitHub Annotation to Components + +For any Component whose workflows you want to see, set the `github.com/project-slug` annotation: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service + annotations: + github.com/project-slug: my-org/my-service +spec: + # ... +``` + +This is the same annotation the upstream [`@backstage/plugin-github-actions`](https://www.npmjs.com/package/@backstage/plugin-github-actions) plugin reads. + +:::note +The card reads this annotation from the **Backstage catalog entity**, not from the OpenChoreo Component CR directly. If your catalog sync does not copy the CR annotation onto the entity, set `github.com/project-slug` on the catalog entity itself. +::: + +### What You'll See + +When configured correctly: + +- **CI/CD Tab**: A dedicated tab lists recent workflow runs for the annotated repository. +- The first time you open it, complete the one-time GitHub login when the popup appears. + +### Troubleshooting GitHub Actions Visibility + +**The card shows a sign-in prompt that fails, or `/api/auth/github/start` returns `404 No auth provider registered for 'github'`:** + +- The GitHub OAuth provider is not registered. Complete [section 5.1](#51-create-a-github-oauth-app)–[5.3](#53-enable-github-actions-in-helm-values): create the OAuth App, set `oauth.clientId`, store `github-oauth-client-secret`, and restart Backstage. + +**The login popup opens but errors with a `redirect_uri` mismatch:** + +- The OAuth App's callback URL must be exactly `/api/auth/github/handler/frame` (scheme, host, and port matching the URL the browser uses). + +**The CI/CD tab shows no runs even though the workflow ran:** + +- Verify the `github.com/project-slug` annotation is on the Backstage **catalog entity** and matches the repository slug exactly (`/`, case-sensitive). +- For a **private** repository, the signed-in user must have access to it on GitHub and must have approved the `repo` scope during the OAuth consent. + +**GitHub Enterprise Server users see `Cannot find host` errors:** + +- Both `host` and `apiBaseUrl` must be set. Setting only one causes the other to fall back to github.com defaults. + +## Troubleshooting + +### 401 Unauthorized + +- **Token expired**: Get a new token using client credentials +- **Invalid token**: Verify your `client_id` and `client_secret` +- **Wrong JWKS**: Ensure ThunderID/IDP URL is correctly configured in OpenChoreo + +### 404 Not Found + +- **Component doesn't exist**: Create the component first in Backstage +- **Wrong path**: Verify namespace, project, and component names match exactly + +### 403 Forbidden + +- **Missing permissions**: Service account may lack required roles +- **Namespace restriction**: Check if service account has access to the target namespace + +### Connection Refused + +- **API not accessible**: Verify `OPENCHOREO_API_URL` is reachable from CI runner +- **Firewall rules**: Ensure CI runners can reach the OpenChoreo API endpoint + +### Debug Tips + +1. **Test token generation** independently: + + ```bash + curl -v -X POST "$THUNDER_URL/oauth2/token" \ + -d "grant_type=client_credentials" \ + -d "client_id=$CLIENT_ID" \ + -d "client_secret=$CLIENT_SECRET" + ``` + +2. **Test API connectivity** with a simple GET: + + ```bash + curl -v -H "Authorization: Bearer $TOKEN" \ + "$OPENCHOREO_API_URL/api/v1/namespaces" + ``` + +3. **Check workload status** after creation: + ```bash + curl -H "Authorization: Bearer $TOKEN" \ + "$OPENCHOREO_API_URL/api/v1/namespaces/$NAMESPACE/workloads?component=$COMPONENT" + ``` + +## Best Practices + +- **Rotate credentials regularly**: Set up credential rotation for service accounts +- **Use short-lived tokens**: Configure appropriate token validity periods +- **Implement retry logic**: Handle transient API failures gracefully +- **Tag images consistently**: Use git SHAs or semantic versions for traceability +- **Secure secrets**: Use your CI system's secret store (Jenkins credentials, GitHub Actions secrets, etc.) for storing sensitive values +- **Monitor deployments**: Set up alerts for failed workload creations diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/architecture.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/architecture.png new file mode 100644 index 00000000..f3f13f39 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/architecture.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/ci-architecture.png b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/ci-architecture.png new file mode 100644 index 00000000..0813c448 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/images/ci-architecture.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/overview.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/overview.md new file mode 100644 index 00000000..b89b97b4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/overview.md @@ -0,0 +1,151 @@ +--- +title: Overview +description: Understand how Workflows work in OpenChoreo +--- + +# Workflows in OpenChoreo + +OpenChoreo provides a unified **Workflow** design for running automation tasks. Whether you need component CI builds, infrastructure provisioning, data pipelines, or any other automation, it all uses the same Workflow and WorkflowRun resources. + +:::note +OpenChoreo currently supports only Argo Workflows as the underlying engine for executing workflows. It can be extended to support more Kubernetes-native engines. +::: + +## Multi-Plane Architecture + + + +- **Control Plane**: Hosts Workflow and WorkflowRun CRs, orchestrates execution +- **Workflow Plane**: Executes Argo Workflows using ClusterWorkflowTemplates, performs compute-intensive operations +- **Communication**: Control plane controller connects to workflow plane via a websocket connection + +In Single Cluster Setup, both planes run in the same cluster. + +## Core Resources + +### Workflow + +A **Workflow** is a platform engineer-defined template that specifies _what_ to execute. It consists of: + +- **Schema**: Defines developer-facing parameters that can be configured when triggering an execution +- **RunTemplate**: An inline Argo Workflow manifest with CEL expressions (`${metadata.*}`, `${parameters.*}`, `${externalRefs[''].spec.*}`) that composes one or more ClusterWorkflowTemplates into a pipeline +- **Resources**: Additional Kubernetes resources needed for the workflow (e.g., ExternalSecrets for credentials) +- **ExternalRefs**: References to external CRs (e.g., `SecretReference`) resolved at runtime and injected into the CEL context +- **TTLAfterCompletion**: Optional duration after which completed runs are automatically deleted + +Workflows live in the control plane and bridge it to the workflow plane where actual execution happens. + +### WorkflowRun + +A **WorkflowRun** represents a single execution instance. When created, it: + +- References the Workflow to use +- Provides actual values for the schema parameters +- Triggers the controller to render and execute the Argo Workflow in the workflow plane +- Tracks execution state through conditions and task status + +:::warning Imperative Resource +WorkflowRun is an **imperative** resource, it triggers an action rather than declaring a desired state. Do not include WorkflowRuns in GitOps repositories. Instead, create them through Git webhooks, the UI, or direct `occ apply` commands. +::: + +### Argo ClusterWorkflowTemplate + +An Argo **ClusterWorkflowTemplate** (CWT) is an [Argo Workflows](https://argo-workflows.readthedocs.io/en/latest/cluster-workflow-templates/) resource that defines a **single reusable step** at cluster scope in the workflow plane. Each CWT encapsulates one discrete operation - cloning a repo, building an image, pushing to a registry, etc. + +CWTs are **not full pipelines**. Instead, the Workflow CR's `runTemplate` contains an inline Argo Workflow that composes multiple CWTs into a pipeline using per-step `templateRef` references: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +spec: + runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + name: ${metadata.workflowRunName} + namespace: workflows-${metadata.namespaceName} + spec: + serviceAccountName: workflow-sa + entrypoint: pipeline + templates: + - name: pipeline + steps: + - - name: checkout-source + templateRef: + name: checkout-source + template: checkout + clusterScope: true + - - name: build-image + templateRef: + name: docker + template: build-image + clusterScope: true +``` + +:::info You don't create Argo Workflow CRs by hand +At runtime, OpenChoreo renders `runTemplate` and creates an Argo `Workflow` **instance** in the workflow plane. +As a Platform Engineer, you only author the inline template inside the Workflow CR's `runTemplate`. +::: + +:::tip Why Cluster Workflow Templates? +We are recommending to use Argo ClusterWorkflowTemplates for all steps to maximize reuse and maintainability. This way, you can update the logic of a step (e.g., how to build a Docker image) in one place and have it automatically applied to all Workflows that reference it. +::: + +## Workflow Type + +### Generic Workflows + +Generic workflows execute standalone automation tasks not tied to any component. Use them for: + +- **Infrastructure Provisioning** — Terraform, Pulumi, or cloud resource automation +- **Data Processing (ETL)** — Extract, transform, and load pipelines +- **End-to-End Testing** — Integration and acceptance test suites +- **Package Publishing** — Publishing libraries to npm, PyPI, Maven, etc. +- **Custom Docker Builds** — Container image builds not tied to a component + +### CI Workflows + +CI workflows (also known as component workflows) are regular Workflow CRs used within Components. They enable: + +- **Auto-builds** triggered by Git webhooks +- **UI integration** for CI workflow management +- **ComponentType governance** via `allowedWorkflows` +- **Workload generation** from build outputs + +In OpenChoreo, a Workflow is "component-capable" when: + +1. It carries `openchoreo.dev/workflow-type: "component"` (required for UI to categorize CI workflows) +2. It is referenced by a Component via `Component.spec.workflow.name` +3. It is explicitly allowed by the ComponentType via `ComponentType.spec.allowedWorkflows` + +See [CI Governance](./ci-governance.md) for the full guide. + +### Resource Cleanup + +WorkflowRuns can be cleaned up in two ways: + +**Manual Deletion**: When deleted via `kubectl delete`, the controller removes all resources created in the workflow plane. + +**Automatic TTL-based Cleanup**: Platform engineers configure `ttlAfterCompletion` in the Workflow template: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: docker +spec: + ttlAfterCompletion: "7d" # Retain for 7 days after completion + # ... +``` + +**TTL format**: Duration string without spaces — days (d), hours (h), minutes (m), seconds (s). Examples: `"90d"`, `"1h30m"`, `"1d12h30m15s"`. + +## What's Next + +- [Creating Workflows](./creating-workflows.mdx) — Step-by-step guide for defining custom Workflows +- [Running Workflows](./running-workflows.md) — How to trigger and monitor WorkflowRuns +- [CI Governance](./ci-governance.md) — CI workflow labels, governance, and auto-build configuration diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/running-workflows.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/running-workflows.md new file mode 100644 index 00000000..4aa37761 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/running-workflows.md @@ -0,0 +1,108 @@ +--- +title: Running Workflows +description: How to trigger and monitor WorkflowRuns +--- + +# Running Workflows + +WorkflowRuns are how you trigger and track workflow executions. This guide covers creating, monitoring, and managing WorkflowRuns. + +## Creating a WorkflowRun + +A WorkflowRun references a Workflow and provides parameter values: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: my-workflow-run-01 + namespace: default +spec: + workflow: + kind: ClusterWorkflow + name: github-stats-report + parameters: + source: + org: "openchoreo" + repo: "openchoreo" +``` + +Apply it: + +```bash +kubectl apply -f workflowrun.yaml +``` + +### Parameter Defaults + +If a Workflow schema defines default values, you can omit those parameters in the WorkflowRun: + +```yaml +spec: + workflow: + kind: ClusterWorkflow + name: github-stats-report + parameters: + source: + org: "myorg" + # repo defaults to "openchoreo" +``` + +## Monitoring Execution + +```bash +# Watch WorkflowRun status +kubectl get workflowrun my-workflow-run-01 -w + +# View detailed status +kubectl get workflowrun my-workflow-run-01 -o yaml +``` + +### Conditions + +WorkflowRuns track execution through conditions: + +| Condition | Description | +| ------------------- | --------------------------------------- | +| `WorkflowRunning` | Argo Workflow is currently executing | +| `WorkflowCompleted` | Workflow completed (success or failure) | +| `WorkflowSucceeded` | Workflow completed successfully | +| `WorkflowFailed` | Workflow failed or errored | + +### Task Status + +The `status.tasks` field provides a vendor-neutral view of individual workflow steps: + +```yaml +status: + tasks: + - name: checkout-source + phase: Succeeded + startedAt: "2024-01-15T10:28:00Z" + completedAt: "2024-01-15T10:28:30Z" + - name: build-image + phase: Running + startedAt: "2024-01-15T10:28:30Z" +``` + +Task phases: `Pending`, `Running`, `Succeeded`, `Failed`, `Skipped`, `Error`. + +## Cleanup + +### Manual Deletion + +```bash +kubectl delete workflowrun my-workflow-run-01 +``` + +This automatically cleans up all resources created in the workflow plane (Argo Workflow, ExternalSecrets, ConfigMaps, etc.). + +### Automatic TTL-based Cleanup + +If the Workflow defines `ttlAfterCompletion`, completed runs are automatically deleted after the specified duration. The TTL is copied from the Workflow to the WorkflowRun at creation time. + +## See Also + +- [Creating Workflows](./creating-workflows.mdx) — How to define Workflows +- [CI Governance](./ci-governance.md) — CI workflow labels, governance, and configuration +- [WorkflowRun API Reference](../../reference/api/application/workflowrun.md) — Full resource specification diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/schema-syntax.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/schema-syntax.md new file mode 100644 index 00000000..2244f766 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/schema-syntax.md @@ -0,0 +1,470 @@ +--- +title: Schema Syntax +description: Parameter schema definition for Workflows using openAPIV3Schema +--- + +# Schema Syntax + +This guide explains how to define parameter schemas for Workflows and ClusterWorkflows using `openAPIV3Schema`. Schemas are defined using standard [OpenAPI v3 JSON Schema](https://swagger.io/docs/specification/data-models/) format. + +## Overview + +Workflow parameters are defined under `spec.parameters.openAPIV3Schema`. They control what developers can configure when creating a WorkflowRun. The schema validates input and provides defaults for omitted fields. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflow +metadata: + name: my-workflow +spec: + parameters: + openAPIV3Schema: + type: object + properties: + fieldName: + type: string + description: "A description of this field" +``` + +## Basic Types + +### Primitives + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + repoUrl: + type: string + description: "Git repository URL" + retryCount: + type: integer + default: 3 + minimum: 0 + maximum: 10 + timeoutMinutes: + type: number + minimum: 0.5 + dryRun: + type: boolean + default: false +``` + +### Arrays + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + buildArgs: + type: array + default: [] + description: "Docker build arguments" + items: + type: object + required: [name, value] + properties: + name: + type: string + description: "Build argument name" + value: + type: string + description: "Build argument value" + tags: + type: array + items: + type: string + default: [] +``` + +### Objects + +For structured parameters, use nested `properties`: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + commit: + type: string + default: "" + description: "Git commit SHA (optional)" + appPath: + type: string + default: "." + description: "Path to the application directory" +``` + +## Required vs Optional Fields + +Fields are **optional by default** in JSON Schema. Use `required` to mark mandatory fields, and `default` to provide fallback values. + +### Required Fields + +Use the `required` keyword at the object level to list mandatory properties: + +```yaml +parameters: + openAPIV3Schema: + type: object + required: + - repository # Must be provided + properties: + repository: + type: object + required: + - url # Must be provided within repository + properties: + url: + type: string + branch: + type: string + default: main # Optional with default +``` + +### Defaults + +Provide `default` values to make fields optional and ensure predictable behavior when omitted: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + # Optional primitives with defaults + timeout: + type: string + default: "30m" + trivyScan: + type: boolean + default: true + + # Optional object with default + docker: + type: object + default: {} + properties: + context: + type: string + default: "." + filePath: + type: string + default: "./Dockerfile" +``` + +When an object has `default: {}`, all its nested field defaults are applied automatically: + +```yaml +# Input: parameters: {} +# Result: docker = {context: ".", filePath: "./Dockerfile"} +``` + +## Validation Constraints + +Standard JSON Schema validation keywords are supported: + +### Strings + +```yaml +identifier: + type: string + minLength: 1 + maxLength: 63 + pattern: "^[a-z]([a-z0-9-]*[a-z0-9])?$" +``` + +### Numbers + +```yaml +replicas: + type: integer + minimum: 1 + maximum: 10 +cpuLimit: + type: number + minimum: 0.1 + exclusiveMinimum: true +``` + +### Enumerations + +```yaml +outputFormat: + type: string + enum: + - table + - json + - yaml + default: "table" + description: "Report output format" +``` + +### Arrays + +```yaml +environments: + type: array + items: + type: string + minItems: 1 + maxItems: 5 + uniqueItems: true +``` + +## Vendor Extensions for CI Workflows + +CI workflows that support auto-build (Git webhook-triggered builds) use `x-openchoreo-component-parameter-repository-*` vendor extensions to identify repository-related fields. See [CI Governance](./ci-governance.md#vendor-extension-fields-for-auto-build-and-ui) for details. + +```yaml +parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + required: + - url + properties: + url: + type: string + description: "Git repository URL" + x-openchoreo-component-parameter-repository-url: true + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + x-openchoreo-component-parameter-repository-secret-ref: true + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + x-openchoreo-component-parameter-repository-branch: true + commit: + type: string + default: "" + x-openchoreo-component-parameter-repository-commit: true + appPath: + type: string + default: "." + x-openchoreo-component-parameter-repository-app-path: true +``` + +## Template Variable Access + +Parameters defined in the schema are accessible in `runTemplate` and `resources` via CEL expressions: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + repository: + type: object + properties: + url: + type: string + revision: + type: object + properties: + branch: + type: string + default: main + timeout: + type: string + default: "30m" + +runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + name: ${metadata.workflowRunName} + namespace: ${metadata.namespace} + spec: + arguments: + parameters: + - name: git-repo + value: ${parameters.repository.url} # Nested access + - name: branch + value: ${parameters.repository.revision.branch} + - name: timeout + value: ${parameters.timeout} # Top-level access +``` + +See [Context Variables](../../reference/cel/context-variables.md#workflow-variables) for all available template variables. + +## Complete Examples + +### CI Workflow (Dockerfile Builder) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflow +metadata: + name: dockerfile-builder + labels: + openchoreo.dev/workflow-type: "component" + annotations: + openchoreo.dev/description: "Build with a provided Dockerfile/Containerfile/Podmanfile" +spec: + ttlAfterCompletion: "1d" + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + x-openchoreo-component-parameter-repository-url: true + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + x-openchoreo-component-parameter-repository-secret-ref: true + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + x-openchoreo-component-parameter-repository-branch: true + commit: + type: string + default: "" + description: "Git commit SHA or reference (optional)" + x-openchoreo-component-parameter-repository-commit: true + appPath: + type: string + default: "." + description: "Path to the application directory" + x-openchoreo-component-parameter-repository-app-path: true + docker: + type: object + default: {} + description: "Docker build configuration" + properties: + context: + type: string + default: "." + description: "Docker build context path" + filePath: + type: string + default: "./Dockerfile" + description: "Path to the Dockerfile" + buildEnv: + type: array + default: [] + description: "Environment variables for the build" + items: + type: object + required: [name, value] + properties: + name: + type: string + value: + type: string +``` + +### Generic Automation Workflow (Terraform) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: aws-rds-postgres-create + namespace: default + annotations: + openchoreo.dev/description: "Provision an AWS RDS PostgreSQL instance using Terraform" +spec: + ttlAfterCompletion: "1d" + parameters: + openAPIV3Schema: + type: object + properties: + git: + type: object + default: {} + description: "Source repository containing Terraform files" + properties: + repoUrl: + type: string + default: "https://github.com/openchoreo/openchoreo.git" + description: "Git repository URL" + branch: + type: string + default: "main" + description: "Branch or tag to check out" + tfPath: + type: string + default: "samples/workflows/aws-rds-postgres-create/terraform" + description: "Path to Terraform files in the repo" + aws: + type: object + default: {} + properties: + region: + type: string + default: "us-east-1" + description: "AWS region for the RDS instance" + credentialsSecret: + type: string + description: "Kubernetes Secret with AWS credentials" + db: + type: object + default: {} + properties: + identifier: + type: string + description: "Unique RDS instance identifier" + name: + type: string + description: "Initial database name" + username: + type: string + description: "Master username" + engineVersion: + type: string + default: "16" + description: "PostgreSQL engine version" +``` + +## Related Resources + +- [Creating Workflows](./creating-workflows.mdx) - Step-by-step guide for defining Workflows +- [Workflow API Reference](../../reference/api/platform/workflow.md) - Full CRD specification +- [Context Variables](../../reference/cel/context-variables.md#workflow-variables) - Template variables available in Workflows +- [CI Governance](./ci-governance.md) - CI workflow labels, governance, and auto-build configuration diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workflow-workload-configuration.mdx b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workflow-workload-configuration.mdx new file mode 100644 index 00000000..3a79c456 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workflow-workload-configuration.mdx @@ -0,0 +1,145 @@ +--- +title: Workload Publishing Credentials +description: Configure OAuth authentication and authorization for CI workflows to publish workloads. +--- + +# Workload Publishing Credentials + +CI workflows in OpenChoreo use the `generate-workload` ClusterWorkflowTemplate to create and update Workload CRs via the OpenChoreo API. This workflow step authenticates as a service account using the OAuth 2.0 client credentials grant. + +By default, OpenChoreo ships with ThunderID as the identity provider and a pre-configured OAuth client (`openchoreo-workload-publisher-client`) for development and testing. When using an external identity provider, platform engineers must configure the OAuth application, store the credentials, update the workflow template, and set up the authorization binding. + +## Prerequisites + +Before configuring, ensure you have: + +1. An external identity provider integrated with OpenChoreo (see [Identity Provider Configuration](../identity-configuration.mdx)) +2. Access to create OAuth applications in your identity provider +3. `kubectl` access to the cluster + +## Step 1: Create an OAuth Application + +Create an OAuth 2.0 application in your identity provider with the following settings: + +- **Grant Type**: `client_credentials` (service-to-service authentication) +- **Token Format**: JWT (not opaque tokens) + +Note the **client ID** and **client secret** — you will need them in the following steps. + +## Step 2: Store the Client Secret + +Store the OAuth client secret in a Kubernetes secret so it can be mounted into workflow steps: + +```bash +kubectl create secret generic workload-publisher-oauth-secret \ + -n \ + --from-literal=client-secret="" +``` + +:::tip +For managing secrets in production environments, refer to the [Secret Management](../secret-management.mdx) guide for best practices using External Secrets Operator. +::: + +## Step 3: Update the ClusterWorkflowTemplate + +The `generate-workload` ClusterWorkflowTemplate accepts OAuth and API server parameters as inputs. Update the default values to point to your identity provider and API server: + +```yaml +- name: generate-workload-cr + inputs: + parameters: + - name: oauth-token-url + default: "https://your-idp.example.com/oauth2/token" + - name: oauth-client-id + default: "" + - name: oauth-client-secret + default: "" + - name: api-server-url + default: "" +``` + +| Parameter | Description | +| --------------------- | ---------------------------------------------------- | +| `oauth-token-url` | Your identity provider's token endpoint | +| `oauth-client-id` | Client ID of the OAuth application created in Step 1 | +| `oauth-client-secret` | Client secret (or reference to Kubernetes secret) | +| `api-server-url` | URL of the OpenChoreo API server | + +:::tip +For production deployments, mount the client secret from the Kubernetes secret into the workflow step as an environment variable or volume, rather than passing it as a workflow parameter. Refer to the [Argo Workflows documentation](https://argo-workflows.readthedocs.io/en/latest/walk-through/kubernetes-resources/) for details on referencing secrets in workflow templates. +::: + +See the [sample workflow template](https://github.com/openchoreo/openchoreo/blob/main/samples/getting-started/workflow-templates/generate-workload.yaml) for a complete example. + +## Step 4: Configure Authorization + +The workload publisher authenticates as a service account using the `client_credentials` grant. The OpenChoreo API matches the `sub` claim in the JWT to identify the caller. You must grant the new client the `workload-publisher` role via a bootstrap authorization mapping. + +OpenChoreo ships with a default `workload-publisher` role that has the minimum required permissions: + +```yaml +- name: workload-publisher + system: true + actions: + - "workload:create" + - "workload:update" + - "workflowrun:view" + - "workflowrun:update" +``` + +Add the following to your Control Plane Helm values, replacing `` with the client ID from Step 1: + +```yaml +openchoreoApi: + config: + security: + authorization: + bootstrap: + mappings: + - name: workload-publisher-binding + kind: ClusterAuthzRoleBinding + system: true + roleMappings: + - roleRef: + name: workload-publisher + kind: ClusterAuthzRole + entitlement: + claim: sub + value: "" + effect: allow +``` + +:::warning +The `workload-publisher` role and its binding are required for CI workflows to function. When overriding the `bootstrap.mappings` array, make sure to include this binding along with any other bindings you want to keep. See the [Authorization Configuration](../authorization.md#customizing-bootstrap-roles-and-bindings) guide for details. +::: + +## Verification + +After configuring, verify the setup: + +1. **Check that the secret exists:** + + ```bash + kubectl get secret workload-publisher-oauth-secret -n + ``` + +2. **Verify the ClusterWorkflowTemplate is updated:** + + ```bash + kubectl get clusterworkflowtemplate generate-workload -o yaml + ``` + +3. **Verify the authorization binding was created:** + + ```bash + kubectl get clusterauthzrolebindings | grep workload-publisher + ``` + +4. **Trigger a build** and check that the workflow step successfully obtains an OAuth token and creates/updates the Workload CR. + +## See Also + +- [Identity Provider Configuration](../identity-configuration.mdx) — Configure identity providers for OpenChoreo +- [Authorization Configuration](../authorization.md) — Configure roles, bindings, and subject types +- [Secret Management](../secret-management.mdx) — Manage secrets with External Secrets Operator +- [Workload Generation](./workload-generation.md) — How CI workflows create Workload CRs diff --git a/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workload-generation.md b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workload-generation.md new file mode 100644 index 00000000..13d087b2 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/platform-engineer-guide/workflows/workload-generation.md @@ -0,0 +1,154 @@ +--- +title: Workload Generation +description: How CI workflows create Workload CRs via the OpenChoreo API server +--- + +# Workload Generation + +When a CI workflow builds a container image, the next step is creating a Workload CR in the control plane. The ClusterWorkflowTemplate calls the OpenChoreo API server directly to create or update the Workload resource. + +## How It Works + +The workflow step handles workload creation end-to-end by calling the OpenChoreo API server: + +1. The CI workflow builds and publishes a container image +2. The workflow step generates a workload payload (using `occ workload create` to produce a local file, or by constructing the JSON directly) +3. The step obtains an OAuth access token via client credentials grant +4. The step calls `POST /api/v1/namespaces/{namespaceName}/workloads` to create the Workload +5. If the Workload already exists (HTTP 409), the step falls back to `PUT /api/v1/namespaces/{namespaceName}/workloads/{workloadName}` to update it +6. The API server creates or updates the Workload CR in the control plane +7. The step annotates the WorkflowRun with the workload CR and source origin, so the UI can display build details such as the container image and workload configuration + +## Workflow Step Details + +### Authentication + +The workflow step authenticates with the API server using OAuth 2.0 client credentials: + +```bash +TOKEN_RESPONSE=$(curl -s --fail-with-body \ + -X POST "${OAUTH_TOKEN_URL}" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}") + +ACCESS_TOKEN=$(echo "${TOKEN_RESPONSE}" | jq -r '.access_token') +``` + +The OAuth parameters (token URL, client ID, client secret) are provided as input parameters to the ClusterWorkflowTemplate step. + +By default, OpenChoreo ships with ThunderID as the identity provider and a pre-configured OAuth client (`openchoreo-workload-publisher-client`) for development and testing. If you are using an external identity provider, refer to the [Workload Publishing Credentials](./workflow-workload-configuration.mdx) operations guide for setup instructions. + +### Creating the Workload + +After obtaining the token, the step calls the API server to create the Workload: + +```bash +curl -s -X POST "${API_URL}/api/v1/namespaces/${NAMESPACE_NAME}/workloads" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + -d @workload-cr.json +``` + +If the Workload already exists (HTTP 409 Conflict), the step updates it instead: + +```bash +curl -s -X PUT "${API_URL}/api/v1/namespaces/${NAMESPACE_NAME}/workloads/${WORKLOAD_NAME}" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + -d @workload-cr.json +``` + +### Annotating the WorkflowRun + +After creating or updating the Workload, the step annotates the WorkflowRun with the workload details. The UI uses these annotations to display build output such as the container image and workload configuration. + +The step fetches the current WorkflowRun, adds the annotations, and updates it via `PUT`: + +```bash +# Get the current WorkflowRun +WF_RUN_RESPONSE=$(curl -s -w "\n%{http_code}" \ + -X GET "${API_URL}/api/v1/namespaces/${NAMESPACE_NAME}/workflowruns/${RUN_NAME}" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}") + +# Add annotations and update +curl -s -X PUT "${API_URL}/api/v1/namespaces/${NAMESPACE_NAME}/workflowruns/${RUN_NAME}" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + -d @workflowrun-updated.json +``` + +Two annotations are set on the WorkflowRun: + +| Annotation | Description | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `openchoreo.dev/workload` | The complete workload CR as a compact JSON string (contains the image, endpoints, configurations, etc.) | +| `openchoreo.dev/workload-from-source` | `"true"` if the workload was generated from a `workload.yaml` descriptor in the source repository, `"false"` if auto-generated with just the container image | + +### ClusterWorkflowTemplate Configuration + +The workflow template step accepts the following input parameters for API server and OAuth configuration: + +```yaml +# In the ClusterWorkflowTemplate +- name: generate-workload-cr + inputs: + parameters: + - name: image + - name: run-name + # OAuth configuration + - name: oauth-token-url + default: "http://host.k3d.internal:8080/oauth2/token" + - name: oauth-host-header + default: "thunder.openchoreo.localhost" + - name: oauth-client-id + default: "openchoreo-workload-publisher-client" + - name: oauth-client-secret + default: "openchoreo-workload-publisher-secret" + # API server configuration + - name: api-server-url + default: "http://host.k3d.internal:8080" + - name: api-server-host-header + default: "api.openchoreo.localhost" +``` + +## Workload Descriptor + +You can provide a workload descriptor YAML file in your source repository to define the full workload structure. The workflow step uses this descriptor when generating the workload payload that is sent to the API server. + +```yaml +# workload.yaml - place in your source repository +apiVersion: openchoreo.dev/v1alpha1 + +metadata: + name: reading-list-service + +endpoints: + - name: reading-list-api + port: 5000 + type: HTTP + schemaFile: openapi.yaml + +configurations: + env: + - name: LOG_LEVEL + value: info + - name: APP_ENV + value: production + files: + - name: app-config + mountPath: /etc/config/app.json + value: | + {"feature_flags": {"new_feature": true}} +``` + +- **With descriptor**: Full workload specification with endpoints, dependencies, and configurations +- **Without descriptor**: Basic workload with just the container image + +Using `occ workload create` is optional. You can use it inside the workflow step to read the descriptor and produce a Workload CR file, which is then converted to JSON and sent to the API server. Alternatively, you can skip the CLI and construct the JSON payload directly in the workflow step. + +## See Also + +- [CI Governance](./ci-governance.md) — CI workflow labels, governance, and configuration +- [Creating Workflows](./creating-workflows.mdx) — Full workflow creation guide +- [Workload API Reference](../../reference/api/application/workload.md) — Full Workload specification +- [Workload Publishing Credentials](./workflow-workload-configuration.mdx) — Configure workflow authentication for external identity providers diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/application/component.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/component.md new file mode 100644 index 00000000..001cbbab --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/component.md @@ -0,0 +1,181 @@ +--- +title: Component API Reference +description: Deployable unit of an application, referencing a ComponentType within a Project +--- + +# Component + +A Component represents a deployable unit of an application in OpenChoreo. It serves as the core abstraction that +references a platform-defined ComponentType (or ClusterComponentType) and optionally includes +workflow configuration when using OpenChoreo's CI system to build from source. Components are the primary building blocks +used to define applications within a Project. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Components are namespace-scoped resources and belong to a Project through the owner field. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: + namespace: # Namespace for grouping components +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| --------------- | --------------------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- | +| `owner` | [ComponentOwner](#componentowner) | Yes | - | Ownership information linking the component to a project | +| `componentType` | [ComponentTypeRef](#componenttyperef) | Yes | - | Reference to a ComponentType or ClusterComponentType | +| `autoDeploy` | boolean | No | `false` | Automatically deploy the component when created | +| `autoBuild` | boolean | No | - | Automatically trigger builds when code is pushed; requires webhook configuration in the Git provider | +| `parameters` | object | No | - | Parameter values merged from the ComponentType's parameter and environmentConfigs schema | +| `traits` | [[ComponentTrait](#componenttrait)] | No | [] | Traits to compose into this component; each trait can be instantiated multiple times | +| `workflow` | [ComponentWorkflowConfig](#componentworkflowconfig) | No | - | Workflow configuration for building the component; references a Workflow or ClusterWorkflow CR | + +### ComponentOwner + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ------- | ----------------------------------------------------- | +| `projectName` | string | Yes | - | Name of the project that owns this component (min: 1) | + +### ComponentTypeRef + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | --------------- | -------------------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `ComponentType` | Kind of the referenced resource: `ComponentType` (namespace-scoped) or `ClusterComponentType` (cluster-scoped) | +| `name` | string | Yes | - | Name in `{workloadType}/{componentTypeName}` format (e.g., `deployment/service`) | + +The `componentType` field references a platform-defined [ComponentType](../platform/componenttype.md) or [ClusterComponentType](../platform/clustercomponenttype.md) +using a structured object with `kind` and `name` fields. The `kind` defaults to `ComponentType` (namespace-scoped) but can be set +to `ClusterComponentType` for cluster-scoped types. + +### ComponentWorkflowConfig + +Defines the workflow used to build the component. The referenced Workflow must be listed in the `allowedWorkflows` of the ComponentType. + +| Field | Type | Required | Default | Description | +| ------------ | ------ | -------- | ----------------- | -------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `ClusterWorkflow` | Kind of the workflow resource: `Workflow` (namespace-scoped) or `ClusterWorkflow` (cluster-scoped) | +| `name` | string | Yes | - | Name of the Workflow or ClusterWorkflow CR to use | +| `parameters` | object | No | - | Developer-provided parameter values validated against the Workflow's schema | + +### ComponentTrait + +| Field | Type | Required | Default | Description | +| -------------- | ------ | -------- | ------- | ----------------------------------------------------------------------------------------- | +| `kind` | string | No | `Trait` | Kind of the trait resource: `Trait` (namespace-scoped) or `ClusterTrait` (cluster-scoped) | +| `name` | string | Yes | - | Name of the Trait resource to use (min: 1) | +| `instanceName` | string | Yes | - | Unique identifier for this trait instance within the component (min: 1) | +| `parameters` | object | No | - | Trait parameter values; schema is defined by the Trait resource | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ------------- | ------- | ------------------------------------------------------------------------ | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking component state | +| `latestRelease` | LatestRelease | - | Information about the latest ComponentRelease created for this component | + +#### LatestRelease + +| Field | Type | Description | +| ------------- | ------ | -------------------------------------------- | +| `name` | string | Name of the latest ComponentRelease resource | +| `releaseHash` | string | Hash of the ComponentRelease spec | + +#### Condition Types + +Common condition types for Component resources: + +- `Ready` - Indicates if the component is ready +- `Reconciled` - Indicates if the controller has successfully reconciled the component + +## Examples + +### Service Component with Workflow Build + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: customer-service + namespace: default +spec: + owner: + projectName: my-project + componentType: + kind: ComponentType + name: deployment/service + workflow: + name: docker + parameters: + dockerContext: . + dockerfilePath: ./Dockerfile +``` + +### WebApplication Component with Auto Deploy + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: frontend-app + namespace: default +spec: + owner: + projectName: my-project + componentType: + kind: ComponentType + name: deployment/web-app + autoDeploy: true + autoBuild: true + workflow: + kind: ClusterWorkflow + name: google-cloud-buildpacks +``` + +### Component with Traits + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: backend-service + namespace: default +spec: + owner: + projectName: my-project + componentType: + kind: ClusterComponentType + name: deployment/service + traits: + - kind: ClusterTrait + name: oauth2-proxy + instanceName: auth + parameters: + provider: github +``` + +## Annotations + +Components support the following annotations: + +| Annotation | Description | +| ----------------------------- | ------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the component | + +## Related Resources + +- [Project](./project.md) - Contains components +- [Workload](./workload.md) - Workload definitions associated with components +- [ComponentType](../platform/componenttype.md) - Platform-defined templates referenced by components +- [ComponentRelease](../runtime/componentrelease.md) - Immutable release snapshots for deployment diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/application/project.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/project.md new file mode 100644 index 00000000..5ed1aa3b --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/project.md @@ -0,0 +1,92 @@ +--- +title: Project API Reference +description: Logical boundary for organizing related components, services, and resources +--- + +# Project + +A Project represents a cloud-native application composed of multiple components in OpenChoreo. It serves as the +fundamental unit of isolation and provides a logical boundary for organizing related components, services, and +resources. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Projects are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Project +metadata: + name: + namespace: # Namespace for grouping projects +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `deploymentPipelineRef` | [DeploymentPipelineRef](#deploymentpipelineref) | Yes | - | Reference to the DeploymentPipeline that defines the promotion paths between environments for this project. Must reference an existing DeploymentPipeline in the same namespace | + +### DeploymentPipelineRef + +Reference to a DeploymentPipeline that defines the promotion paths between environments for this project. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | -------------------- | ---------------------------------------- | +| `kind` | string | No | `DeploymentPipeline` | Kind of the deployment pipeline resource | +| `name` | string | Yes | - | Name of the deployment pipeline resource | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------- | ------- | --------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the project state | + +#### Condition Types + +Common condition types for Project resources: + +- `Ready` - Indicates if the project is fully provisioned and ready +- `Reconciled` - Indicates if the controller has successfully reconciled the project +- `NamespaceProvisioned` - Indicates if project namespaces have been created in all environments + +## Examples + +### Basic Project + +A simple project referencing the default deployment pipeline: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Project +metadata: + name: internal-apps + namespace: default + annotations: + openchoreo.dev/display-name: Internal Applications + openchoreo.dev/description: This project contains components that are used by company's internal applications +spec: + deploymentPipelineRef: + name: default-deployment-pipeline +``` + +## Annotations + +Projects support the following annotations: + +| Annotation | Description | +| ----------------------------- | ----------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the project | + +## Related Resources + +- [Component](./component.md) - Deployable units within projects +- [DeploymentPipeline](../platform/deployment-pipeline.md) - Defines environment promotion paths diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/application/resource.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/resource.md new file mode 100644 index 00000000..73da30cb --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/resource.md @@ -0,0 +1,164 @@ +--- +title: Resource API Reference +description: Developer-declared dependency on managed infrastructure provisioned through a ResourceType +--- + +# Resource + +A Resource represents a developer-declared dependency on managed infrastructure (database, queue, cache, object store) provisioned through a [ResourceType](../platform/resourcetype.md) or [ClusterResourceType](../platform/clusterresourcetype.md) template. Resources are project-bound: each Resource belongs to exactly one Project, and components in that project consume its outputs through Workload `dependencies.resources[]`. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Resources are namespace-scoped resources and belong to a Project through the owner field. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: + namespace: +``` + +**Short names:** `res` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ------------ | ----------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------- | +| `owner` | [ResourceOwner](#resourceowner) | Yes | - | Ownership information linking the Resource to a project (immutable) | +| `type` | [ResourceTypeRef](#resourcetyperef) | Yes | - | Reference to a ResourceType or ClusterResourceType template (immutable) | +| `parameters` | object | No | - | Parameter values validated against the ResourceType's `parameters` schema; failures surface via conditions | + +:::note +Both `owner` and `type` are immutable after creation. To re-target a Resource to a different template, delete and recreate it. +::: + +### ResourceOwner + +| Field | Type | Required | Description | +| ------------- | ------ | -------- | ---------------------------------------------------- | +| `projectName` | string | Yes | Name of the project that owns this Resource (min: 1) | + +### ResourceTypeRef + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------ | +| `kind` | string | No | `ResourceType` | Kind of the referenced template: `ResourceType` (namespace-scoped) or `ClusterResourceType` (cluster-scoped) | +| `name` | string | Yes | - | Name of the ResourceType or ClusterResourceType (DNS-1123 label; min: 1) | + +Mirrors the [ComponentTypeRef](./component.md#componenttyperef) shape. The kind disambiguates a namespace-scoped ResourceType from a cluster-scoped ClusterResourceType with the same name. + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | ----------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking Resource state | +| `latestRelease` | [LatestResourceRelease](#latestresourcerelease) | - | Pointer to the most recent ResourceRelease cut from this Resource | + +#### LatestResourceRelease + +| Field | Type | Description | +| ------ | ------ | ------------------------------------------------------------------------------------------ | +| `name` | string | Name of the latest ResourceRelease resource (shape: `{resource}-{hash}`) | +| `hash` | string | Content hash covering `Resource.spec` + the referenced ResourceType's spec at release time | + +#### Condition Types + +Common condition types for Resource resources: + +- `Ready` — Indicates the Resource is in a healthy state, the referenced ResourceType has been resolved, and the latest ResourceRelease has been reconciled +- `Finalizing` — Surfaced during deletion while the two-phase finalizer waits for ResourceReleaseBindings and owned ResourceReleases to be cleaned up + +## Examples + +### Postgres Resource + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-postgres + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ClusterResourceType + name: postgres + parameters: + database: doclet +``` + +### NATS Resource (no parameters) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-nats + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ClusterResourceType + name: nats +``` + +### Resource Referencing a Namespace-Scoped ResourceType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: order-cache + namespace: default +spec: + owner: + projectName: order-service + type: + kind: ResourceType + name: valkey-cache + parameters: + version: "8" +``` + +## Usage + +A Resource is created by a developer (or by GitOps tooling on their behalf) and references a ResourceType that platform engineers have published. The Resource controller cuts a [ResourceRelease](../runtime/resourcerelease.md) when the hash of `Resource.spec` plus the referenced ResourceType's spec changes; release advance into environments happens through a [ResourceReleaseBinding](../platform/resourcereleasebinding.md) authored by a platform engineer or GitOps process. + +```bash +# Create the Resource +kubectl apply -f doclet-postgres.yaml + +# Inspect the cut release +kubectl get resource doclet-postgres -o jsonpath='{.status.latestRelease}' + +# Inspect the rendered DP-side state once a binding is Ready +kubectl get rrb -l openchoreo.dev/resource=doclet-postgres +``` + +## Annotations + +Resources support the following annotations: + +| Annotation | Description | +| ----------------------------- | ------------------------------------ | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the Resource | + +## Related Resources + +- [Project](./project.md) — Owns Resources alongside Components +- [Workload](./workload.md) — Declares resource dependencies through `dependencies.resources[]` +- [ResourceType](../platform/resourcetype.md) — Platform-defined template referenced by a Resource +- [ClusterResourceType](../platform/clusterresourcetype.md) — Cluster-scoped variant of ResourceType +- [ResourceRelease](../runtime/resourcerelease.md) — Immutable snapshot cut by the Resource controller +- [ResourceReleaseBinding](../platform/resourcereleasebinding.md) — Per-environment binding that deploys a release diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workflowrun.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workflowrun.md new file mode 100644 index 00000000..b3bf222d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workflowrun.md @@ -0,0 +1,261 @@ +--- +title: WorkflowRun API Reference +description: Single execution instance of a Workflow with specific parameter values +--- + +# WorkflowRun + +A WorkflowRun represents a single execution instance of a [Workflow](../platform/workflow.md) in OpenChoreo. While +Workflows define the template and parameter schema for what can be executed, WorkflowRuns represent actual executions +with specific parameter values. When created, the controller renders and executes the Argo Workflow in the workflow plane. + +:::note +WorkflowRuns currently support Argo Workflow-based workflows only. +::: + +:::warning Imperative Resource +WorkflowRun is an **imperative** resource — it triggers an action rather than declaring a desired state. Each time a +WorkflowRun is applied, it initiates a new execution. For this reason, do not include WorkflowRuns in GitOps +repositories. Instead, create them through Git webhooks, the UI, or direct `kubectl apply` commands. +::: + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +WorkflowRuns are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: + namespace: +``` + +**WorkflowRuns** should have labels to link the run to a component and project if it is running for a component: + +```yaml +metadata: + labels: + openchoreo.dev/component: + openchoreo.dev/project: +``` + +These labels are accessible in the Workflow's CEL expressions as `${metadata.labels['openchoreo.dev/component']}` and `${metadata.labels['openchoreo.dev/project']}`. + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | --------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------- | +| `workflow` | [WorkflowConfig](#workflowconfig) | Yes | - | Workflow configuration referencing the Workflow CR and providing parameter values | +| `ttlAfterCompletion` | string | No | - | Auto-delete duration after completion. Copied from the Workflow template. Pattern: `^(\d+d)?(\d+h)?(\d+m)?(\d+s)?$` | + +### WorkflowConfig + +| Field | Type | Required | Default | Description | +| ------------ | ------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `ClusterWorkflow` | Kind of the referenced workflow: `Workflow` (namespace-scoped) or `ClusterWorkflow` (cluster-scoped). Immutable after creation. | +| `name` | string | Yes | - | Name of the Workflow or ClusterWorkflow CR to use for this execution (min length: 1). Immutable after creation. | +| `parameters` | object | No | - | Developer-provided values conforming to the parameter schema defined in the Workflow or ClusterWorkflow CR | + +The `parameters` field contains nested configuration that matches the `parameters.openAPIV3Schema` structure defined in the +referenced Workflow or ClusterWorkflow. + +### Status Fields + +| Field | Type | Default | Description | +| -------------- | ----------------------------------------- | ------- | -------------------------------------------------------------------------- | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking execution state | +| `runReference` | [ResourceReference](#resourcereference) | - | Reference to the workflow execution resource in workflow plane | +| `resources` | [][ResourceReference](#resourcereference) | - | References to additional resources created in workflow plane (for cleanup) | +| `tasks` | [][WorkflowTask](#workflowtask) | - | Vendor-neutral step status list ordered by execution sequence | +| `startedAt` | Timestamp | - | When the workflow run started execution | +| `completedAt` | Timestamp | - | When the workflow run finished execution (used with TTL for auto-delete) | + +#### ResourceReference + +| Field | Type | Default | Description | +| ------------ | ------ | ------- | ---------------------------------------------------------------- | +| `apiVersion` | string | "" | API version of the resource (e.g., `v1`, `argoproj.io/v1alpha1`) | +| `kind` | string | "" | Kind of the resource (e.g., `Secret`, `Workflow`) | +| `name` | string | "" | Name of the resource in the workflow plane cluster | +| `namespace` | string | "" | Namespace of the resource in the workflow plane cluster | + +#### WorkflowTask + +Provides a vendor-neutral abstraction over workflow engine-specific steps (e.g., Argo Workflow nodes). + +| Field | Type | Default | Description | +| ------------- | --------- | ------- | -------------------------------------------------------------------------------- | +| `name` | string | "" | Name of the task/step | +| `phase` | string | "" | Execution phase: `Pending`, `Running`, `Succeeded`, `Failed`, `Skipped`, `Error` | +| `startedAt` | Timestamp | - | When the task started execution | +| `completedAt` | Timestamp | - | When the task finished execution | +| `message` | string | "" | Additional details, typically populated on failure or error | + +#### Condition Types + +- `WorkflowCompleted` - Workflow has completed (successfully or with failure) +- `WorkflowRunning` - Workflow is currently executing in the workflow plane +- `WorkflowSucceeded` - Workflow execution completed successfully +- `WorkflowFailed` - Workflow execution failed or errored + +## Examples + +### Docker Build WorkflowRun + +Since `kind` defaults to `ClusterWorkflow`, you only need to specify the name: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: docker-build-run-01 + namespace: default +spec: + workflow: + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/openchoreo/sample-workloads" + revision: + branch: "main" + appPath: "/service-go-greeter" + docker: + context: "/service-go-greeter" + filePath: "/service-go-greeter/Dockerfile" +``` + +### Component WorkflowRun (with labels) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: greeter-build-01 + namespace: default + labels: + openchoreo.dev/component: greeter-service + openchoreo.dev/project: default +spec: + workflow: + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/openchoreo/sample-workloads" + secretRef: "github-credentials" + revision: + branch: "main" + commit: "a1b2c3d4" + appPath: "/service-go-greeter" + docker: + context: "/service-go-greeter" + filePath: "/service-go-greeter/Dockerfile" +``` + +### WorkflowRun Referencing a Namespace-Scoped Workflow + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: github-stats-report-run-01 + namespace: default +spec: + workflow: + kind: Workflow + name: github-stats-report + parameters: + source: + org: "openchoreo" + repo: "openchoreo" + output: + format: "table" +``` + +### Minimal WorkflowRun Using Defaults + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowRun +metadata: + name: simple-run + namespace: default +spec: + workflow: + name: dockerfile-builder + parameters: + repository: + url: "https://github.com/myorg/hello-world" + # Uses default values for other parameters from Workflow schema +``` + +## Status Example + +After execution, a WorkflowRun status might look like: + +```yaml +status: + conditions: + - type: WorkflowCompleted + status: "True" + lastTransitionTime: "2024-01-15T10:30:00Z" + reason: WorkflowSucceeded + message: Workflow has completed successfully + observedGeneration: 1 + - type: WorkflowRunning + status: "False" + lastTransitionTime: "2024-01-15T10:29:30Z" + reason: WorkflowRunning + message: Argo Workflow running has completed + observedGeneration: 1 + - type: WorkflowSucceeded + status: "True" + lastTransitionTime: "2024-01-15T10:30:00Z" + reason: WorkflowSucceeded + message: Workflow completed successfully + observedGeneration: 1 + runReference: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + name: greeter-build-01 + namespace: workflows-default + resources: + - apiVersion: external-secrets.io/v1 + kind: ExternalSecret + name: greeter-build-01-git-secret + namespace: workflows-default + tasks: + - name: checkout-source + phase: Succeeded + startedAt: "2024-01-15T10:28:00Z" + completedAt: "2024-01-15T10:28:30Z" + - name: build-image + phase: Succeeded + startedAt: "2024-01-15T10:28:30Z" + completedAt: "2024-01-15T10:29:45Z" + - name: publish-image + phase: Succeeded + startedAt: "2024-01-15T10:29:45Z" + completedAt: "2024-01-15T10:30:00Z" + startedAt: "2024-01-15T10:28:00Z" + completedAt: "2024-01-15T10:30:00Z" +``` + +## Annotations + +| Annotation | Description | +| ----------------------------- | ---------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the workflow run | + +## Related Resources + +- [Workflow](../platform/workflow.md) - Template definitions for workflow execution +- [ClusterWorkflow](../platform/clusterworkflow.md) - Cluster-scoped workflow template definitions +- [Workflows Guide](../../../platform-engineer-guide/workflows/overview.md) - Guide for creating and using workflows diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workload.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workload.md new file mode 100644 index 00000000..6a712d4c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/application/workload.md @@ -0,0 +1,285 @@ +--- +title: Workload API Reference +description: Runtime specification for a Component, including containers, endpoints, and dependencies +--- + +# Workload + +A Workload defines the runtime specification for a Component in OpenChoreo, including container configuration, +network endpoints, and dependencies on other services. It represents the actual deployment characteristics of a +component, specifying the container to run, what ports to expose, and what dependencies to inject. Workloads are +created automatically by build processes or can be defined manually for pre-built images. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Workloads are namespace-scoped resources and belong to a Component through the owner field. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: + namespace: # Namespace for grouping workloads +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ------------------------------------------------ | -------- | ------- | --------------------------------------------------------------------- | +| `owner` | [WorkloadOwner](#workloadowner) | Yes | - | Ownership information linking the workload to a project and component | +| `container` | [Container](#container) | Yes | - | Container specification for the workload | +| `endpoints` | map[string][WorkloadEndpoint](#workloadendpoint) | No | {} | Network endpoints for port exposure keyed by endpoint name | +| `dependencies` | [WorkloadDependencies](#workloaddependencies) | No | - | Dependencies on other workload endpoints | + +### WorkloadOwner + +| Field | Type | Required | Default | Description | +| --------------- | ------ | -------- | ------- | ------------------------------------------------------ | +| `projectName` | string | Yes | - | Name of the project that owns this workload (min: 1) | +| `componentName` | string | Yes | - | Name of the component that owns this workload (min: 1) | + +### Container + +| Field | Type | Required | Default | Description | +| --------- | ------------------- | -------- | ------- | ---------------------------------------- | +| `image` | string | Yes | - | OCI image to run (digest or tag, min: 1) | +| `command` | []string | No | [] | Container entrypoint | +| `args` | []string | No | [] | Arguments for the entrypoint | +| `env` | [[EnvVar](#envvar)] | No | [] | Environment variables | +| `files` | [[File](#file)] | No | [] | File configurations and secrets | + +### EnvVar + +Exactly one of `value` or `valueFrom` must be set. + +| Field | Type | Required | Default | Description | +| ----------- | ----------------------------------- | -------- | ------- | ----------------------------------------------------------------- | +| `key` | string | Yes | - | Environment variable name | +| `value` | string | No | - | Literal value (mutually exclusive with `valueFrom`) | +| `valueFrom` | [EnvVarValueFrom](#envvarvaluefrom) | No | - | Reference to an external source (mutually exclusive with `value`) | + +### File + +Exactly one of `value` or `valueFrom` must be set. + +| Field | Type | Required | Default | Description | +| ----------- | ----------------------------------- | -------- | ------- | ----------------------------------------------------------------- | +| `key` | string | Yes | - | File name | +| `mountPath` | string | Yes | - | Path where the file should be mounted | +| `value` | string | No | - | Literal file content (mutually exclusive with `valueFrom`) | +| `valueFrom` | [EnvVarValueFrom](#envvarvaluefrom) | No | - | Reference to an external source (mutually exclusive with `value`) | + +### EnvVarValueFrom + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------- | -------- | ------- | ----------------------------------------- | +| `secretKeyRef` | [SecretKeyRef](#secretkeyref) | No | - | Reference to a key in a Kubernetes secret | + +### SecretKeyRef + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | --------------------- | +| `name` | string | Yes | - | Name of the secret | +| `key` | string | Yes | - | Key within the secret | + +### WorkloadEndpoint + +| Field | Type | Required | Default | Description | +| ------------- | ------------------------------------------- | -------- | ------- | --------------------------------------------------------------------- | +| `type` | [EndpointType](#endpointtype) | Yes | - | Protocol/technology of the endpoint | +| `port` | int32 | Yes | - | Port number exposed by the endpoint (1-65535) | +| `targetPort` | int32 | No | `port` | Target port on the container (1-65535), defaults to `port` if not set | +| `visibility` | [][EndpointVisibility](#endpointvisibility) | No | [] | Additional visibility scopes beyond the implicit `project` visibility | +| `displayName` | string | No | - | Human-readable name for the endpoint | +| `basePath` | string | No | - | Base path of the API exposed via the endpoint | +| `schema` | [Schema](#schema) | No | - | Optional API schema definition for the endpoint | + +**Visibility Behavior:** + +- Every endpoint automatically gets `project` visibility (accessible within the same project and environment) +- The `visibility` array adds **additional** scopes beyond the implicit project access +- Multiple visibility levels can be specified to create routes on different gateways + +### EndpointVisibility + +| Value | Description | +| ----------- | ------------------------------------------------------------------------------------ | +| `project` | Accessible only within the same project and environment (implicit for all endpoints) | +| `namespace` | Accessible across all projects in the same namespace and environment | +| `internal` | Accessible across all namespaces in the deployment (intranet) | +| `external` | Accessible from outside the deployment, including public internet | + +### EndpointType + +| Value | Description | +| ----------- | ----------------------------------- | +| `HTTP` | HTTP endpoint (including REST APIs) | +| `gRPC` | gRPC service endpoint | +| `GraphQL` | GraphQL API endpoint | +| `Websocket` | WebSocket endpoint | +| `TCP` | Raw TCP endpoint | +| `UDP` | UDP endpoint | + +### Schema + +| Field | Type | Required | Default | Description | +| --------- | ------ | -------- | ------- | ---------------------------------------------- | +| `type` | string | No | "" | Schema type (e.g., "openapi", "graphql", etc.) | +| `content` | string | No | "" | Schema content (API definition) | + +### WorkloadDependencies + +| Field | Type | Required | Default | Description | +| ----------- | ------------------------------------------- | -------- | ------- | ----------------------------- | +| `endpoints` | [[WorkloadConnection](#workloadconnection)] | No | [] | List of endpoint dependencies | + +### WorkloadConnection + +| Field | Type | Required | Default | Description | +| ------------- | ----------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------- | +| `project` | string | No | - | Name of the project that owns the target component | +| `component` | string | Yes | - | Name of the target component | +| `name` | string | Yes | - | Name of the endpoint on the target component | +| `visibility` | string | Yes | - | Visibility scope of the target endpoint (`project` or `namespace` only) | +| `envBindings` | [ConnectionEnvBindings](#connectionenvbindings) | Yes | - | Environment variable bindings for connection details | + +### ConnectionEnvBindings + +| Field | Type | Required | Default | Description | +| ---------- | ------ | -------- | ------- | --------------------------------------------------------------- | +| `address` | string | No | - | Environment variable name for the full address (host:port/path) | +| `host` | string | No | - | Environment variable name for the host | +| `port` | string | No | - | Environment variable name for the port | +| `basePath` | string | No | - | Environment variable name for the base path | + +## Examples + +### Basic Service Workload + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: customer-service-workload + namespace: default +spec: + owner: + projectName: my-project + componentName: customer-service + container: + image: myregistry/customer-service:v1.0.0 + env: + - key: LOG_LEVEL + value: info + endpoints: + http: + type: HTTP + port: 8080 + visibility: ["external"] + basePath: "/api/v1" + displayName: "Customer REST API" + metrics: + type: HTTP + port: 9090 + targetPort: 9090 +``` + +### Workload with Environment Variables and Files + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: secure-service-workload + namespace: default +spec: + owner: + projectName: my-project + componentName: secure-service + container: + image: myregistry/secure-service:v1.0.0 + env: + - key: LOG_LEVEL + value: info + - key: GIT_PAT + valueFrom: + secretKeyRef: + name: git-secrets + key: pat + files: + - key: ssl.pem + mountPath: /tmp + valueFrom: + secretKeyRef: + name: certificates + key: privateKey + - key: application.toml + mountPath: /tmp + value: | + schema_generation: + enable: true + endpoints: + api: + type: HTTP + port: 8080 + visibility: ["external"] + basePath: "/api" +``` + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workload +metadata: + name: order-service-workload + namespace: default +spec: + owner: + projectName: my-project + componentName: order-service + container: + image: myregistry/order-service:v2.1.0 + command: ["/app/server"] + args: ["--config", "/etc/config.yaml"] + endpoints: + api: + type: HTTP + port: 8080 + visibility: ["external"] + basePath: "/orders" + displayName: "Order Management API" + schema: + content: | + openapi: 3.0.0 + info: + title: Order API + version: 1.0.0 + dependencies: + endpoints: + - component: postgres-db + name: api + visibility: project + envBindings: + address: DATABASE_URL + host: DB_HOST + port: DB_PORT +``` + +## Annotations + +Workloads support the following annotations: + +| Annotation | Description | +| ----------------------------- | ------------------------------------ | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the workload | + +## Related Resources + +- [Component](./component.md) - Components that own workloads +- [ComponentRelease](../runtime/componentrelease.md) - Immutable release snapshots that include workload specs diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrole.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrole.md new file mode 100644 index 00000000..86426bb9 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrole.md @@ -0,0 +1,85 @@ +--- +title: AuthzRole API Reference +description: Namespace-scoped authorization role defining permitted actions within a namespace +--- + +# AuthzRole + +An AuthzRole defines a namespace-scoped authorization role containing a set of permitted actions. Namespace roles are scoped to a single namespace and can only be referenced by `AuthzRoleBinding` resources within the same namespace. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +AuthzRoles are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRole +metadata: + name: + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ------------- | -------- | -------- | ------- | ------------------------------------------------------------------------------------------ | +| `actions` | []string | Yes | - | List of actions this role permits. Supports wildcards (`*`, `component:*`). Minimum 1 item | +| `description` | string | No | "" | Human-readable description of the role's purpose | + +### Actions Format + +Actions follow the `resource:verb` format. Supported patterns: + +| Pattern | Meaning | +| ---------------- | ------------------------------- | +| `component:view` | A specific action | +| `component:*` | All actions for a resource type | +| `*` | All actions on all resources | + +## Examples + +### Developer Role + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRole +metadata: + name: developer + namespace: acme +spec: + actions: + - "component:*" + - "project:view" + - "workflow:view" + - "workload:view" + - "workload:create" + description: "Developer access for the acme namespace" +``` + +### Namespace Viewer + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRole +metadata: + name: namespace-viewer + namespace: acme +spec: + actions: + - "namespace:view" + - "project:view" + - "component:view" + description: "Read-only access within the acme namespace" +``` + +## Related Resources + +- [ClusterAuthzRole](./clusterauthzrole.md) - Cluster-scoped role +- [AuthzRoleBinding](./authzrolebinding.md) - Bind subjects to roles within a namespace +- [ClusterAuthzRoleBinding](./clusterauthzrolebinding.md) - Bind subjects to cluster roles with optional per-mapping scope diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrolebinding.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrolebinding.md new file mode 100644 index 00000000..e6f137f5 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/authzrolebinding.md @@ -0,0 +1,212 @@ +--- +title: AuthzRoleBinding API Reference +description: Binds a subject to namespace-scoped roles with optional project or component scope +--- + +# AuthzRoleBinding + +An AuthzRoleBinding connects a subject (identified by a JWT claim-value pair) to one or more roles within a namespace. Each role mapping can optionally narrow the binding's scope to a specific project or component within the resource hierarchy. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +AuthzRoleBindings are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ------------------------------------- | -------- | ------- | -------------------------------------------- | +| `entitlement` | [EntitlementClaim](#entitlementclaim) | Yes | - | Subject identification from JWT claims | +| `roleMappings` | [RoleMapping[]](#rolemapping) | Yes | - | List of role-scope pairs this binding grants | +| `effect` | string | No | `allow` | `allow` or `deny` | + +### EntitlementClaim + +| Field | Type | Required | Description | +| ------- | ------ | -------- | ----------------------------------------------- | +| `claim` | string | Yes | JWT claim name (e.g., `groups`, `sub`, `email`) | +| `value` | string | Yes | JWT claim value to match (e.g., `dev-team`) | + +### RoleMapping + +Each entry in the `roleMappings` array pairs a role reference with an optional scope and optional attribute-based conditions. + +| Field | Type | Required | Description | +| ------------ | ----------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | +| `roleRef` | [RoleRef](#roleref) | Yes | Reference to the role to bind | +| `scope` | [TargetScope](#targetscope) | No | Narrows the mapping to a specific project or component. Omit for namespace-wide | +| `conditions` | [AuthzCondition[]](#authzcondition) | No | Attribute-based restrictions on specific actions granted by the role. Omit for no restrictions | + +### RoleRef + +| Field | Type | Required | Description | +| ------ | ------ | -------- | -------------------------------------------------- | +| `kind` | string | Yes | `AuthzRole` (same namespace) or `ClusterAuthzRole` | +| `name` | string | Yes | Name of the role to bind | + +### TargetScope + +All fields are optional. Omitted fields mean "all" at that level. + +| Field | Type | Required | Description | +| ----------- | ------ | -------- | -------------------------------------------------- | +| `project` | string | No | Scope to a specific project within the namespace | +| `component` | string | No | Scope to a specific component (requires `project`) | + +:::important +`scope.component` requires `scope.project` to be set. This is enforced by a validation rule on the resource. +::: + +### AuthzCondition + +Each entry in `conditions` gates a set of actions in the role mapping on a CEL expression evaluated against attributes of the request. + +| Field | Type | Required | Description | +| ------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | string[] | Yes | Action patterns this condition applies to — the entry's expression is attached to each listed action. Supports exact matches and wildcards. | +| `expression` | string | Yes | A CEL expression that must evaluate to `true` for the action to be permitted by this role mapping. | + +Multiple entries on the same role mapping are combined with **OR** semantics — at least one entry whose `actions` cover the request action must evaluate to `true` for the action to be permitted. Entries whose `actions` do not match the request action do not contribute to the decision. + +For the full list of attributes available to expressions and the evaluation model, see [Conditions on Role Bindings](../../../platform-engineer-guide/authorization/conditions.md). + +## Examples + +### Namespace-Wide Developer Access + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: backend-team-dev-binding + namespace: acme +spec: + entitlement: + claim: groups + value: backend-team + roleMappings: + - roleRef: + kind: AuthzRole + name: developer + effect: allow +``` + +### Project-Scoped Access + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: backend-team-crm-binding + namespace: acme +spec: + entitlement: + claim: groups + value: backend-team + roleMappings: + - roleRef: + kind: AuthzRole + name: developer + scope: + project: crm + effect: allow +``` + +### Component-Scoped Access + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: api-team-gateway-binding + namespace: acme +spec: + entitlement: + claim: groups + value: api-team + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: viewer + scope: + project: crm + component: api-gateway + effect: allow +``` + +### Deny Access to a Specific Project + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: block-billing-access + namespace: acme +spec: + entitlement: + claim: groups + value: backend-team + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: viewer + scope: + project: billing + effect: deny +``` + +### Restrict Component Deployments to Non-Production Environments + +Use `conditions` on a role mapping to gate specific actions on request attributes. The binding below grants `developer` access to the `backend-team` group, but blocks release-binding mutations in production. See [Conditions](../../../platform-engineer-guide/authorization/conditions.md) for the full attribute model. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: AuthzRoleBinding +metadata: + name: backend-team-binding + namespace: acme +spec: + entitlement: + claim: groups + value: backend-team + roleMappings: + - roleRef: + kind: AuthzRole + name: developer + conditions: + - actions: + - releasebinding:create + - releasebinding:update + - releasebinding:delete + expression: 'resource.environment != "acme/prod"' + effect: allow +``` + +## Allow and Deny + +Both `ClusterAuthzRoleBinding` and `AuthzRoleBinding` carry an **effect** field: either `allow` or `deny`. When multiple bindings match a request, the system follows a **deny-overrides** strategy: + +- If **any** matching binding has effect `allow` **AND** **no** matching binding has effect `deny`: **ALLOW** +- If **any** matching binding has effect `deny`: **DENY** (deny always wins) +- If **no** bindings match: **DENY** (default deny) + +A single `deny` binding can override any number of `allow` bindings, making it straightforward to revoke specific permissions without restructuring the entire role hierarchy. + +## Related Resources + +- [AuthzRole](./authzrole.md) - Namespace-scoped role definition +- [ClusterAuthzRole](./clusterauthzrole.md) - Cluster-scoped role definition +- [ClusterAuthzRoleBinding](./clusterauthzrolebinding.md) - Cluster-scoped role binding diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrole.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrole.md new file mode 100644 index 00000000..b24723c7 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrole.md @@ -0,0 +1,81 @@ +--- +title: ClusterAuthzRole API Reference +description: Cluster-scoped authorization role available across all namespaces +--- + +# ClusterAuthzRole + +A ClusterAuthzRole defines a cluster-scoped authorization role containing a set of permitted actions. Cluster roles are available across all namespaces and can be referenced by both `ClusterAuthzRoleBinding` and `AuthzRoleBinding` resources. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterAuthzRoles are cluster-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRole +metadata: + name: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ------------- | -------- | -------- | ------- | ------------------------------------------------------------------------------------------ | +| `actions` | []string | Yes | - | List of actions this role permits. Supports wildcards (`*`, `component:*`). Minimum 1 item | +| `description` | string | No | "" | Human-readable description of the role's purpose | + +### Actions Format + +Actions follow the `resource:verb` format. Supported patterns: + +| Pattern | Meaning | +| ---------------- | ------------------------------- | +| `component:view` | A specific action | +| `component:*` | All actions for a resource type | +| `*` | All actions on all resources | + +## Examples + +### Platform Admin (Full Access) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRole +metadata: + name: platform-admin +spec: + actions: + - "*" + description: "Platform administrator with full access to all resources" +``` + +### Read-Only Viewer + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRole +metadata: + name: viewer +spec: + actions: + - "namespace:view" + - "project:view" + - "component:view" + - "environment:view" + - "workflow:view" + - "dataplane:view" + description: "Read-only access to core resources" +``` + +## Related Resources + +- [AuthzRole](./authzrole.md) - Namespace-scoped role +- [ClusterAuthzRoleBinding](./clusterauthzrolebinding.md) - Bind subjects to cluster roles with optional per-mapping scope +- [AuthzRoleBinding](./authzrolebinding.md) - Bind subjects to roles within a namespace diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrolebinding.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrolebinding.md new file mode 100644 index 00000000..a2c7ffa4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterauthzrolebinding.md @@ -0,0 +1,192 @@ +--- +title: ClusterAuthzRoleBinding API Reference +description: Binds a subject to ClusterAuthzRoles with optional namespace or resource scope +--- + +# ClusterAuthzRoleBinding + +A ClusterAuthzRoleBinding connects a subject (identified by a JWT claim-value pair) to one or more `ClusterAuthzRole` resources, granting or denying the roles' permissions. Each role mapping can optionally be scoped to a specific namespace, project, or component within the resource hierarchy. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterAuthzRoleBindings are cluster-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ------------------------------------------- | -------- | ------- | ------------------------------------------------ | +| `entitlement` | [EntitlementClaim](#entitlementclaim) | Yes | - | Subject identification from JWT claims | +| `roleMappings` | [ClusterRoleMapping[]](#clusterrolemapping) | Yes | - | List of role-scope pairs this binding applies to | +| `effect` | string | No | `allow` | `allow` or `deny` | + +### EntitlementClaim + +| Field | Type | Required | Description | +| ------- | ------ | -------- | --------------------------------------------------- | +| `claim` | string | Yes | JWT claim name (e.g., `groups`, `sub`, `email`) | +| `value` | string | Yes | JWT claim value to match (e.g., `platformEngineer`) | + +### ClusterRoleMapping + +Each entry in the `roleMappings` array pairs a role reference with an optional scope and optional attribute-based conditions. + +| Field | Type | Required | Description | +| ------------ | ----------------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | +| `roleRef` | [RoleRef](#roleref) | Yes | Reference to the cluster role to bind | +| `scope` | [ClusterTargetScope](#clustertargetscope) | No | Narrows the mapping to a specific namespace, project, or component. Omit for cluster-wide | +| `conditions` | [AuthzCondition[]](#authzcondition) | No | Attribute-based restrictions on specific actions granted by the role. Omit for no restrictions | + +### RoleRef + +| Field | Type | Required | Description | +| ------ | ------ | -------- | -------------------------------------- | +| `kind` | string | Yes | Must be `ClusterAuthzRole` | +| `name` | string | Yes | Name of the `ClusterAuthzRole` to bind | + +### ClusterTargetScope + +All fields are optional. Omitted fields mean "all" at that level. + +| Field | Type | Required | Description | +| ----------- | ------ | -------- | ------------------------------------------------------------------ | +| `namespace` | string | No | Scope to a specific namespace | +| `project` | string | No | Scope to a specific project (requires `namespace`) | +| `component` | string | No | Scope to a specific component (requires `namespace` and `project`) | + +:::important + +- `roleMappings[].roleRef.kind` must be `ClusterAuthzRole`. ClusterAuthzRoleBindings cannot reference namespace-scoped `AuthzRole` resources. This is enforced by a validation rule on the resource. +- `scope.project` requires `scope.namespace`, and `scope.component` requires `scope.project`. + ::: + +### AuthzCondition + +Each entry in `conditions` gates a set of actions in the role mapping on a CEL expression evaluated against attributes of the request. + +| Field | Type | Required | Description | +| ------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | string[] | Yes | Action patterns this condition applies to — the entry's expression is attached to each listed action. Supports exact matches and wildcards. | +| `expression` | string | Yes | A CEL expression that must evaluate to `true` for the action to be permitted by this role mapping. | + +Multiple entries on the same role mapping are combined with **OR** semantics — at least one entry whose `actions` cover the request action must evaluate to `true` for the action to be permitted. Entries whose `actions` do not match the request action do not contribute to the decision. + +For the full list of attributes available to expressions and the evaluation model, see [Conditions](../../../platform-engineer-guide/authorization/conditions.md). + +## Examples + +### Grant Admin Access Cluster-Wide + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: platform-admins-binding +spec: + entitlement: + claim: groups + value: platformEngineer + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: platform-admin + effect: allow +``` + +### Grant Viewer Access to a Service Account + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: backstage-reader-binding +spec: + entitlement: + claim: sub + value: openchoreo-backstage-client + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: viewer + effect: allow +``` + +### Namespace-Scoped Admin with Cluster-Wide Reader + +Multiple role mappings can be combined in a single binding, each with an independent scope: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: acme-admins-binding +spec: + entitlement: + claim: groups + value: acme-admins + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: admin + scope: + namespace: acme + - roleRef: + kind: ClusterAuthzRole + name: cluster-reader + effect: allow +``` + +In this example, `acme-admins` gets full `admin` access scoped to the `acme` namespace and cluster-wide read-only visibility into cluster-level resources — all in a single CR. + +### Restrict Observability Reads to Lower Environments + +Use `conditions` on a role mapping to gate specific actions on request attributes. The binding below grants the `dashboard-readonly` service account `observability-reader` access cluster-wide, but limits log, metric reads to `dev` and `staging`. See [Conditions](../../../platform-engineer-guide/authorization/conditions.md) for the full attribute model. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterAuthzRoleBinding +metadata: + name: lower-env-observability-binding +spec: + entitlement: + claim: sub + value: dashboard-readonly + roleMappings: + - roleRef: + kind: ClusterAuthzRole + name: observability-reader + conditions: + - actions: + - logs:view + - metrics:view + expression: 'resource.environment in ["acme/dev", "acme/staging"]' + effect: allow +``` + +## Allow and Deny + +Both `ClusterAuthzRoleBinding` and `AuthzRoleBinding` carry an **effect** field: either `allow` or `deny`. When multiple bindings match a request, the system follows a **deny-overrides** strategy: + +- If **any** matching binding has effect `allow` **AND** **no** matching binding has effect `deny`: **ALLOW** +- If **any** matching binding has effect `deny`: **DENY** (deny always wins) +- If **no** bindings match: **DENY** (default deny) + +A single `deny` binding can override any number of `allow` bindings, making it straightforward to revoke specific permissions without restructuring the entire role hierarchy. + +## Related Resources + +- [ClusterAuthzRole](./clusterauthzrole.md) - Cluster-scoped role definition +- [AuthzRoleBinding](./authzrolebinding.md) - Namespace-scoped role binding with optional target scope +- [AuthzRole](./authzrole.md) - Namespace-scoped role definition diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustercomponenttype.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustercomponenttype.md new file mode 100644 index 00000000..00e6700f --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustercomponenttype.md @@ -0,0 +1,427 @@ +--- +title: ClusterComponentType API Reference +description: Cluster-scoped deployment template reusable across all namespaces +--- + +# ClusterComponentType + +A ClusterComponentType is a cluster-scoped variant of [ComponentType](./componenttype.md) that defines reusable +deployment templates available across all namespaces. This enables platform engineers to define shared component types +once and reference them from Components in any namespace, eliminating duplication. + +ClusterComponentTypes share the same spec structure as ComponentTypes with two key constraints: because +ClusterComponentTypes are cluster-scoped, they can only reference **ClusterTraits** (not namespace-scoped Traits) +in their `traits` and `allowedTraits` fields, and can only reference **ClusterWorkflows** (not namespace-scoped +Workflows) in their `allowedWorkflows` field. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterComponentTypes are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterComponentType +metadata: + name: +``` + +:::note +ClusterComponentType manifests must **not** include `metadata.namespace`. If you are copying from a namespace-scoped +ComponentType example, remove the `namespace` field. +::: + +**Short names:** `cct`, `ccts` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | --------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------ | +| `workloadType` | string | Yes | - | Primary workload type: `deployment`, `statefulset`, `cronjob`, `job`, `proxy` | +| `allowedWorkflows` | [[ClusterWorkflowRef](#clusterworkflowref)] | No | [] | ClusterWorkflow references developers can use for building this component type; if empty, no workflows are allowed | +| `parameters` | [SchemaSection](#schemasection) | No | - | Configurable parameters schema for components of this type | +| `environmentConfigs` | [SchemaSection](#schemasection) | No | - | Environment-specific configuration schema for components of this type | +| `traits` | [[ClusterComponentTypeTrait](#clustercomponenttypetrait)] | No | [] | Pre-configured ClusterTrait instances automatically applied to all Components of this type | +| `allowedTraits` | [[ClusterTraitRef](#clustertraitref)] | No | [] | ClusterTraits that developers can attach to components of this type | +| `validations` | [[ValidationRule](#validationrule)] | No | [] | CEL-based rules evaluated during rendering; all must pass for rendering to proceed | +| `resources` | [[ResourceTemplate](#resourcetemplate)] | Yes | - | Templates for generating Kubernetes resources | + +:::note +The `workloadType` field is immutable after creation and determines the primary resource type for components of this +type. For non-proxy workload types, one resource template must have an `id` matching the `workloadType`. +::: + +### ClusterWorkflowRef + +Specifies a ClusterWorkflow that developers can use with components of this type. Because ClusterComponentType is +cluster-scoped, only ClusterWorkflow references are allowed (not namespace-scoped Workflows). + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ----------------- | ------------------------------------ | +| `kind` | string | No | `ClusterWorkflow` | Must be `ClusterWorkflow` | +| `name` | string | Yes | - | Name of the ClusterWorkflow resource | + +**Example:** + +```yaml +allowedWorkflows: + - kind: ClusterWorkflow + name: docker + - kind: ClusterWorkflow + name: google-cloud-buildpacks +``` + +### ClusterComponentTypeTrait + +Represents a pre-configured trait instance embedded in a ClusterComponentType. Only ClusterTrait references are +allowed since ClusterComponentType is cluster-scoped. + +| Field | Type | Required | Default | Description | +| -------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `kind` | string | No | `ClusterTrait` | Must be `ClusterTrait` | +| `name` | string | Yes | - | Name of the ClusterTrait | +| `instanceName` | string | Yes | - | Unique instance name within the component type | +| `parameters` | object | No | - | Trait parameter values (can use CEL expressions referencing the ComponentType schema, e.g., `${parameters.storage.mountPath}`) | +| `environmentConfigs` | object | No | - | Environment-specific configuration values for the trait | + +### ClusterTraitRef + +Specifies a ClusterTrait that developers can attach to components of this type. Unlike the namespace-scoped +[TraitRef](./componenttype.md#traitref), only ClusterTrait references are allowed. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | -------------- | ------------------------ | +| `kind` | string | Yes | `ClusterTrait` | Must be `ClusterTrait` | +| `name` | string | Yes | - | Name of the ClusterTrait | + +### SchemaSection + +Defines a schema section used for `parameters` and `environmentConfigs` fields using standard JSON Schema. + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | ------------------------------------------ | +| `openAPIV3Schema` | object | Yes | - | Standard OpenAPI V3 JSON Schema definition | + +**Example:** + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + imagePullPolicy: + type: string + default: IfNotPresent + port: + type: integer + default: 80 + +environmentConfigs: + openAPIV3Schema: + type: object + properties: + cpu: + type: string + default: 100m + memory: + type: string + default: 256Mi +``` + +### ValidationRule + +Defines a CEL-based validation rule evaluated during rendering. All rules must evaluate to true for rendering to +proceed. + +| Field | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------------- | +| `rule` | string | Yes | CEL expression wrapped in `${...}` that must evaluate to true | +| `message` | string | Yes | Error message shown when the rule evaluates to false | + +**Example:** + +```yaml +validations: + - rule: ${parameters.replicas >= 1} + message: "replicas must be at least 1" + - rule: ${parameters.port > 0 && parameters.port <= 65535} + message: "port must be between 1 and 65535" +``` + +### ResourceTemplate + +Defines a template for generating Kubernetes resources with CEL expressions for dynamic values. + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ----------- | --------------------------------------------------------------------- | +| `id` | string | Yes | - | Unique identifier (must match `workloadType` for primary) | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `includeWhen` | string | No | - | CEL expression determining if resource should be created | +| `forEach` | string | No | - | CEL expression for generating multiple resources from list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if `forEach` is set) | +| `template` | object | Yes | - | Kubernetes resource template with CEL expressions | + +#### CEL Expression Syntax + +Templates use CEL expressions enclosed in `${...}` that have access to context variables. Refer to the +[ComponentType CEL Expression Syntax](./componenttype.md#cel-expression-syntax) for the full list of available +context variables (`metadata`, `parameters`, `environmentConfigs`, `workload`, `configurations`, `dataplane`) and +[helper functions](./componenttype.md#helper-functions). + +## Examples + +### Basic Deployment ClusterComponentType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterComponentType +metadata: + name: service +spec: + workloadType: deployment + + parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + port: + type: integer + default: 80 + + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + replicas: ${parameters.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${metadata.podSelectors} + spec: + containers: + - name: main + image: ${workload.container.image} + ports: + - containerPort: ${parameters.port} +``` + +### ClusterComponentType with Embedded Traits and Validations + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterComponentType +metadata: + name: web-service +spec: + workloadType: deployment + + parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + minimum: 1 + port: + type: integer + default: 8080 + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + cpu: + type: string + default: 100m + memory: + type: string + default: 256Mi + + validations: + - rule: ${parameters.replicas >= 1} + message: "replicas must be at least 1" + + # Pre-configured traits automatically applied to all components + traits: + - kind: ClusterTrait + name: resource-limits + instanceName: default-limits + environmentConfigs: + cpuLimit: "${environmentConfigs.cpu}" + memoryLimit: "${environmentConfigs.memory}" + + # Additional traits developers can attach + allowedTraits: + - kind: ClusterTrait + name: persistent-volume + + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + replicas: ${parameters.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${metadata.podSelectors} + spec: + containers: + - name: main + image: ${workload.container.image} + ports: + - containerPort: ${parameters.port} + + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.componentName} + namespace: ${metadata.namespace} + spec: + selector: ${metadata.podSelectors} + ports: + - port: 80 + targetPort: ${parameters.port} + + - id: httproute-external + forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility && ep.type in ["HTTP", "GraphQL", "Websocket"]) ? [name] : []).flatten()}' + var: endpoint + template: + apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: ${oc_generate_name(metadata.componentName, endpoint)} + namespace: ${metadata.namespace} + labels: '${oc_merge(metadata.labels, {"openchoreo.dev/endpoint-name": endpoint, "openchoreo.dev/endpoint-visibility": "external"})}' + spec: + parentRefs: + - name: ${gateway.ingress.external.name} + namespace: ${gateway.ingress.external.namespace} + hostnames: | + ${[gateway.ingress.external.?http, gateway.ingress.external.?https] + .filter(g, g.hasValue()).map(g, g.value().host).distinct() + .map(h, oc_dns_label(endpoint, metadata.componentName, metadata.environmentName, metadata.componentNamespace) + "." + h)} + rules: + - matches: + - path: + type: PathPrefix + value: /${metadata.componentName}-${endpoint} + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("") != "" ? workload.endpoints[endpoint].?basePath.orValue("") : "/"}' + backendRefs: + - name: ${metadata.componentName} + port: ${workload.endpoints[endpoint].port} +``` + +### Scheduled Task ClusterComponentType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterComponentType +metadata: + name: scheduled-task +spec: + workloadType: cronjob + + parameters: + openAPIV3Schema: + type: object + properties: + schedule: + type: string + concurrencyPolicy: + type: string + default: Forbid + enum: + - Allow + - Forbid + - Replace + + resources: + - id: cronjob + template: + apiVersion: batch/v1 + kind: CronJob + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + schedule: ${parameters.schedule} + concurrencyPolicy: ${parameters.concurrencyPolicy} + jobTemplate: + spec: + template: + spec: + containers: + - name: main + image: ${workload.container.image} + restartPolicy: OnFailure +``` + +## Usage + +Components reference a ClusterComponentType using `spec.componentType` with `kind: ClusterComponentType`: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service + namespace: default +spec: + componentType: + kind: ClusterComponentType + name: deployment/service # format: workloadType/name + parameters: + replicas: 3 + port: 8080 +``` + +## Best Practices + +1. **Use for shared patterns**: Define ClusterComponentTypes for deployment patterns used across multiple namespaces; use namespace-scoped ComponentTypes for namespace-specific patterns +2. **Naming convention**: Use descriptive names like `service`, `web-application`, `scheduled-task` +3. **Trait restrictions**: Remember that ClusterComponentTypes can only reference ClusterTraits, not namespace-scoped Traits +4. **Parameter design**: Keep parameters focused and provide sensible defaults +5. **Validations**: Add validation rules for parameters that have constraints (e.g., minimum replicas, valid port ranges) +6. **Testing**: Validate ClusterComponentTypes with sample Components before platform-wide deployment + +## Related Resources + +- [ComponentType](./componenttype.md) - Namespace-scoped variant of ClusterComponentType +- [ClusterWorkflow](./clusterworkflow.md) - Cluster-scoped workflows that can be referenced by ClusterComponentTypes +- [ClusterTrait](./clustertrait.md) - Cluster-scoped traits that can be referenced by ClusterComponentTypes +- [Configuration Helpers](../../cel/helper-functions.md) - Configuration helper functions reference +- [Component](../application/component.md) - Uses ComponentTypes or ClusterComponentTypes for deployment +- [ReleaseBinding](releasebinding.md) - Binds a ComponentRelease to an environment with parameter overrides +- [Trait](trait.md) - Namespace-scoped traits (cannot be used with ClusterComponentTypes) diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterdataplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterdataplane.md new file mode 100644 index 00000000..8045b401 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterdataplane.md @@ -0,0 +1,255 @@ +--- +title: ClusterDataPlane API Reference +description: Cluster-scoped Kubernetes data plane shared across namespaces to deploy workloads +--- + +# ClusterDataPlane + +A ClusterDataPlane is a cluster-scoped variant of [DataPlane](./dataplane.md) that represents a Kubernetes cluster where application workloads are deployed. Unlike the namespace-scoped DataPlane, a ClusterDataPlane is a cluster-scoped resource, making it suitable for shared infrastructure scenarios where multiple teams or organizations use the same underlying cluster. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the downstream cluster through a WebSocket agent running in the ClusterDataPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterDataPlanes are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterDataPlane +metadata: + name: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | +| `planeID` | string | No | CR name | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `gateway` | [GatewaySpec](#gatewayspec) | Yes | - | API gateway configuration for this ClusterDataPlane | +| `secretStoreRef` | [SecretStoreRef](#secretstoreref) | No | - | Reference to External Secrets Operator ClusterSecretStore in the ClusterDataPlane | +| `observabilityPlaneRef` | [ObservabilityPlaneRef](#observabilityplaneref) | No | - | Reference to a ClusterObservabilityPlane resource for monitoring and logging | + +### PlaneID + +The `planeID` identifies the logical plane this ClusterDataPlane CR connects to. Multiple ClusterDataPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"prod-cluster"`, `"shared-dataplane"`, `"us-east-1"` + +:::important PlaneID Consistency +The `planeID` in the ClusterDataPlane CR must match the `clusterAgent.planeId` Helm value configured during data plane installation. If not specified, it defaults to the CR name for backwards compatibility. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the downstream cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### GatewaySpec + +Gateway configuration for the ClusterDataPlane. + +| Field | Type | Required | Default | Description | +| --------- | ----------------------------------------- | -------- | ------- | ----------------------------- | +| `ingress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Ingress gateway configuration | +| `egress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Egress gateway configuration | + +### GatewayNetworkSpec + +Network-level gateway configuration for ingress or egress. + +| Field | Type | Required | Default | Description | +| ---------- | ------------------------------------------- | -------- | ------- | --------------------------------------- | +| `external` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | External gateway endpoint configuration | +| `internal` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | Internal gateway endpoint configuration | + +### GatewayEndpointSpec + +Configuration for a specific gateway endpoint. + +| Field | Type | Required | Default | Description | +| ----------- | ------------------------------------------- | -------- | ------- | -------------------------------------------- | +| `name` | string | Yes | - | Name of the Kubernetes Gateway resource | +| `namespace` | string | Yes | - | Namespace of the Kubernetes Gateway resource | +| `http` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTP listener configuration | +| `https` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTPS listener configuration | +| `tls` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | TLS listener configuration | + +### GatewayListenerSpec + +Configuration for a gateway listener. + +| Field | Type | Required | Default | Description | +| -------------- | ------- | -------- | ------- | ----------------------------------- | +| `listenerName` | string | No | - | Name of the listener on the Gateway | +| `port` | integer | Yes | - | Port number for the listener | +| `host` | string | Yes | - | Hostname for the listener | + +### SecretStoreRef + +Reference to an External Secrets Operator ClusterSecretStore. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ------------------------------------------------------ | +| `name` | string | Yes | - | Name of the ClusterSecretStore in the ClusterDataPlane | + +### ObservabilityPlaneRef + +Reference to a ClusterObservabilityPlane for monitoring and logging. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | --------------------------- | ------------------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `ClusterObservabilityPlane` | Must be `ClusterObservabilityPlane`. ClusterDataPlane can only reference cluster-scoped observability planes. | +| `name` | string | Yes | - | Name of the ClusterObservabilityPlane resource | + +:::note Resolution Behavior + +- ClusterDataPlane can **only** reference a `ClusterObservabilityPlane` (not a namespace-scoped `ObservabilityPlane`). This is enforced by API validation. +- If `observabilityPlaneRef` is omitted, the controller attempts to find a ClusterObservabilityPlane named "default". If no default exists, observability is not configured. +- If the referenced ClusterObservabilityPlane is not found, the controller returns an error and the ClusterDataPlane will not become ready. + ::: + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ------- | --------------------------------------------------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No\* | - | Namespace of the secret (required for cluster-scoped resources) | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | ------------------------------------------------------------------ | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the ClusterDataPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +#### Condition Types + +Common condition types for ClusterDataPlane resources: + +- `Ready` - Indicates if the ClusterDataPlane is ready to accept workloads +- `Connected` - Indicates if connection to the target cluster is established +- `GatewayProvisioned` - Indicates if the gateway has been configured + +## Examples + +### Basic ClusterDataPlane Configuration + +This example shows a minimal ClusterDataPlane configuration. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterDataPlane +metadata: + name: shared-dataplane +spec: + planeID: "shared-cluster" + clusterAgent: + clientCA: + secretKeyRef: + name: cluster-agent-ca + namespace: openchoreo-system + key: ca.crt + gateway: + ingress: + external: + name: default-gateway + namespace: openchoreo-system + http: + port: 80 + host: api.example.com + https: + port: 443 + host: api.example.com + secretStoreRef: + name: vault-backend +``` + +### ClusterDataPlane with Observability + +This example shows a ClusterDataPlane linked to a ClusterObservabilityPlane for monitoring and logging. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterDataPlane +metadata: + name: production-dataplane +spec: + planeID: "prod-cluster" + clusterAgent: + clientCA: + secretKeyRef: + name: cluster-agent-ca + namespace: openchoreo-system + key: ca.crt + gateway: + ingress: + external: + name: default-gateway + namespace: openchoreo-system + http: + port: 80 + host: api.prod.example.com + https: + port: 443 + host: api.prod.example.com + secretStoreRef: + name: default + observabilityPlaneRef: + kind: ClusterObservabilityPlane + name: production-observability +``` + +## Annotations + +ClusterDataPlanes support the following annotations: + +| Annotation | Description | +| ----------------------------- | -------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the ClusterDataPlane | + +## Related Resources + +- [DataPlane](./dataplane.md) - Namespace-scoped variant of ClusterDataPlane +- [Environment](./environment.md) - Runtime environments deployed on DataPlanes or ClusterDataPlanes +- [ClusterWorkflowPlane](./clusterworkflowplane.md) - Cluster-scoped workflow plane configuration +- [ClusterObservabilityPlane](./clusterobservabilityplane.md) - Cluster-scoped observability plane +- [Project](../application/project.md) - Applications deployed to DataPlanes diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterobservabilityplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterobservabilityplane.md new file mode 100644 index 00000000..5e6db4ce --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterobservabilityplane.md @@ -0,0 +1,234 @@ +--- +title: ClusterObservabilityPlane API Reference +description: Cluster-scoped observability plane shared across namespaces for collecting metrics, logs, and traces +--- + +# ClusterObservabilityPlane + +A ClusterObservabilityPlane is a cluster-scoped variant of [ObservabilityPlane](./observabilityplane.md) that represents the infrastructure layer responsible for collecting, storing, and analyzing observability data (metrics, logs, and traces) from OpenChoreo workloads. Unlike the namespace-scoped ObservabilityPlane, a ClusterObservabilityPlane is a cluster-scoped resource, making it suitable for shared monitoring infrastructure. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the observability cluster through a WebSocket agent running in the ClusterObservabilityPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterObservabilityPlanes are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterObservabilityPlane +metadata: + name: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | +| `planeID` | string | Yes | - | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `observerURL` | string | Yes | - | Base URL of the Observer API in the observability plane cluster | +| `rcaAgentURL` | string | No | - | Base URL of the optional SRE Agent API in the observability plane cluster | + +### PlaneID + +The `planeID` identifies the logical plane this ClusterObservabilityPlane CR connects to. Multiple ClusterObservabilityPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"shared-obs"`, `"monitoring-cluster"`, `"eu-central-1"` + +:::important PlaneID Consistency +The `planeID` in the ClusterObservabilityPlane CR must match the `clusterAgent.planeId` Helm value configured during observability plane installation. If not specified, it defaults to the CR name for backwards compatibility. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the observability cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### ObserverURL + +The base URL of the Observer API service running in the observability plane cluster. This API is used by the control plane to query logs, metrics, and traces. + +**Format:** `http://observer.:` + +**Example:** `http://observer.openchoreo.localhost:11080` + +### RCAAgentURL + +The base URL of the optional SRE Agent API service running in the observability plane cluster. When set, external clients can call this endpoint to visualize AI-powered root cause analysis for fired alerts and interact with the SRE Agent with a chat interface. + +**Format:** `http://rca-agent.:` + +**Example:** `http://rca-agent.openchoreo.localhost:11080` + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ------- | --------------------------------------------------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No\* | - | Namespace of the secret (required for cluster-scoped resources) | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | --------------------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the ClusterObservabilityPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +## Examples + +### Basic ClusterObservabilityPlane Configuration + +This example shows a minimal ClusterObservabilityPlane configuration. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterObservabilityPlane +metadata: + name: production-observability +spec: + planeID: "prod-monitoring" + clusterAgent: + clientCA: + secretKeyRef: + name: observability-agent-ca + namespace: openchoreo-system + key: ca.crt + observerURL: http://observer.openchoreo.localhost:11080 +``` + +### ClusterObservabilityPlane with Inline CA Certificate + +This example uses an inline CA certificate (suitable for development/testing). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterObservabilityPlane +metadata: + name: dev-observability +spec: + planeID: "dev-monitoring" + clusterAgent: + clientCA: + value: | + -----BEGIN CERTIFICATE----- + MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKuoMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + ... (certificate content) ... + -----END CERTIFICATE----- + observerURL: http://observer.openchoreo.localhost:11080 +``` + +## Linking Planes to ClusterObservabilityPlane + +Once a ClusterObservabilityPlane is created, you can link DataPlanes, ClusterDataPlanes, WorkflowPlanes, and ClusterWorkflowPlanes to it for centralized monitoring and logging. + +### Linking a DataPlane + +```bash +kubectl patch dataplane -n --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch dataplane production-dataplane -n my-org --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":"production-observability"}}}' +``` + +### Linking a ClusterDataPlane + +```bash +kubectl patch clusterdataplane --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch clusterdataplane shared-dataplane --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":"production-observability"}}}' +``` + +### Linking a WorkflowPlane + +```bash +kubectl patch workflowplane -n --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch workflowplane production-workflowplane -n my-org --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":"production-observability"}}}' +``` + +### Linking a ClusterWorkflowPlane + +```bash +kubectl patch clusterworkflowplane --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch clusterworkflowplane shared-workflowplane --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ClusterObservabilityPlane","name":"production-observability"}}}' +``` + +## Annotations + +ClusterObservabilityPlanes support the following annotations: + +| Annotation | Description | +| ----------------------------- | ----------------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the ClusterObservabilityPlane | + +## Related Resources + +- [ObservabilityPlane](./observabilityplane.md) - Namespace-scoped variant of ClusterObservabilityPlane +- [DataPlane](./dataplane.md) - Can reference ClusterObservabilityPlane for monitoring +- [ClusterDataPlane](./clusterdataplane.md) - Cluster-scoped data plane that can reference ClusterObservabilityPlane +- [WorkflowPlane](./workflowplane.md) - Can reference ClusterObservabilityPlane for workflow job monitoring +- [ClusterWorkflowPlane](./clusterworkflowplane.md) - Cluster-scoped workflow plane that can reference ClusterObservabilityPlane +- [ObservabilityAlertRule](./observabilityalertrule.md) - Defines alerting rules for the plane +- [ObservabilityAlertsNotificationChannel](./observabilityalertsnotificationchannel.md) - Defines notification destinations for alerts diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterresourcetype.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterresourcetype.md new file mode 100644 index 00000000..552748dc --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterresourcetype.md @@ -0,0 +1,138 @@ +--- +title: ClusterResourceType API Reference +description: Cluster-scoped resource provisioning template reusable across all namespaces +--- + +# ClusterResourceType + +A ClusterResourceType is the cluster-scoped variant of [ResourceType](./resourcetype.md). Use it for templates intended to be shared platform-wide; namespace-scoped ResourceTypes are available when a template should be available only within a specific namespace. + +ClusterResourceTypes currently share the same spec structure as ResourceTypes; only scope differs. The shapes may diverge in a future release if cluster-only fields are added. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterResourceTypes are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterResourceType +metadata: + name: +``` + +:::note +ClusterResourceType manifests must **not** include `metadata.namespace`. If you are copying from a namespace-scoped ResourceType example, remove the `namespace` field. +::: + +**Short names:** `crt`, `crts` + +### Spec Fields + +The spec currently mirrors [ResourceType.spec](./resourcetype.md#spec-fields) and may diverge in a future release. Refer to that page for the full field reference. The CEL surface, output kinds, manifest `includeWhen` / `readyWhen` semantics, and `retainPolicy` behavior all match the namespace-scoped form. + +| Field | Type | Required | Default | Description | +| -------------------- | ---------------------------------------------------------------- | -------- | -------- | ----------------------------------------------------------------------- | +| `parameters` | [SchemaSection](./resourcetype.md#schemasection) | No | - | Schema for `Resource.spec.parameters` values | +| `environmentConfigs` | [SchemaSection](./resourcetype.md#schemasection) | No | - | Schema for `ResourceReleaseBinding.spec.resourceTypeEnvironmentConfigs` | +| `retainPolicy` | string | No | `Delete` | Default retention behavior for bindings of this type | +| `outputs` | [[ResourceTypeOutput](./resourcetype.md#resourcetypeoutput)] | No | [] | Named outputs consumed by workloads | +| `resources` | [[ResourceTypeManifest](./resourcetype.md#resourcetypemanifest)] | Yes | - | Kubernetes manifest templates emitted on the data plane | + +### Status Fields + +ClusterResourceType currently has no status fields. + +## Examples + +### Cluster-Scoped Valkey Cache + +A ClusterResourceType available to every namespace. Note the absence of `metadata.namespace`. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterResourceType +metadata: + name: valkey +spec: + environmentConfigs: + openAPIV3Schema: + type: object + properties: + memory: + type: string + default: "128Mi" + + retainPolicy: Delete + + outputs: + - name: host + value: "${metadata.name}.${metadata.namespace}.svc.cluster.local" + - name: port + value: "6379" + - name: password + secretKeyRef: + name: "${metadata.name}-creds" + key: password + + resources: + # ... omitted for brevity; see the ResourceType reference for the full pattern ... + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + selector: + app: ${metadata.name} + ports: + - name: valkey + port: 6379 + targetPort: 6379 + - id: statefulset + template: + # ... StatefulSet template ... +``` + +The example ClusterResourceTypes (`postgres`, `valkey`, `nats`) under `samples/getting-started/cluster-resource-types/` in the OpenChoreo repository demonstrate the full pattern—including ESO-backed credential generation and opt-in admin UIs. They use in-cluster StatefulSets for stateful infrastructure and are intended for local development and demonstration, not production use. + +## Usage + +A Resource references a ClusterResourceType by setting `spec.type.kind: ClusterResourceType`: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: doclet-cache + namespace: default +spec: + owner: + projectName: doclet + type: + kind: ClusterResourceType + name: valkey +``` + +A Resource that omits `spec.type.kind` defaults to `ResourceType` (namespace-scoped) per the CRD default—set the kind explicitly when targeting the cluster-scoped form. + +## Best Practices + +1. **Use ClusterResourceTypes for shared infrastructure patterns** used across many namespaces (Postgres, Valkey, NATS). Reserve namespace-scoped ResourceTypes for templates that depend on namespace-local configuration. +2. **Document the kind explicitly** on consumer manifests so reviewers see whether a Resource is consuming a cluster-wide or namespace-local template. +3. **Apply the same retention defaults** as you would for ResourceTypes—stateful templates should ship with `retainPolicy: Retain`. + +## Related Resources + +- [ResourceType](./resourcetype.md) — Namespace-scoped variant +- [Resource](../application/resource.md) — Developer-facing CRD +- [ResourceRelease](../runtime/resourcerelease.md) — Immutable snapshot cut by the Resource controller +- [ResourceReleaseBinding](./resourcereleasebinding.md) — Per-environment binding +- [Authoring ResourceTypes (PE Guide)](../../../platform-engineer-guide/resource-types.md) diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustertrait.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustertrait.md new file mode 100644 index 00000000..562720cc --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clustertrait.md @@ -0,0 +1,466 @@ +--- +title: ClusterTrait API Reference +description: Cluster-scoped reusable cross-cutting concern available across all namespaces +--- + +# ClusterTrait + +A ClusterTrait is a cluster-scoped variant of [Trait](./trait.md) that defines reusable cross-cutting concerns +available across namespaces. This enables platform engineers to define shared traits once — such as persistent +storage, observability, or security policies — and allow Components in any namespace to reference them, eliminating +duplication. + +ClusterTraits share the same spec structure as Traits with the same `parameters`, `environmentConfigs`, `creates`, and `patches` fields. +The only difference is scope: ClusterTraits are cluster-scoped (no namespace), while Traits are namespace-scoped. + +:::note +Unlike namespace-scoped [Traits](./trait.md), ClusterTraits do not support the `validations` field. +::: + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterTraits are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: +``` + +:::note +ClusterTrait manifests must **not** include `metadata.namespace`. If you are copying from a namespace-scoped +Trait example, remove the `namespace` field. +::: + +**Short names:** `ctrait`, `ctraits` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | ------------------------------- | -------- | ------- | ------------------------------------------------------------------------------ | +| `parameters` | [SchemaSection](#schemasection) | No | - | Developer-facing configurable parameters for this trait | +| `environmentConfigs` | [SchemaSection](#schemasection) | No | - | Parameters that can be overridden per environment | +| `creates` | [[TraitCreate](#traitcreate)] | No | [] | New Kubernetes resources to create when this trait is applied | +| `patches` | [[TraitPatch](#traitpatch)] | No | [] | Modifications to the rendered resources produced by the ComponentType template | + +### SchemaSection + +Defines the schema for configurable parameters using standard JSON Schema. + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | ------------------------------------------------------- | +| `openAPIV3Schema` | object | No | - | Standard OpenAPI v3 JSON Schema for defining parameters | + +**Example:** + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + volumeName: + type: string + mountPath: + type: string + containerName: + type: string + default: app + +environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: 10Gi + storageClass: + type: string + default: standard +``` + +### TraitCreate + +Defines a new Kubernetes resource to be created when the trait is applied. + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ----------- | --------------------------------------------------------------------- | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `includeWhen` | string | No | - | CEL expression determining if resource should be created | +| `forEach` | string | No | - | CEL expression for generating multiple resources from list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if `forEach` is set) | +| `template` | object | Yes | - | Kubernetes resource template with CEL expressions | + +#### CEL Context Variables for Creates + +CEL expressions in trait create templates have access to the following context variables: + +##### metadata + +Platform-computed metadata for resource generation (same as ComponentType): + +| Field | Type | Description | +| ----------------------------- | ------ | ------------------------------------------------------------------- | +| `metadata.name` | string | Base name for generated resources (e.g., `my-service-dev-a1b2c3d4`) | +| `metadata.namespace` | string | Target namespace for resources | +| `metadata.componentNamespace` | string | Target namespace of the component | +| `metadata.componentName` | string | Name of the component | +| `metadata.componentUID` | string | Unique identifier of the component | +| `metadata.projectName` | string | Name of the project | +| `metadata.projectUID` | string | Unique identifier of the project | +| `metadata.environmentName` | string | Name of the environment (e.g., `development`, `production`) | +| `metadata.environmentUID` | string | Unique identifier of the environment | +| `metadata.dataPlaneName` | string | Name of the data plane | +| `metadata.dataPlaneUID` | string | Unique identifier of the data plane | +| `metadata.labels` | map | Common labels to add to all resources | +| `metadata.annotations` | map | Common annotations to add to all resources | +| `metadata.podSelectors` | map | Platform-injected selectors for pod identity | + +##### trait + +Trait-specific metadata: + +| Field | Type | Description | +| -------------------- | ------ | ---------------------------------------------------------------- | +| `trait.name` | string | Name of the trait (e.g., `persistent-volume`) | +| `trait.instanceName` | string | Unique instance name within the component (e.g., `data-storage`) | + +##### parameters + +Trait instance parameters from `Component.spec.traits[].parameters` with schema defaults applied. Use for static configuration that doesn't change across environments. + +##### environmentConfigs + +Environment-specific configuration from `ReleaseBinding.spec.traitEnvironmentConfigs[instanceName]` with schema defaults applied. Use for values that vary per environment. + +##### dataplane + +Data plane configuration: + +| Field | Type | Description | +| ----------------------------- | ------ | --------------------------------------------------- | +| `dataplane.secretStore` | string | Name of the ClusterSecretStore for external secrets | +| `dataplane.publicVirtualHost` | string | Public virtual host for external access | + +##### Helper Functions + +| Function | Description | +| --------------------------- | ------------------------------------------------------------------------------------------ | +| `oc_generate_name(args...)` | Generate valid Kubernetes names with hash suffix for uniqueness | +| `oc_hash(string)` | Generate 8-character FNV-32a hash from input string | +| `oc_merge(map1, map2, ...)` | Shallow merge maps (later maps override earlier ones) | +| `oc_omit()` | Remove field/key from output when used in conditional expressions | +| `oc_dns_label(args...)` | Generate RFC 1123-compliant DNS label (≤63 chars) with hash suffix for HTTPRoute hostnames | + +### TraitPatch + +Defines modifications to existing resources generated by the ComponentType. + +| Field | Type | Required | Default | Description | +| ------------- | ------------------------------------------- | -------- | ----------- | --------------------------------------------------------------------- | +| `forEach` | string | No | - | CEL expression for iterating over a list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if `forEach` is set) | +| `target` | [PatchTarget](#patchtarget) | Yes | - | Specifies which resource to patch | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `operations` | [[JSONPatchOperation](#jsonpatchoperation)] | Yes | - | List of JSONPatch operations to apply | + +### PatchTarget + +Specifies which Kubernetes resource to modify. + +| Field | Type | Required | Description | +| --------- | ------ | -------- | --------------------------------------------------------------------------- | +| `group` | string | Yes | API group (e.g., `apps`, `batch`). Use empty string `""` for core resources | +| `version` | string | Yes | API version (e.g., `v1`, `v1beta1`) | +| `kind` | string | Yes | Resource type (e.g., `Deployment`, `StatefulSet`) | +| `where` | string | No | CEL expression to filter which resources to patch | + +### JSONPatchOperation + +Defines a modification using JSONPatch format (RFC 6902) with OpenChoreo extensions. + +| Field | Type | Required | Description | +| ------- | ------ | -------- | ------------------------------------- | +| `op` | string | Yes | Operation: `add`, `replace`, `remove` | +| `path` | string | Yes | JSON Pointer to the field (RFC 6901) | +| `value` | any | No | Value to set (not used for `remove`) | + +#### Supported Operations + +- **add**: Add a new field or array element +- **replace**: Replace an existing field value +- **remove**: Delete a field + +#### Path Syntax + +Supports array filters for targeting specific elements: + +``` +/spec/containers[?(@.name=='app')]/volumeMounts/- +``` + +## Examples + +### Persistent Volume ClusterTrait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: persistent-volume +spec: + parameters: + openAPIV3Schema: + type: object + required: + - volumeName + - mountPath + properties: + volumeName: + type: string + mountPath: + type: string + containerName: + type: string + default: app + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: 10Gi + storageClass: + type: string + default: standard + + creates: + - targetPlane: dataplane + template: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: ${metadata.name}-${parameters.volumeName} + namespace: ${metadata.namespace} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${environmentConfigs.size} + storageClassName: ${environmentConfigs.storageClass} + + patches: + - target: + group: apps + version: v1 + kind: Deployment + targetPlane: dataplane + operations: + - op: add + path: /spec/template/spec/volumes/- + value: + name: ${parameters.volumeName} + persistentVolumeClaim: + claimName: ${metadata.name}-${parameters.volumeName} + - op: add + path: /spec/template/spec/containers/[?(@.name=='${parameters.containerName}')]/volumeMounts/- + value: + name: ${parameters.volumeName} + mountPath: ${parameters.mountPath} +``` + +### Sidecar Container ClusterTrait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: logging-sidecar +spec: + parameters: + openAPIV3Schema: + type: object + properties: + logPath: + type: string + default: /var/log/app + sidecarImage: + type: string + default: fluent/fluent-bit:latest + + patches: + - target: + group: apps + version: v1 + kind: Deployment + operations: + - op: add + path: /spec/template/spec/containers/- + value: + name: log-collector + image: ${parameters.sidecarImage} + volumeMounts: + - name: logs + mountPath: ${parameters.logPath} + - op: add + path: /spec/template/spec/volumes/- + value: + name: logs + emptyDir: {} +``` + +### Resource Limits ClusterTrait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: resource-limits +spec: + environmentConfigs: + openAPIV3Schema: + type: object + properties: + cpuLimit: + type: string + default: 1000m + memoryLimit: + type: string + default: 512Mi + + patches: + - target: + group: apps + version: v1 + kind: Deployment + operations: + - op: add + path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/cpu + value: ${environmentConfigs.cpuLimit} + - op: add + path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/memory + value: ${environmentConfigs.memoryLimit} +``` + +### Multi-Volume ClusterTrait with forEach + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: multi-volume +spec: + parameters: + openAPIV3Schema: + type: object + properties: + mounts: + type: array + items: + type: object + properties: + name: + type: string + path: + type: string + + patches: + - target: + group: apps + version: v1 + kind: Deployment + forEach: ${parameters.mounts} + var: mount + operations: + - op: add + path: /spec/template/spec/volumes/- + value: + name: ${mount.name} + emptyDir: {} + - op: add + path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/- + value: + name: ${mount.name} + mountPath: ${mount.path} +``` + +## Usage + +Developers attach ClusterTraits to components using `kind: ClusterTrait` in the Component specification: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service + namespace: default +spec: + componentType: + kind: ClusterComponentType + name: deployment/service + + traits: + - name: persistent-volume + kind: ClusterTrait + instanceName: data-storage + parameters: + volumeName: data + mountPath: /var/data + containerName: app +``` + +Platform engineers can set trait `environmentConfigs` in ReleaseBinding: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + environment: production + owner: + componentName: my-service + projectName: default + + traitEnvironmentConfigs: + data-storage: # keyed by instanceName + size: 100Gi + storageClass: production-ssd +``` + +## Best Practices + +1. **Use for shared concerns**: Define ClusterTraits for cross-cutting concerns shared across namespaces; use namespace-scoped Traits for namespace-specific concerns +2. **Single responsibility**: Each trait should address one cross-cutting concern +3. **Naming**: Use descriptive names that indicate the capability being added +4. **Parameters**: Provide sensible defaults for all non-required parameters +5. **Target specificity**: Use `where` clauses when needed to avoid unintended modifications +6. **Testing**: Test ClusterTraits with different ComponentTypes to ensure compatibility +7. **Idempotency**: Ensure traits can be safely applied multiple times + +## ClusterTrait vs Trait + +| Aspect | Trait | ClusterTrait | +| ------------ | ------------------------------------- | ---------------------------------------- | +| Scope | Namespace-scoped | Cluster-scoped | +| Availability | Only within its namespace | Across all namespaces | +| Short names | `trait`, `traits` | `ctrait`, `ctraits` | +| Validations | Supports `validations` field | Does **not** support `validations` field | +| Used by | ComponentType or ClusterComponentType | ComponentType or ClusterComponentType | + +## Related Resources + +- [Trait](./trait.md) - Namespace-scoped variant of ClusterTrait +- [ComponentType](./componenttype.md) - Defines the base deployment pattern that traits modify +- [ClusterComponentType](./clustercomponenttype.md) - Cluster-scoped variant of ComponentType (can only use ClusterTraits) +- [Component](../application/component.md) - Attaches traits to components +- [ReleaseBinding](releasebinding.md) - Binds a ComponentRelease to an environment with trait parameter overrides diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflow.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflow.md new file mode 100644 index 00000000..b9f69272 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflow.md @@ -0,0 +1,202 @@ +--- +title: ClusterWorkflow API Reference +description: Cluster-scoped automation template reusable across all namespaces +--- + +# ClusterWorkflow + +A ClusterWorkflow is a cluster-scoped variant of [Workflow](./workflow.md) that defines reusable automation templates +available across all namespaces. This enables platform engineers to define shared workflow templates once and reference +them from WorkflowRuns or ClusterComponentTypes in any namespace, eliminating duplication. + +ClusterWorkflows share the same spec structure as Workflows with one key constraint: because ClusterWorkflows are +cluster-scoped, they can only reference **ClusterWorkflowPlanes** (not namespace-scoped WorkflowPlanes) in their +`workflowPlaneRef` field. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterWorkflows are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflow +metadata: + name: +``` + +:::note +ClusterWorkflow manifests must **not** include `metadata.namespace`. If you are copying from a namespace-scoped +Workflow example, remove the `namespace` field. +::: + +**Short names:** `cwf`, `cwfs` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | --------------------------------------------------- | -------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `workflowPlaneRef` | [ClusterWorkflowPlaneRef](#clusterworkflowplaneref) | No | `{kind: "ClusterWorkflowPlane", name: "default"}` | Reference to the ClusterWorkflowPlane for this workflow's operations | +| `parameters` | [SchemaSection](./workflow.md#schemasection) | No | - | Developer-facing parameter schema | +| `runTemplate` | object | Yes | - | Kubernetes resource template (typically Argo Workflow) with template variables for runtime evaluation | +| `resources` | [][WorkflowResource](#workflowresource) | No | - | Additional Kubernetes resources to create alongside the workflow run | +| `externalRefs` | [][ExternalRef](#externalref) | No | - | References to external CRs resolved at runtime and injected into the CEL context | +| `ttlAfterCompletion` | string | No | - | Auto-delete duration after workflow run completion (e.g., `90d`, `1h30m`). Pattern: `^(\d+d)?(\d+h)?(\d+m)?(\d+s)?$` | + +### ClusterWorkflowPlaneRef + +References the cluster-scoped workflow plane where workflows execute. This field is **immutable** after creation. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ----------------------------------------- | +| `kind` | string | Yes | - | Must be `ClusterWorkflowPlane` | +| `name` | string | Yes | - | Name of the ClusterWorkflowPlane resource | + +If not specified, the controller resolves to the `ClusterWorkflowPlane` named `default`. + +### Parameters (SchemaSection) + +See [Workflow SchemaSection](./workflow.md#schemasection) for the full schema documentation. ClusterWorkflows use the same +`openAPIV3Schema` format as Workflows. + +### WorkflowResource + +See [Workflow WorkflowResource](./workflow.md#workflowresource) for the full documentation. ClusterWorkflows use the +same resource structure as Workflows. + +### ExternalRef + +See [Workflow ExternalRef](./workflow.md#externalref) for the full documentation. ClusterWorkflows use the same +external reference structure as Workflows. + +### Template Variables + +ClusterWorkflows support the same template variables as Workflows. See [Workflow Template Variables](./workflow.md#template-variables) for the full list, including `${metadata.*}`, `${parameters.*}`, `${externalRefs.*}`, and `${workflowplane.secretStore}`. + +### Status Fields + +| Field | Type | Default | Description | +| ------------ | ----------- | ------- | ---------------------------------------------------------- | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the workflow state | + +## Examples + +### Dockerfile Builder ClusterWorkflow + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflow +metadata: + name: dockerfile-builder + labels: + openchoreo.dev/workflow-type: "component" + annotations: + openchoreo.dev/description: "Build with a provided Dockerfile/Containerfile/Podmanfile" +spec: + workflowPlaneRef: + kind: ClusterWorkflowPlane + name: default + ttlAfterCompletion: "1d" + + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + x-openchoreo-component-parameter-repository-url: true + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + x-openchoreo-component-parameter-repository-secret-ref: true + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + x-openchoreo-component-parameter-repository-branch: true + commit: + type: string + default: "" + description: "Git commit SHA or reference (optional)" + x-openchoreo-component-parameter-repository-commit: true + appPath: + type: string + default: "." + description: "Path to the application directory within the repository" + x-openchoreo-component-parameter-repository-app-path: true + docker: + type: object + default: {} + description: "Docker build configuration" + properties: + context: + type: string + default: "." + description: "Docker build context path" + filePath: + type: string + default: "./Dockerfile" + description: "Path to the Dockerfile" + + runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + name: ${metadata.workflowRunName} + namespace: ${metadata.namespace} + spec: + serviceAccountName: workflow-sa + entrypoint: build-workflow + templates: + - name: build-workflow + steps: + - - name: checkout-source + templateRef: + name: checkout-source + clusterScope: true + template: checkout + - - name: build-image + templateRef: + name: containerfile-build + clusterScope: true + template: build-image +``` + +## Labels + +| Label | Description | +| ------------------------------ | -------------------------------------------------------------------------------- | +| `openchoreo.dev/workflow-type` | Set to `"component"` to mark this as a CI workflow for UI and CLI categorization | + +## Annotations + +| Annotation | Description | +| ----------------------------- | ------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the ClusterWorkflow | + +## Related Resources + +- [Workflow](./workflow.md) - Namespace-scoped variant of ClusterWorkflow +- [WorkflowRun](../application/workflowrun.md) - Runtime execution instances that can reference ClusterWorkflows +- [ClusterComponentType](./clustercomponenttype.md) - Can restrict allowed ClusterWorkflows via `allowedWorkflows` +- [ClusterWorkflowPlane](./clusterworkflowplane.md) - Cluster-scoped workflow plane referenced by ClusterWorkflows diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflowplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflowplane.md new file mode 100644 index 00000000..f40c28b5 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/clusterworkflowplane.md @@ -0,0 +1,204 @@ +--- +title: ClusterWorkflowPlane API Reference +description: Cluster-scoped Kubernetes workflow plane shared across namespaces to execute workflows +--- + +# ClusterWorkflowPlane + +A ClusterWorkflowPlane is a cluster-scoped variant of [WorkflowPlane](./workflowplane.md) that represents the infrastructure layer responsible for executing workflow workloads in OpenChoreo. Unlike the namespace-scoped WorkflowPlane, a ClusterWorkflowPlane is a cluster-scoped resource, making it suitable for shared workflow plane infrastructure scenarios. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the workflow plane cluster through a WebSocket agent running in the ClusterWorkflowPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ClusterWorkflowPlanes are cluster-scoped resources (no namespace). + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflowPlane +metadata: + name: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | +| `planeID` | string | Yes | - | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `secretStoreRef` | [SecretStoreRef](#secretstoreref) | No | - | Reference to External Secrets Operator ClusterSecretStore in the ClusterWorkflowPlane | +| `observabilityPlaneRef` | [ObservabilityPlaneRef](#observabilityplaneref) | No | - | Reference to a ClusterObservabilityPlane resource for monitoring and logging | + +### PlaneID + +The `planeID` identifies the logical plane this ClusterWorkflowPlane CR connects to. Multiple ClusterWorkflowPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"shared-workflow"`, `"ci-cluster"`, `"us-west-2"` + +:::important PlaneID Consistency +The `planeID` in the ClusterWorkflowPlane CR must match the `clusterAgent.planeId` Helm value configured during workflow plane installation. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the workflow plane cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### SecretStoreRef + +Reference to an External Secrets Operator ClusterSecretStore. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ---------------------------------------------------------- | +| `name` | string | Yes | - | Name of the ClusterSecretStore in the ClusterWorkflowPlane | + +### ObservabilityPlaneRef + +Reference to a ClusterObservabilityPlane for monitoring and logging. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `ClusterObservabilityPlane` | Must be `ClusterObservabilityPlane`. ClusterWorkflowPlane can only reference cluster-scoped observability planes. | +| `name` | string | Yes | - | Name of the ClusterObservabilityPlane resource | + +:::note Resolution Behavior + +- ClusterWorkflowPlane can **only** reference a `ClusterObservabilityPlane` (not a namespace-scoped `ObservabilityPlane`). This is enforced by API validation. +- If `observabilityPlaneRef` is omitted, the controller attempts to find a ClusterObservabilityPlane named "default". If no default exists, observability is not configured. +- If the referenced ClusterObservabilityPlane is not found, the controller returns an error and the ClusterWorkflowPlane will not become ready. + ::: + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ------- | --------------------------------------------------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No\* | - | Namespace of the secret (required for cluster-scoped resources) | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | ---------------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the ClusterWorkflowPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +## Examples + +### Basic ClusterWorkflowPlane Configuration + +This example shows a minimal ClusterWorkflowPlane configuration. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflowPlane +metadata: + name: shared-workflowplane +spec: + planeID: "shared-workflow" + clusterAgent: + clientCA: + secretKeyRef: + name: workflowplane-agent-ca + namespace: openchoreo-system + key: ca.crt +``` + +### ClusterWorkflowPlane with Secret Store + +This example demonstrates using External Secrets Operator for managing secrets. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflowPlane +metadata: + name: secure-workflowplane +spec: + planeID: "secure-workflow" + clusterAgent: + clientCA: + secretKeyRef: + name: agent-ca-cert + namespace: openchoreo-system + key: ca.crt + secretStoreRef: + name: vault-backend +``` + +### ClusterWorkflowPlane with Observability + +This example shows a ClusterWorkflowPlane linked to a ClusterObservabilityPlane for monitoring workflow jobs. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterWorkflowPlane +metadata: + name: monitored-workflowplane +spec: + planeID: "prod-ci" + clusterAgent: + clientCA: + secretKeyRef: + name: workflowplane-agent-ca + namespace: openchoreo-system + key: ca.crt + secretStoreRef: + name: default + observabilityPlaneRef: + kind: ClusterObservabilityPlane + name: production-observability +``` + +## Annotations + +ClusterWorkflowPlanes support the following annotations: + +| Annotation | Description | +| ----------------------------- | ------------------------------------------------ | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the ClusterWorkflowPlane | + +## Related Resources + +- [WorkflowPlane](./workflowplane.md) - Namespace-scoped variant of ClusterWorkflowPlane +- [DataPlane](./dataplane.md) - Runtime infrastructure for deployed applications +- [ClusterDataPlane](./clusterdataplane.md) - Cluster-scoped data plane configuration +- [ClusterObservabilityPlane](./clusterobservabilityplane.md) - Cluster-scoped observability plane +- [Component](../application/component.md) - Application components that trigger workflows +- [WorkflowRun](../application/workflowrun.md) - Workflow job executions on WorkflowPlanes diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/componenttype.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/componenttype.md new file mode 100644 index 00000000..f0713dbd --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/componenttype.md @@ -0,0 +1,499 @@ +--- +title: ComponentType API Reference +description: Platform-defined deployment template with configurable parameters and CEL-based resource generation +--- + +# ComponentType + +A ComponentType is a platform-defined template that determines how components are deployed and what resources are +generated for them. ComponentTypes enable platform engineers to create reusable deployment patterns with configurable +parameters, replacing the fixed component classes from previous versions. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ComponentTypes are namespace-scoped resources typically created in a namespace to be available for +components in that namespace. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: + namespace: # Namespace for grouping component types +``` + +**Short names:** `ct`, `cts` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------- | +| `workloadType` | string | Yes | - | Primary workload type: `deployment`, `statefulset`, `cronjob`, `job`, `proxy` | +| `allowedWorkflows` | [[WorkflowRef](#workflowref)] | No | [] | Workflow references developers can use for building this component type; if empty, no workflows are allowed | +| `parameters` | [SchemaSection](#schemasection) | No | - | Developer-facing parameter schema for components of this type | +| `environmentConfigs` | [SchemaSection](#schemasection) | No | - | Per-environment configuration overrides schema | +| `traits` | [[ComponentTypeTrait](#componenttypetrait)] | No | [] | Pre-configured trait instances automatically applied to all Components of this type | +| `allowedTraits` | [[TraitRef](#traitref)] | No | [] | Traits that developers can attach to components of this type beyond those embedded in `traits` | +| `validations` | [[ValidationRule](#validationrule)] | No | [] | Deprecated alias for `preRenderValidations` (identical semantics); set only one of the two | +| `preRenderValidations` | [[ValidationRule](#validationrule)] | No | [] | CEL-based rules evaluated before rendering against the static context; all must pass for rendering to proceed | +| `postRenderValidations` | [[PostRenderValidation](#postrendervalidation)] | No | [] | CEL-based rules evaluated after all traits are applied, against the final rendered resources | +| `resources` | [[ResourceTemplate](#resourcetemplate)] | Yes | - | Templates for generating Kubernetes resources | + +:::note +The `workloadType` field is immutable after creation and determines the primary resource type for components of this +type. For non-proxy workload types, one resource template must have an `id` matching the `workloadType`. +::: + +### WorkflowRef + +Specifies a Workflow that developers can use with components of this type. `allowedWorkflows` is an explicit allow +list, so only referenced Workflows are permitted. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ---------- | ---------------------------------------------------------------------------------------------------- | +| `kind` | string | No | `Workflow` | Kind of the referenced resource: `Workflow` (namespace-scoped) or `ClusterWorkflow` (cluster-scoped) | +| `name` | string | Yes | - | Name of the Workflow or ClusterWorkflow resource | + +**Example:** + +```yaml +allowedWorkflows: + - kind: Workflow + name: nodejs-build + - kind: ClusterWorkflow + name: dockerfile-builder + - name: container-image-scan +``` + +### ComponentTypeTrait + +Represents a pre-configured trait instance embedded in a ComponentType. These traits are automatically applied to all +Components of this type. + +| Field | Type | Required | Default | Description | +| -------------------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `kind` | string | No | `Trait` | Kind of the referenced resource: `Trait` (namespace-scoped) or `ClusterTrait` (cluster-scoped) | +| `name` | string | Yes | - | Name of the Trait or ClusterTrait | +| `instanceName` | string | Yes | - | Unique instance name within the component type | +| `parameters` | object | No | - | Trait parameter values (can use CEL expressions referencing the ComponentType schema, e.g., `${parameters.storage.mountPath}`) | +| `environmentConfigs` | object | No | - | Environment-specific override values for the trait | + +### TraitRef + +Specifies a Trait or ClusterTrait that developers can attach to components of this type. Traits listed here must not +overlap with traits already embedded in `spec.traits`. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ---------------------------------------------------------------------------------------------- | +| `kind` | string | No | `Trait` | Kind of the referenced resource: `Trait` (namespace-scoped) or `ClusterTrait` (cluster-scoped) | +| `name` | string | Yes | - | Name of the Trait or ClusterTrait | + +### ValidationRule + +Defines a CEL-based validation rule evaluated before rendering, against the static context. All rules must evaluate to +true for rendering to proceed. This is the entry shape for `preRenderValidations` and the deprecated `validations`. + +| Field | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------------- | +| `rule` | string | Yes | CEL expression wrapped in `${...}` that must evaluate to true | +| `message` | string | Yes | Error message shown when the rule evaluates to false | + +**Example:** + +```yaml +preRenderValidations: + - rule: ${parameters.replicas >= 1} + message: "replicas must be at least 1" + - rule: ${parameters.port > 0 && parameters.port <= 65535} + message: "port must be between 1 and 65535" +``` + +### PostRenderValidation + +Asserts a CEL rule against the rendered Kubernetes resources after all traits have been applied. Each entry selects +target resources by GVK (with an optional `where` filter), binds each match to the `resource` variable, and requires +`rule` to evaluate to true. + +| Field | Type | Required | Default | Description | +| ------------------ | ------ | -------- | ----------- | ---------------------------------------------------------------------------------------------------------- | +| `when` | string | No | - | CEL guard `${...}` evaluated against the declaring resource's context; if false, the validation is skipped | +| `forEach` | string | No | - | CEL expression `${...}` producing a list; the validation repeats per item | +| `var` | string | No | - | Loop variable name for `forEach` (required when `forEach` is set); in scope in `target.where` and `rule` | +| `target.group` | string | Yes | - | API group of the rendered resources to select (empty string for the core group) | +| `target.version` | string | Yes | - | API version of the rendered resources to select | +| `target.kind` | string | Yes | - | Kind of the rendered resources to select | +| `target.where` | string | No | - | CEL filter `${...}` over the selected resources, with `resource` bound | +| `target.mustMatch` | bool | No | `true` | When true and no rendered resource matches the target, the validation fails | +| `targetPlane` | string | No | `dataplane` | Plane whose resources are selected: `dataplane` or `observabilityplane` | +| `rule` | string | Yes | - | CEL expression `${...}` evaluated with `resource` bound to each match; must evaluate to true | +| `message` | string | Yes | - | Error message shown when the rule fails (literal string; `${...}` is not interpolated) | + +**Example:** + +```yaml +postRenderValidations: + - target: + group: apps + version: v1 + kind: Deployment + rule: ${resource.spec.template.spec.securityContext.runAsNonRoot == true} + message: "traits must not relax pod-level non-root execution" +``` + +### SchemaSection + +Both `parameters` and `environmentConfigs` use the `SchemaSection` type, which holds a schema in `openAPIV3Schema` format: + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | -------------------------------------- | +| `openAPIV3Schema` | object | No | - | Standard OpenAPI v3 JSON Schema format | + +#### openAPIV3Schema Format + +Uses standard OpenAPI v3 JSON Schema: + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + port: + type: integer + default: 80 +``` + +### ResourceTemplate + +Defines a template for generating Kubernetes resources with CEL expressions for dynamic values. + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ----------- | --------------------------------------------------------------------- | +| `id` | string | Yes | - | Unique identifier (must match `workloadType` for primary) | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `includeWhen` | string | No | - | CEL expression determining if resource should be created | +| `forEach` | string | No | - | CEL expression for generating multiple resources from list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if `forEach` is set) | +| `template` | object | Yes | - | Kubernetes resource template with CEL expressions | + +#### CEL Expression Syntax + +Templates use CEL expressions enclosed in `${...}` that have access to the following context variables: + +##### metadata + +Platform-computed metadata for resource generation: + +| Field | Type | Description | +| ----------------------------- | ------ | ---------------------------------------------------------------------------------- | +| `metadata.name` | string | Base name for generated resources (e.g., `my-service-dev-a1b2c3d4`) | +| `metadata.namespace` | string | Target namespace for resources | +| `metadata.componentNamespace` | string | Target namespace of the component | +| `metadata.componentName` | string | Name of the component | +| `metadata.componentUID` | string | Unique identifier of the component | +| `metadata.projectName` | string | Name of the project | +| `metadata.projectUID` | string | Unique identifier of the project | +| `metadata.environmentName` | string | Name of the environment (e.g., `development`, `production`) | +| `metadata.environmentUID` | string | Unique identifier of the environment | +| `metadata.dataPlaneName` | string | Name of the data plane | +| `metadata.dataPlaneUID` | string | Unique identifier of the data plane | +| `metadata.labels` | map | Common labels to add to all resources | +| `metadata.annotations` | map | Common annotations to add to all resources | +| `metadata.podSelectors` | map | Platform-injected selectors for pod identity (use in Deployment/Service selectors) | + +##### parameters + +Component parameters from `Component.spec.parameters` with schema defaults applied. Use for static configuration that doesn't change across environments. + +##### environmentConfigs + +Environment-specific overrides from `ReleaseBinding.spec.componentTypeEnvironmentConfigs` with schema defaults applied. Use for values that vary per environment (resources, replicas, etc.). + +##### workload + +Workload specification from the Workload resource: + +| Field | Type | Description | +| ------------------------------------- | ----------------- | ------------------------------------------------------------------------- | +| `workload.container` | object | Container configuration | +| `workload.container.image` | string | Container image | +| `workload.container.command` | []string | Container command | +| `workload.container.args` | []string | Container arguments | +| `workload.endpoints` | map[string]object | Network endpoints keyed by endpoint name | +| `workload.endpoints[name].type` | string | Endpoint protocol (`HTTP`, `gRPC`, `GraphQL`, `Websocket`, `TCP`, `UDP`) | +| `workload.endpoints[name].port` | int32 | Port number | +| `workload.endpoints[name].basePath` | string | Base path prefix (optional, default `"/"`) | +| `workload.endpoints[name].visibility` | []string | Visibility scopes: `"project"`, `"namespace"`, `"internal"`, `"external"` | + +##### configurations + +Configuration and secret references extracted from the workload container: + +| Field | Type | Description | +| ------------------------------ | -------- | -------------------------------------------------------- | +| `configurations.configs.envs` | []object | Environment variable configs (each has `name`, `value`) | +| `configurations.configs.files` | []object | File configs (each has `name`, `mountPath`, `value`) | +| `configurations.secrets.envs` | []object | Secret env vars (each has `name`, `value`, `remoteRef`) | +| `configurations.secrets.files` | []object | Secret files (each has `name`, `mountPath`, `remoteRef`) | + +The `remoteRef` object contains: `key`, `property` (optional), `version` (optional). + +**Configuration Helper Functions:** + +The `configurations` object provides several helper methods to simplify working with container configurations. See [Configuration Helpers](../../cel/helper-functions.md) for detailed documentation on these functions: + +- `configurations.toContainerEnvFrom()` - Generate envFrom array for the container +- `configurations.toConfigEnvsByContainer()` - List config environment variables +- `configurations.toSecretEnvsByContainer()` - List secret environment variables +- `configurations.toConfigFileList()` - Flatten all config files into a single list +- `configurations.toSecretFileList()` - Flatten all secret files into a single list +- `configurations.toContainerVolumeMounts()` - Generate volumeMounts for the container +- `configurations.toVolumes()` - Generate volumes array + +##### dataplane + +Data plane configuration: + +| Field | Type | Description | +| ----------------------------- | ------ | --------------------------------------------------- | +| `dataplane.secretStore` | string | Name of the ClusterSecretStore for external secrets | +| `dataplane.publicVirtualHost` | string | Public virtual host for external access | + +##### gateway + +Ingress gateway configuration for HTTPRoute generation: + +| Field | Type | Description | +| ------------------------------------ | ------ | ----------------------------------------------------------- | +| `gateway.ingress.external.name` | string | Name of the external ingress Gateway resource | +| `gateway.ingress.external.namespace` | string | Namespace of the external ingress Gateway resource | +| `gateway.ingress.external.http` | object | HTTP listener (optional; has `.host`) | +| `gateway.ingress.external.https` | object | HTTPS listener (optional; has `.host`) | +| `gateway.ingress.internal.name` | string | Name of the internal ingress Gateway resource | +| `gateway.ingress.internal.namespace` | string | Namespace of the internal ingress Gateway resource | +| `gateway.ingress.internal.http` | object | HTTP listener for internal gateway (optional; has `.host`) | +| `gateway.ingress.internal.https` | object | HTTPS listener for internal gateway (optional; has `.host`) | + +##### Helper Functions + +| Function | Description | +| --------------------------- | ------------------------------------------------------------------------------------------ | +| `oc_generate_name(args...)` | Generate valid Kubernetes names with hash suffix for uniqueness | +| `oc_hash(string)` | Generate 8-character FNV-32a hash from input string | +| `oc_merge(map1, map2, ...)` | Shallow merge maps (later maps override earlier ones) | +| `oc_omit()` | Remove field/key from output when used in conditional expressions | +| `oc_dns_label(args...)` | Generate RFC 1123-compliant DNS label (≤63 chars) with hash suffix for HTTPRoute hostnames | + +For a comprehensive guide to configuration helper functions, see the [Configuration Helpers](../../cel/helper-functions.md). + +## Examples + +### Basic HTTP Service ComponentType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: service + namespace: default +spec: + workloadType: deployment + + parameters: + openAPIV3Schema: + type: object + properties: + replicas: + type: integer + default: 1 + port: + type: integer + default: 80 + + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + replicas: ${parameters.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${metadata.podSelectors} + spec: + containers: + - name: main + image: ${workload.container.image} + ports: + - containerPort: ${parameters.port} + + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.componentName} + namespace: ${metadata.namespace} + spec: + selector: ${metadata.podSelectors} + ports: + - port: 80 + targetPort: ${parameters.port} + + - id: httproute-external + forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility && ep.type in ["HTTP", "GraphQL", "Websocket"]) ? [name] : []).flatten()}' + var: endpoint + template: + apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: ${oc_generate_name(metadata.componentName, endpoint)} + namespace: ${metadata.namespace} + labels: '${oc_merge(metadata.labels, {"openchoreo.dev/endpoint-name": endpoint, "openchoreo.dev/endpoint-visibility": "external"})}' + spec: + parentRefs: + - name: ${gateway.ingress.external.name} + namespace: ${gateway.ingress.external.namespace} + hostnames: | + ${[gateway.ingress.external.?http, gateway.ingress.external.?https] + .filter(g, g.hasValue()).map(g, g.value().host).distinct() + .map(h, oc_dns_label(endpoint, metadata.componentName, metadata.environmentName, metadata.componentNamespace) + "." + h)} + rules: + - matches: + - path: + type: PathPrefix + value: /${metadata.componentName}-${endpoint} + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("") != "" ? workload.endpoints[endpoint].?basePath.orValue("") : "/"}' + backendRefs: + - name: ${metadata.componentName} + port: ${workload.endpoints[endpoint].port} +``` + +### Scheduled Task ComponentType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: scheduled-task + namespace: default +spec: + workloadType: cronjob + + parameters: + openAPIV3Schema: + type: object + properties: + schedule: + type: string + concurrencyPolicy: + type: string + default: Forbid + enum: + - Allow + - Forbid + - Replace + + resources: + - id: cronjob + template: + apiVersion: batch/v1 + kind: CronJob + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + schedule: ${parameters.schedule} + concurrencyPolicy: ${parameters.concurrencyPolicy} + jobTemplate: + spec: + template: + spec: + containers: + - name: main + image: ${workload.container.image} + restartPolicy: OnFailure +``` + +### ComponentType with Resource Iteration + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: multi-config-service + namespace: default +spec: + workloadType: deployment + + resources: + - id: deployment + template: + # ... deployment spec ... + + - id: file-config + includeWhen: ${has(configurations.configs.files) && configurations.configs.files.size() > 0} + forEach: ${configurations.configs.files} + var: config + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${metadata.name}-${config.name} + namespace: ${metadata.namespace} + data: + ${config.name}: ${config.value} +``` + +## Usage + +Components reference a ComponentType using the `spec.componentType` field: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service +spec: + componentType: + kind: ComponentType + name: deployment/service # References the ComponentType + parameters: + replicas: 3 + port: 8080 +``` + +## Best Practices + +1. **Naming Convention**: Use descriptive names like `service`, `web-application`, `scheduled-task` +2. **Parameter Design**: Keep parameters focused and provide sensible defaults +3. **Resource IDs**: Use clear, descriptive IDs for each resource template +4. **Conditional Resources**: Use `includeWhen` for optional resources based on parameters +5. **Type Definitions**: Define reusable types for complex parameter structures +6. **Testing**: Validate ComponentTypes with sample components before platform-wide deployment + +## Related Resources + +- [ClusterComponentType](./clustercomponenttype.md) - Cluster-scoped variant of ComponentType +- [Configuration Helpers](../../cel/helper-functions.md) - Configuration helper functions reference +- [Component](../application/component.md) - Uses ComponentTypes for deployment +- [ReleaseBinding](releasebinding.md) - Binds a ComponentRelease to an environment with parameter overrides +- [Trait](trait.md) - Adds cross-cutting concerns to components using ComponentTypes diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/dataplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/dataplane.md new file mode 100644 index 00000000..44a89f71 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/dataplane.md @@ -0,0 +1,420 @@ +--- +title: DataPlane API Reference +description: Namespace-scoped Kubernetes data plane cluster to deploy workloads +--- + +# DataPlane + +A DataPlane represents a Kubernetes cluster where application workloads are deployed. It defines the connection to a target Kubernetes cluster via a cluster agent and gateway settings for routing traffic to applications. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the downstream cluster through a WebSocket agent running in the DataPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +DataPlanes are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: DataPlane +metadata: + name: + namespace: # Namespace for grouping dataplanes +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- | +| `planeID` | string | No | CR name | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `gateway` | [GatewaySpec](#gatewayspec) | No | - | API gateway configuration for this DataPlane | +| `secretStoreRef` | [SecretStoreRef](#secretstoreref) | No | - | Reference to External Secrets Operator ClusterSecretStore in the DataPlane | +| `observabilityPlaneRef` | [ObservabilityPlaneRef](#observabilityplaneref) | No | - | Reference to the ObservabilityPlane or ClusterObservabilityPlane resource for monitoring and logging | + +### PlaneID + +The `planeID` identifies the logical plane this DataPlane CR connects to. Multiple DataPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations for multi-tenancy scenarios. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"prod-cluster"`, `"shared-dataplane"`, `"us-east-1"` + +:::important PlaneID Consistency +The `planeID` in the DataPlane CR must match the `clusterAgent.planeId` Helm value configured during data plane installation. If not specified, it defaults to the CR name for backwards compatibility. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the downstream cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### GatewaySpec + +Gateway configuration for the DataPlane. + +| Field | Type | Required | Default | Description | +| --------- | ----------------------------------------- | -------- | ------- | ----------------------------- | +| `ingress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Ingress gateway configuration | +| `egress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Egress gateway configuration | + +### GatewayNetworkSpec + +Network-level gateway configuration for ingress or egress. + +| Field | Type | Required | Default | Description | +| ---------- | ------------------------------------------- | -------- | ------- | --------------------------------------- | +| `external` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | External gateway endpoint configuration | +| `internal` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | Internal gateway endpoint configuration | + +### GatewayEndpointSpec + +Configuration for a specific gateway endpoint. + +| Field | Type | Required | Default | Description | +| ----------- | ------------------------------------------- | -------- | ------- | -------------------------------------------- | +| `name` | string | Yes | - | Name of the Kubernetes Gateway resource | +| `namespace` | string | Yes | - | Namespace of the Kubernetes Gateway resource | +| `http` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTP listener configuration | +| `https` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTPS listener configuration | +| `tls` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | TLS listener configuration | + +### GatewayListenerSpec + +Configuration for a gateway listener. + +| Field | Type | Required | Default | Description | +| -------------- | ------- | -------- | ------- | ----------------------------------- | +| `listenerName` | string | No | - | Name of the listener on the Gateway | +| `port` | integer | Yes | - | Port number for the listener | +| `host` | string | Yes | - | Hostname for the listener | + +### SecretStoreRef + +Reference to an External Secrets Operator ClusterSecretStore. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ----------------------------------------------- | +| `name` | string | Yes | - | Name of the ClusterSecretStore in the DataPlane | + +### ObservabilityPlaneRef + +Reference to an ObservabilityPlane or ClusterObservabilityPlane for monitoring and logging. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ------------------------------------------------------------------------------------- | +| `kind` | string | Yes | - | Kind of the observability plane (`ObservabilityPlane` or `ClusterObservabilityPlane`) | +| `name` | string | Yes | - | Name of the observability plane resource | + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ----------------------- | ----------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No | Same as parent resource | Namespace of the secret | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | ----------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the DataPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +#### Condition Types + +Common condition types for DataPlane resources: + +- `Ready` - Indicates if the DataPlane is ready to accept workloads +- `Connected` - Indicates if connection to the target cluster is established +- `GatewayProvisioned` - Indicates if the gateway has been configured + +## Getting the Agent CA Certificate + +The cluster agent automatically generates its CA certificate when deployed to the data plane cluster. This certificate is used by the control plane to verify the identity of the data plane agent during mTLS authentication. + +### Extracting the CA Certificate + +You can extract the CA certificate using: + +```bash +# For multi-cluster setups, specify the data plane cluster context +kubectl --context get secret cluster-agent-tls \ + -n openchoreo-data-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d + +# Example for k3d multi-cluster setup: +kubectl --context k3d-openchoreo-dp get secret cluster-agent-tls \ + -n openchoreo-data-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d +``` + +:::important +In multi-cluster setups, you **must** specify the `--context` flag to target the data plane cluster, not the control plane cluster. The `cluster-agent-tls` secret exists in the data plane cluster where the agent is deployed. +::: + +### Adding the Certificate to the DataPlane CR + +You can add the CA certificate to the DataPlane CR in two ways: + +**Option 1: Inline value (for testing/development)** + +```bash +# Extract the CA certificate from the data plane cluster +CA_CERT=$(kubectl --context get secret cluster-agent-tls \ + -n openchoreo-data-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d) + +# Create DataPlane in the control plane with inline CA certificate +kubectl --context apply -f - < get secret cluster-agent-tls \ + -n openchoreo-data-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/dataplane-ca.crt + +# Create a secret in the control plane cluster +kubectl --context create secret generic dataplane-agent-ca \ + --from-file=ca.crt=/tmp/dataplane-ca.crt \ + -n my-org + +# Create DataPlane in the control plane referencing the secret +kubectl --context apply -f - < + namespace: # Namespace for grouping pipelines +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ---------------- | --------------------------------- | -------- | ------- | -------------------------------------------------------------- | +| `promotionPaths` | [[PromotionPath](#promotionpath)] | No | [] | Defines the available paths for promotion between environments | + +### PromotionPath + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `sourceEnvironmentRef` | [EnvironmentRef](#environmentref) | Yes | - | Reference to the source environment for promotion | +| `targetEnvironmentRefs` | [[TargetEnvironmentRef](#targetenvironmentref)] | Yes | - | List of target environments for promotion | + +### EnvironmentRef + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------------- | -------------------------------- | +| `kind` | string | No | `Environment` | Kind of the environment resource | +| `name` | string | Yes | - | Name of the environment resource | + +### TargetEnvironmentRef + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------------- | -------------------------------- | +| `kind` | string | No | `Environment` | Kind of the environment resource | +| `name` | string | Yes | - | Name of the target environment | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------- | ------- | --------------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the deployment pipeline state | + +#### Condition Types + +Common condition types for DeploymentPipeline resources: + +- `Available` - Indicates if the deployment pipeline is available and configured + +## Examples + +### Basic DeploymentPipeline + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: DeploymentPipeline +metadata: + name: default-deployment-pipeline + namespace: default +spec: + promotionPaths: + - sourceEnvironmentRef: + name: development + targetEnvironmentRefs: + - name: staging + - sourceEnvironmentRef: + name: staging + targetEnvironmentRefs: + - name: production +``` + +## Annotations + +DeploymentPipelines support the following annotations: + +| Annotation | Description | +| ----------------------------- | ----------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the deployment pipeline | + +## Related Resources + +- [Project](../application/project.md) - Projects reference deployment pipelines for their promotion + workflows +- [Environment](./environment.md) - Environments that are connected through promotion paths diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/environment.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/environment.md new file mode 100644 index 00000000..f1e4564f --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/environment.md @@ -0,0 +1,186 @@ +--- +title: Environment API Reference +description: Logical environment within a DataPlane where workloads get deployed +--- + +# Environment + +An Environment represents a runtime context (e.g., dev, test, staging, production) where workloads are deployed and +executed. Environments define deployment targets within a DataPlane and control environment-specific configurations like +gateway settings and production flags. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Environments are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Environment +metadata: + name: + namespace: # Namespace for grouping environments +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------- | -------- | ------- | --------------------------------------------------------------------------------- | +| `dataPlaneRef` | [DataPlaneRef](#dataplaneref) | No | - | Reference to the DataPlane or ClusterDataPlane where this environment is deployed | +| `isProduction` | boolean | No | false | Indicates if this is a production environment | +| `gateway` | [GatewaySpec](#gatewayspec) | No | - | Gateway configuration specific to this environment | + +### DataPlaneRef + +Reference to a DataPlane or ClusterDataPlane where this environment is deployed. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ---------------------------------------------------------- | +| `kind` | string | Yes | - | Kind of the data plane (`DataPlane` or `ClusterDataPlane`) | +| `name` | string | Yes | - | Name of the data plane resource | + +:::note DataPlaneRef Resolution +If `dataPlaneRef` is not specified, the system resolves a DataPlane using the following fallback order: + +1. DataPlane named "default" in the Environment's namespace +2. ClusterDataPlane named "default" +3. First available DataPlane or ClusterDataPlane + +When `dataPlaneRef` is provided, both `kind` and `name` are required. Set `kind` to `DataPlane` or `ClusterDataPlane`. +::: + +### GatewaySpec + +Gateway configuration for the environment. + +| Field | Type | Required | Default | Description | +| --------- | ----------------------------------------- | -------- | ------- | ----------------------------- | +| `ingress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Ingress gateway configuration | +| `egress` | [GatewayNetworkSpec](#gatewaynetworkspec) | No | - | Egress gateway configuration | + +### GatewayNetworkSpec + +| Field | Type | Required | Default | Description | +| ---------- | ------------------------------------------- | -------- | ------- | --------------------------------------- | +| `external` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | External gateway endpoint configuration | +| `internal` | [GatewayEndpointSpec](#gatewayendpointspec) | No | - | Internal gateway endpoint configuration | + +### GatewayEndpointSpec + +| Field | Type | Required | Default | Description | +| ----------- | ------------------------------------------- | -------- | ------- | -------------------------------------------- | +| `name` | string | Yes | - | Name of the Kubernetes Gateway resource | +| `namespace` | string | Yes | - | Namespace of the Kubernetes Gateway resource | +| `http` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTP listener configuration | +| `https` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | HTTPS listener configuration | +| `tls` | [GatewayListenerSpec](#gatewaylistenerspec) | No | - | TLS listener configuration | + +### GatewayListenerSpec + +| Field | Type | Required | Default | Description | +| -------------- | ------- | -------- | ------- | ----------------------------------- | +| `listenerName` | string | No | - | Name of the listener on the Gateway | +| `port` | integer | Yes | - | Port number for the listener | +| `host` | string | Yes | - | Hostname for the listener | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------- | ------- | ------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the environment state | + +#### Condition Types + +Common condition types for Environment resources: + +- `Ready` - Indicates if the environment is fully provisioned and ready +- `DataPlaneConnected` - Indicates if the environment is connected to its DataPlane +- `GatewayConfigured` - Indicates if gateway configuration has been applied + +## Examples + +### Development Environment + +A simple development environment with just a DataPlane reference: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Environment +metadata: + name: development + namespace: default +spec: + dataPlaneRef: + kind: DataPlane + name: dev-dataplane + isProduction: false +``` + +### Production Environment + +A production environment with gateway configuration: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Environment +metadata: + name: production + namespace: default +spec: + dataPlaneRef: + kind: DataPlane + name: prod-dataplane + isProduction: true + gateway: + ingress: + external: + name: external-gateway + namespace: gateway-system + https: + listenerName: https + port: 443 + host: api.example.com + internal: + name: internal-gateway + namespace: gateway-system + http: + listenerName: http + port: 80 + host: internal.example.com +``` + +### Environment with ClusterDataPlane + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Environment +metadata: + name: staging + namespace: default +spec: + dataPlaneRef: + kind: ClusterDataPlane + name: shared-dataplane + isProduction: false +``` + +## Annotations + +Environments support the following annotations: + +| Annotation | Description | +| ----------------------------- | --------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the environment | + +## Related Resources + +- [DataPlane](./dataplane.md) - Kubernetes cluster hosting the environment +- [ClusterDataPlane](./clusterdataplane.md) - Cluster-scoped data plane for shared environments +- [DeploymentPipeline](./deployment-pipeline.md) - Defines promotion paths between environments diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertrule.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertrule.md new file mode 100644 index 00000000..c8bceb3f --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertrule.md @@ -0,0 +1,244 @@ +--- +title: ObservabilityAlertRule API Reference +description: Monitoring rule that triggers alerts when conditions on metrics or logs are met +--- + +# ObservabilityAlertRule + +An `ObservabilityAlertRule` defines a rule for monitoring runtime observability data (metrics or logs) and triggering alerts when specific conditions are met. + +:::tip Generated Resources +`ObservabilityAlertRule` resources are **generated automatically** by the OpenChoreo control plane during component releases. They are derived from the alert definitions specified in a component's traits and environment-specific parameters are applied via `ReleaseBinding` CR. +::: + +:::important Notification Channel Required +`ObservabilityAlertRule` resources require a [ObservabilityAlertsNotificationChannel](./observabilityalertsnotificationchannel.md) resource to be configured in the relevant environment before they can be created. +::: + +## Usage Recommendation + +You should **not** create `ObservabilityAlertRule` resources manually. Instead, you should define alert rules using a `Trait` (either from the default `observability-alert-rule` trait or a custom trait) within your component definition. This ensures that the alert rules are properly scoped to your component and managed as part of its lifecycle across different environments. + +### Example: Defining Alerts as Traits + +In your `Component` CR, add the alert rule as a trait (using the default `observability-alert-rule` trait). The trait is responsible for generating an `ObservabilityAlertRule` CR with the appropriate `spec.source`, `spec.condition`, and `spec.actions` fields: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service +spec: + # ... other component fields ... + traits: + - name: observability-alert-rule + kind: Trait + instanceName: high-error-rate-log-alert + parameters: + description: "Triggered when error logs count exceeds 50 in 5 minutes." + severity: "critical" + source: + type: "log" + query: "status:error" + condition: + window: 5m + interval: 1m + operator: gt + threshold: 50 +``` + +Override the environment-specific parameters for the alert rule (enablement, notification channels, and incident/AI RCA behavior) in the `ReleaseBinding` CR via `traitEnvironmentConfigs`: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + environment: production + + traitEnvironmentConfigs: + high-error-rate-log-alert: + enabled: true + actions: + notifications: + channels: + - devops-email-notifications + incident: + enabled: true + triggerAiRca: false +``` + +The control plane will then generate the corresponding `ObservabilityAlertRule` resource for each environment where this component is released. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +`ObservabilityAlertRule` resources are namespace-scoped and typically created within the project-environment namespace similar to how resources are created in dataplanes. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertRule +metadata: + name: + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Description | +| ------------- | --------------------------------- | -------- | --------------------------------------------------------------------------------------------- | +| `name` | string | Yes | Unique identifier for the alert rule | +| `description` | string | No | A human-friendly summary of the alert rule | +| `severity` | [AlertSeverity](#alertseverity) | No | Describes how urgent the alert is (`info`, `warning`, `critical`) | +| `enabled` | boolean | No | Toggles whether this alert rule should be evaluated. Defaults to `true` | +| `source` | [AlertSource](#alertsource) | Yes | Specifies the observability source type (log or metric) and query/metric that drives the rule | +| `condition` | [AlertCondition](#alertcondition) | Yes | Controls when an alert should be triggered based on the source data | +| `actions` | [AlertActions](#alertactions) | Yes | Defines where alerts are sent and whether incidents/AI RCA are triggered | + +### AlertSeverity + +| Value | Description | +| ---------- | -------------------- | +| `info` | Informational alerts | +| `warning` | Warning-level alerts | +| `critical` | Critical alerts | + +### AlertSource + +Specifies where and how events are pulled for evaluation. + +| Field | Type | Required | Description | +| -------- | ----------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | [AlertSourceType](#alertsourcetype) | Yes | The telemetry source type (`log`, `metric`) | +| `query` | string | No | The query for log-based alerting (for example, `status:error`). Required when `type=log`. | +| `metric` | string | No | The metric type for metrics-based alerting. Required when `type=metric`. Must be one of the supported metrics (cpu_usage, memory_usage). | + +### AlertSourceType + +| Value | Description | +| -------- | ---------------------------------------------------------------------- | +| `log` | Log-based alerting (powered by observability logs module) | +| `metric` | Usage metrics-based alerting (powered by observability metrics module) | + +### AlertCondition + +Represents the conditions under which an alert should be triggered. + +| Field | Type | Required | Description | +| ----------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------ | +| `window` | duration | Yes | The time window aggregated before comparison (e.g., `5m`) | +| `interval` | duration | Yes | How often the alert rule is evaluated (e.g., `1m`) | +| `operator` | [AlertConditionOperator](#alertconditionoperator) | Yes | Comparison operator used for evaluation | +| `threshold` | integer | Yes | Trigger value for the configured operator (percentage or count, depending on source) | + +### AlertConditionOperator + +| Value | Description | +| ----- | ---------------------------------- | +| `gt` | Greater than threshold | +| `lt` | Less than threshold | +| `gte` | Greater than or equal to threshold | +| `lte` | Less than or equal to threshold | +| `eq` | Equals the threshold | + +### AlertActions + +Defines what happens when an alert rule is triggered. + +| Field | Type | Required | Description | +| --------------- | ----------------------------------------- | -------- | --------------------------------------- | +| `notifications` | [AlertNotifications](#alertnotifications) | Yes | Notification channels to send alerts to | +| `incident` | [AlertIncident](#alertincident) | No | Optional incident and AI RCA behavior | + +### AlertNotifications + +| Field | Type | Required | Description | +| ---------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------- | +| `channels` | string[] | Yes | List of [ObservabilityAlertsNotificationChannel](./observabilityalertsnotificationchannel.md) names to notify | + +At least one notification channel must be configured. If the originating trait or `ReleaseBinding` override omits `actions.notifications.channels`, the control plane resolves the environment’s default notification channel and populates `actions.notifications.channels` in the generated `ObservabilityAlertRule`. + +### AlertIncident + +Represents incident behavior when an alert fires. + +| Field | Type | Required | Description | +| -------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------- | +| `enabled` | boolean | No | Enables incident creation when this alert fires. Defaults to `false`. | +| `triggerAiRca` | boolean | No | Enables AI-powered root cause analysis when an incident is created. Requires `enabled` to be `true`. | + +## Examples + +### Log-based Alert Rule (Generated from trait) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertRule +metadata: + name: error-logs-alert + namespace: my-project-production +spec: + name: Error Logs Detected + description: Triggered when more than 10 error logs are detected in 1 minute. + severity: critical + enabled: true + source: + type: log + query: 'status: "error"' + condition: + window: 1m + interval: 1m + operator: gt + threshold: 10 + actions: + notifications: + channels: + - devops-email-notifications + incident: + enabled: true + triggerAiRca: false +``` + +### Metric-based Alert Rule for CPU usage (Generated from trait) + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertRule +metadata: + name: high-cpu-usage + namespace: my-project-production +spec: + name: High CPU Usage + description: Triggered when average container CPU usage exceeds 80% of limits for 5 minutes. + severity: warning + enabled: true + source: + type: metric + metric: cpu_usage + condition: + window: 5m + interval: 1m + operator: gte + threshold: 80 + actions: + notifications: + channels: + - devops-slack-notifications +``` + +## Related Resources + +- [ObservabilityPlane](./observabilityplane.md) - The infrastructure layer providing observability data +- [ClusterObservabilityPlane](./clusterobservabilityplane.md) - The infrastructure layer providing observability data for cluster-scoped resources +- [ObservabilityAlertsNotificationChannel](./observabilityalertsnotificationchannel.md) - Destinations for alert notifications +- [Trait](./trait.md) - Alert rules can be defined as traits on components diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertsnotificationchannel.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertsnotificationchannel.md new file mode 100644 index 00000000..ef82430e --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityalertsnotificationchannel.md @@ -0,0 +1,202 @@ +--- +title: ObservabilityAlertsNotificationChannel API Reference +description: Environment-bound destination for delivering alert notifications via email or webhook +--- + +# ObservabilityAlertsNotificationChannel + +An `ObservabilityAlertsNotificationChannel` defines a destination for alert notifications. These resources are **environment-bound**, meaning each channel is associated with a specific OpenChoreo environment. + +:::tip Default Notification Channel +In each environment, one `ObservabilityAlertsNotificationChannel` can be marked as the **default**. The first notification channel created in an environment is automatically marked as the default channel. If an [ObservabilityAlertRule](./observabilityalertrule.md) is created without explicitly specifying `actions.notifications.channels`, it will automatically use the default channel for that environment. +::: + +Currently, **email** and **webhook** notifications are supported. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +`ObservabilityAlertsNotificationChannel` resources are namespace-scoped. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Description | +| --------------- | --------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `environment` | string | Yes | Name of the OpenChoreo environment this channel belongs to (Immutable) | +| `isEnvDefault` | boolean | No | If `true`, this is the default channel for the environment. Default channels are used by alert rules that don't specify a channel. Defaults to `false`. First channel created in an environment will be marked as the default | +| `type` | [NotificationChannelType](#notificationchanneltype) | Yes | The type of notification channel (`email` or `webhook`) | +| `emailConfig` | [EmailConfig](#emailconfig) | Required if `type` is `email` | Email configuration | +| `webhookConfig` | [WebhookConfig](#webhookconfig) | Required if `type` is `webhook` | Webhook configuration | + +### NotificationChannelType + +| Value | Description | +| --------- | --------------------------------- | +| `email` | Email notification channel | +| `webhook` | HTTP webhook notification channel | + +### EmailConfig + +| Field | Type | Required | Description | +| ---------- | ------------------------------- | -------- | ------------------------------------------------------ | +| `from` | string | Yes | The sender email address | +| `to` | string[] | Yes | List of recipient email addresses (minimum 1) | +| `smtp` | [SMTPConfig](#smtpconfig) | Yes | SMTP server configuration | +| `template` | [EmailTemplate](#emailtemplate) | Yes | Email subject and body templates using CEL expressions | + +### WebhookConfig + +| Field | Type | Required | Description | +| ----------------- | ---------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `url` | string | Yes | The webhook endpoint URL where alerts will be sent (must be a valid URI) | +| `headers` | map[string][WebhookHeaderValue](#webhookheadervalue) | No | Optional HTTP headers to include in the webhook request. Each header value can be provided inline or via a secret reference. | +| `payloadTemplate` | string | No | Optional JSON payload template using CEL expressions. If not provided, the raw alertDetails object will be sent as JSON. CEL expressions use `${...}` syntax and have access to alert fields: `${alertName}`, `${alertDescription}`, `${alertSeverity}`, `${alertValue}`, etc. Example for Slack: `{"text": "Alert: ${alertName}", "blocks": [...]}` | + +### WebhookHeaderValue + +Defines a header value that can be provided inline or via a secret reference. + +:::note Mutually Exclusive Fields +Exactly one of `value` or `valueFrom` must be set (not both, not neither). +::: + +| Field | Type | Required | Description | +| ----------- | ----------------------------------- | -------- | ----------------------------------------------------------------------------------- | +| `value` | string | No | Inline header value (mutually exclusive with `valueFrom`) | +| `valueFrom` | [SecretValueFrom](#secretvaluefrom) | No | Reference to a secret containing the header value (mutually exclusive with `value`) | + +### SMTPConfig + +| Field | Type | Required | Description | +| ------ | ------------------------------- | -------- | ------------------------------- | +| `host` | string | Yes | SMTP server hostname | +| `port` | integer | Yes | SMTP server port | +| `auth` | [SMTPAuth](#smtpauth) | Yes | SMTP authentication credentials | +| `tls` | [SMTPTLSConfig](#smtptlsconfig) | Yes | TLS configuration for SMTP | + +### SMTPAuth + +| Field | Type | Required | Description | +| ---------- | ----------------------------------- | -------- | ------------------------------------------------------- | +| `username` | [SecretValueFrom](#secretvaluefrom) | Yes | Username for SMTP authentication (inline or secret ref) | +| `password` | [SecretValueFrom](#secretvaluefrom) | Yes | Password for SMTP authentication (inline or secret ref) | + +### SMTPTLSConfig + +| Field | Type | Required | Description | +| -------------------- | ------- | -------- | ------------------------------------------------------------------------------ | +| `insecureSkipVerify` | boolean | No | If `true`, skips TLS certificate verification (not recommended for production) | + +### EmailTemplate + +Defines the email template using CEL expressions. + +| Field | Type | Required | Description | +| --------- | ------ | -------- | ---------------------------------------------------------------------------------------------- | +| `subject` | string | Yes | CEL expression for the email subject (e.g., `"[${alert.severity}] - ${alert.name} Triggered"`) | +| `body` | string | Yes | CEL expression for the email body | + +### SecretValueFrom + +Defines how to obtain a secret value. + +| Field | Type | Required | Description | +| -------------- | ----------------------------- | -------- | ----------------------------------------- | +| `secretKeyRef` | [SecretKeyRef](#secretkeyref) | No | Reference to a key in a Kubernetes secret | + +### SecretKeyRef + +| Field | Type | Required | Description | +| ----------- | ------ | -------- | ----------------------- | +| `name` | string | Yes | Name of the secret | +| `namespace` | string | Yes | Namespace of the secret | +| `key` | string | Yes | Key within the secret | + +## Examples + +### Email Notification Channel + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: prod-email-notifications + namespace: my-org +spec: + environment: production + isEnvDefault: true + type: email + emailConfig: + from: "alerts@example.com" + to: + - "admin@example.com" + - "devops@example.com" + smtp: + host: "smtp.example.com" + port: 587 + auth: + username: + secretKeyRef: + name: smtp-credentials + key: username + password: + secretKeyRef: + name: smtp-credentials + key: password + tls: + insecureSkipVerify: false + template: + subject: "[OpenChoreo] ${alert.severity}: ${alert.name}" + body: "Alert ${alert.name} triggered at ${alert.startsAt}.\n\nDescription: ${alert.description}" +``` + +### Webhook Notification Channel + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: prod-webhook-notifications + namespace: my-org +spec: + environment: production + isEnvDefault: false + type: webhook + webhookConfig: + url: https://alerts.example.com/webhook + headers: + X-OpenChoreo-Source: + value: observer + Authorization: + valueFrom: + secretKeyRef: + name: webhook-token + key: token + payloadTemplate: | + { + "text": "Alert: ${alertName}", + "severity": "${alertSeverity}", + "description": "${alertDescription}", + "value": "${alertValue}" + } +``` + +## Related Resources + +- [ObservabilityAlertRule](./observabilityalertrule.md) - Rules that trigger notifications to these channels +- [Environment](./environment.md) - Notification channels are environment-specific +- [ObservabilityPlane](./observabilityplane.md) - Provides the underlying observability infrastructure +- [ClusterObservabilityPlane](./clusterobservabilityplane.md) - Provides the underlying observability infrastructure for cluster-scoped resources diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityplane.md new file mode 100644 index 00000000..acc60d62 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/observabilityplane.md @@ -0,0 +1,334 @@ +--- +title: ObservabilityPlane API Reference +description: Namespace-scoped observability plane for collecting metrics, logs, and traces +--- + +# ObservabilityPlane + +An ObservabilityPlane represents the infrastructure layer responsible for collecting, storing, and analyzing observability data (metrics, logs, and traces) from OpenChoreo workloads. It provides centralized monitoring and logging capabilities for applications deployed across DataPlanes and build processes running on WorkflowPlanes. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the observability cluster through a WebSocket agent running in the ObservabilityPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ObservabilityPlanes are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityPlane +metadata: + name: + namespace: # Namespace for grouping observability planes +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | +| `planeID` | string | No | CR name | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `observerURL` | string | Yes | - | Base URL of the Observer API in the observability plane cluster | +| `rcaAgentURL` | string | No | - | Base URL of the optional SRE Agent API in the observability plane cluster | + +### PlaneID + +The `planeID` identifies the logical plane this ObservabilityPlane CR connects to. Multiple ObservabilityPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations for multi-tenancy scenarios. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"shared-obs"`, `"monitoring-cluster"`, `"eu-central-1"` + +:::important PlaneID Consistency +The `planeID` in the ObservabilityPlane CR must match the `clusterAgent.planeId` Helm value configured during observability plane installation. If not specified, it defaults to the CR name for backwards compatibility. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the observability cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### ObserverURL + +The base URL of the Observer API service running in the observability plane cluster. This API is used by the external clients to query logs, metrics, traces, alerts, and incidents. + +**Format:** `http://observer.:` + +**Example:** `http://observer.openchoreo.localhost:11080` + +### RCAAgentURL + +The base URL of the optional SRE Agent API service running in the observability plane cluster. When set, external clients can call this endpoint to visualize AI-powered root cause analysis for fired alerts and interact with the SRE Agent with a chat interface. + +**Format:** `http://rca-agent.:` + +**Example:** `http://rca-agent.openchoreo.localhost:11080` + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ----------------------- | ----------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No | Same as parent resource | Namespace of the secret | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | -------------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the ObservabilityPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +## Getting the Agent CA Certificate + +The cluster agent automatically generates its CA certificate when deployed to the observability plane cluster. This certificate is used by the control plane to verify the identity of the observability plane agent during mTLS authentication. + +### Extracting the CA Certificate + +You can extract the CA certificate using: + +```bash +# For multi-cluster setups, specify the observability plane cluster context +kubectl --context get secret cluster-agent-tls \ + -n openchoreo-observability-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d + +# Example for k3d multi-cluster setup: +kubectl --context k3d-openchoreo-op get secret cluster-agent-tls \ + -n openchoreo-observability-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d +``` + +:::important +In multi-cluster setups, you **must** specify the `--context` flag to target the observability plane cluster, not the control plane cluster. The `cluster-agent-tls` secret exists in the observability plane cluster where the agent is deployed. +::: + +### Adding the Certificate to the ObservabilityPlane CR + +You can add the CA certificate to the ObservabilityPlane CR in two ways: + +**Option 1: Inline value (for testing/development)** + +```bash +# Extract the CA certificate from the observability plane cluster +OP_CA_CERT=$(kubectl --context get secret cluster-agent-tls \ + -n openchoreo-observability-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d) + +# Create ObservabilityPlane in the control plane with inline CA certificate +kubectl --context apply -f - < get secret cluster-agent-tls \ + -n openchoreo-observability-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/observabilityplane-ca.crt + +# Create a secret in the control plane cluster +kubectl --context create secret generic observabilityplane-agent-ca \ + --from-file=ca.crt=/tmp/observabilityplane-ca.crt \ + -n my-org + +# Create ObservabilityPlane in the control plane referencing the secret +kubectl --context apply -f - < -n --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch dataplane production-dataplane -n my-org --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ObservabilityPlane","name":"production-observability"}}}' +``` + +### Linking a WorkflowPlane + +```bash +kubectl patch workflowplane -n --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ObservabilityPlane","name":""}}}' +``` + +Example: + +```bash +kubectl patch workflowplane production-workflowplane -n my-org --type merge \ + -p '{"spec":{"observabilityPlaneRef":{"kind":"ObservabilityPlane","name":"production-observability"}}}' +``` + +:::note Cluster-Scoped Resources +ClusterDataPlane and ClusterWorkflowPlane can **only** reference a `ClusterObservabilityPlane` — they cannot reference a namespace-scoped ObservabilityPlane. To link cluster-scoped resources, see the [ClusterObservabilityPlane linking examples](./clusterobservabilityplane.md#linking-planes-to-clusterobservabilityplane). +::: + +## Annotations + +ObservabilityPlanes support the following annotations: + +| Annotation | Description | +| ----------------------------- | ---------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the ObservabilityPlane | + +## Related Resources + +- [ClusterObservabilityPlane](./clusterobservabilityplane.md) - Cluster-scoped variant of ObservabilityPlane +- [DataPlane](./dataplane.md) - Can reference ObservabilityPlane for monitoring +- [ClusterDataPlane](./clusterdataplane.md) - Can reference ObservabilityPlane for monitoring +- [WorkflowPlane](./workflowplane.md) - Can reference ObservabilityPlane for build job monitoring +- [ClusterWorkflowPlane](./clusterworkflowplane.md) - Can reference ObservabilityPlane for build job monitoring +- [ObservabilityAlertRule](./observabilityalertrule.md) - Defines alerting rules for the plane +- [ObservabilityAlertsNotificationChannel](./observabilityalertsnotificationchannel.md) - Defines notification destinations for alerts diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/releasebinding.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/releasebinding.md new file mode 100644 index 00000000..eea13daf --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/releasebinding.md @@ -0,0 +1,319 @@ +--- +title: ReleaseBinding API Reference +description: Binds a ComponentRelease to an environment with configuration overrides +--- + +# ReleaseBinding + +A ReleaseBinding represents an environment-specific deployment of a Component. It binds a specific release to an environment and allows platform engineers to override component parameters, trait configurations, and workload settings for specific environments like development, staging, or production. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ReleaseBindings are namespace-scoped resources created in the same namespace as the Component they deploy. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: - + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| --------------------------------- | ------------------------------------------- | -------- | ------- | ----------------------------------------------------------- | +| `owner` | [ReleaseBindingOwner](#releasebindingowner) | Yes | - | Identifies the component this release binding applies to | +| `environment` | string | Yes | - | Name of the environment (must match an Environment CR) | +| `releaseName` | string | Yes | - | Name of the ComponentRelease to bind to this environment | +| `componentTypeEnvironmentConfigs` | object | No | - | Overrides for ComponentType `environmentConfigs` parameters | +| `traitEnvironmentConfigs` | map[string]object | No | - | Environment-specific trait parameter overrides | +| `workloadOverrides` | [WorkloadOverride](#workloadoverride) | No | - | Overrides for workload configurations | + +### ReleaseBindingOwner + +Identifies which component this release binding is for. + +| Field | Type | Required | Description | +| --------------- | ------ | -------- | ------------------------------------------- | +| `projectName` | string | Yes | Name of the project that owns the component | +| `componentName` | string | Yes | Name of the component to deploy | + +### WorkloadOverride + +Environment-specific configuration overrides for the workload. + +| Field | Type | Required | Description | +| ----------- | --------------------------------------- | -------- | ---------------------------- | +| `container` | [ContainerOverride](#containeroverride) | No | Container-specific overrides | + +#### ContainerOverride + +| Field | Type | Required | Description | +| ------- | --------------------- | -------- | ------------------------------ | +| `env` | [[EnvVar](#envvar)] | No | Environment variable overrides | +| `files` | [[FileVar](#filevar)] | No | File configuration overrides | + +#### EnvVar + +| Field | Type | Required | Description | +| -------------- | ----------------------------- | -------- | --------------------------- | +| `key` | string | Yes | Environment variable name | +| `value` | string | No | Plain text value | +| `secretKeyRef` | [SecretKeyRef](#secretkeyref) | No | Reference to a secret value | + +#### SecretKeyRef + +| Field | Type | Required | Description | +| ------ | ------ | -------- | --------------------------------- | +| `name` | string | Yes | Name of the SecretKeyReference CR | +| `key` | string | Yes | Key within the secret | + +#### FileVar + +| Field | Type | Required | Description | +| -------------- | ----------------------------- | -------- | -------------------------- | +| `key` | string | Yes | File name | +| `mountPath` | string | Yes | Mount path in container | +| `value` | string | No | Plain text file content | +| `secretKeyRef` | [SecretKeyRef](#secretkeyref) | No | Reference to a secret file | + +### Status Fields + +| Field | Type | Default | Description | +| ------------ | ----------- | ------- | ------------------------------------------------------------ | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking ReleaseBinding state | + +#### Condition Types + +Common condition types for ReleaseBinding resources: + +- `Ready` - Indicates if the release binding is ready +- `Deployed` - Indicates if resources have been deployed successfully +- `Synced` - Indicates if the deployment is in sync with the component definition + +## Examples + +### Basic ReleaseBinding + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + + environment: production + releaseName: my-service-v1 +``` + +### ReleaseBinding with Parameter Overrides + +Override ComponentType `environmentConfigs` parameters for production: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + + environment: production + releaseName: my-service-v1 + + componentTypeEnvironmentConfigs: + resources: + requests: + cpu: "500m" + memory: "1Gi" + limits: + cpu: "2000m" + memory: "4Gi" +``` + +### ReleaseBinding with Trait Environment Configs + +Override trait parameters for a specific environment: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + + environment: production + releaseName: my-service-v1 + + traitEnvironmentConfigs: + data-storage: # instanceName of the trait attachment + size: 100Gi + storageClass: production-ssd + iops: 3000 +``` + +### ReleaseBinding with Workload Overrides + +Override workload environment variables and files: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + + environment: production + releaseName: my-service-v1 + + workloadOverrides: + container: + env: + - key: LOG_LEVEL + value: "error" + - key: CACHE_TTL + value: "3600" + + files: + - key: config.yaml + mountPath: /etc/app + value: | + database: + host: prod-db.example.com + port: 5432 + cache: + enabled: true +``` + +### Complete ReleaseBinding Example + +Combining all override types: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + owner: + projectName: default + componentName: my-service + + environment: production + releaseName: my-service-v1 + + # Override ComponentType environmentConfigs + componentTypeEnvironmentConfigs: + resources: + requests: + cpu: "500m" + memory: "1Gi" + limits: + cpu: "2000m" + memory: "4Gi" + + # Override trait parameters + traitEnvironmentConfigs: + data-storage: + size: 100Gi + storageClass: fast-ssd + + backup: + schedule: "0 2 * * *" + retention: 30 + + # Override workload configurations + workloadOverrides: + container: + env: + - key: LOG_LEVEL + value: "info" + - key: MAX_CONNECTIONS + value: "1000" +``` + +## Usage + +ReleaseBindings are typically created for each environment where a component should be deployed: + +```bash +# Development environment +kubectl apply -f my-service-development.yaml + +# Staging environment +kubectl apply -f my-service-staging.yaml + +# Production environment +kubectl apply -f my-service-production.yaml +``` + +View release bindings: + +```bash +# List all release bindings +kubectl get releasebindings + +# Get release bindings for a specific component +kubectl get releasebinding -l openchoreo.dev/component=my-service + +# View release binding details +kubectl describe releasebinding my-service-production +``` + +## Override Hierarchy + +Parameters are resolved in the following order (later overrides earlier): + +1. **ComponentType defaults** - Default values from ComponentType schema +2. **Component parameters** - Values specified in the Component spec +3. **ReleaseBinding overrides** - Environment-specific values in ReleaseBinding + +Example: + +```yaml +# ComponentType defines: replicas default=1 +# Component sets: replicas=3 +# ReleaseBinding (prod) overrides: replicas=5 +# Result: Production deployment will have 5 replicas +``` + +## Best Practices + +1. **Naming Convention**: Use `-` pattern +2. **Environment-Specific Values**: Only override what differs between environments +3. **Resource Limits**: Always set appropriate limits for production environments +4. **Configuration Management**: Use ConfigMaps/Secrets for complex configurations +5. **Trait Management**: Override trait parameters rather than removing/adding traits +6. **Testing**: Validate overrides in lower environments before production +7. **Documentation**: Document why specific overrides are needed + +## Related Resources + +- [Component](../application/component.md) - Defines the component being deployed +- [ComponentRelease](../runtime/componentrelease.md) - Immutable snapshot that ReleaseBinding references for deployment +- [Environment](environment.md) - Defines the target environment +- [ComponentType](componenttype.md) - Defines available parameters for override +- [Trait](trait.md) - Traits whose parameters can be overridden diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcereleasebinding.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcereleasebinding.md new file mode 100644 index 00000000..61747fad --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcereleasebinding.md @@ -0,0 +1,190 @@ +--- +title: ResourceReleaseBinding API Reference +description: Binds a ResourceRelease to an environment and carries per-environment configuration overrides +--- + +# ResourceReleaseBinding + +A ResourceReleaseBinding pins a specific [ResourceRelease](../runtime/resourcerelease.md) to an [Environment](./environment.md) and carries per-environment overrides for the referenced ResourceType template. It is the resource-side counterpart of [ReleaseBinding](./releasebinding.md): platform engineers (or GitOps tooling) author one binding per Resource per environment to control rollout and retention. + +The Resource controller never creates or modifies ResourceReleaseBindings. The `spec.resourceRelease` pin is advanced manually—through `occ resource promote`, `kubectl edit`, or a GitOps commit. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ResourceReleaseBindings are namespace-scoped resources created in the same namespace as the Resource they deploy. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: - + namespace: +``` + +**Short names:** `rrb`, `rrbs` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------------------- | ----------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `owner` | [ResourceReleaseBindingOwner](#resourcereleasebindingowner) | Yes | - | Identifies the Resource this binding deploys (immutable) | +| `environment` | string | Yes | - | Name of the target Environment (immutable; must match an existing Environment in the namespace) | +| `resourceRelease` | string | No | - | Name of the ResourceRelease pinned by this binding. Unset until promoted; the binding stays pending without it | +| `retainPolicy` | string | No | - | Per-environment override for retention. When unset, falls back to the ResourceType's `retainPolicy` (which itself defaults to `Delete`) | +| `resourceTypeEnvironmentConfigs` | object | No | - | Per-environment values for the referenced ResourceType's `environmentConfigs` schema. Validated by the binding controller | + +:::note +`owner` and `environment` are immutable after creation. To re-target a binding, delete and recreate it. +::: + +### ResourceReleaseBindingOwner + +Identifies the Resource this binding deploys. + +| Field | Type | Required | Description | +| -------------- | ------ | -------- | --------------------------------------------------- | +| `projectName` | string | Yes | Name of the project that owns the Resource (min: 1) | +| `resourceName` | string | Yes | Name of the Resource (min: 1) | + +### Status Fields + +| Field | Type | Default | Description | +| ------------ | --------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------- | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking binding state | +| `outputs` | [[ResolvedResourceOutput](#resolvedresourceoutput)] | [] | Resolved output values populated by the binding controller from the underlying RenderedRelease | + +#### ResolvedResourceOutput + +Each entry corresponds to a single output declared on the referenced ResourceType. Picks exactly one of `value`, `secretKeyRef`, or `configMapKeyRef`—matching the source kind on the ResourceType. + +| Field | Type | Required | Description | +| ----------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------- | +| `name` | string | Yes | Output name; matches the declared output on the ResourceType (min: 1) | +| `value` | string | No | Resolved literal value (for `value`-kind outputs) | +| `secretKeyRef` | [SecretKeyRef](./resourcetype.md#secretkeyref) | No | Resolved `{name, key}` reference to a DP-side Secret (for `secretKeyRef`-kind outputs) | +| `configMapKeyRef` | [ConfigMapKeyRef](./resourcetype.md#configmapkeyref) | No | Resolved `{name, key}` reference to a DP-side ConfigMap (for `configMapKeyRef`-kind outputs) | + +Sensitive material never appears in `status.outputs`. Only the `{name, key}` reference transits the control plane. + +#### Condition Types + +| Type | Meaning | +| ----------------- | -------------------------------------------------------------------------------------------------------------- | +| `Synced` | The binding has been rendered and a corresponding `RenderedRelease` is in sync with the pinned ResourceRelease | +| `ResourcesReady` | All declared `resources[]` entries on the ResourceType report healthy (via `readyWhen` or per-Kind heuristic) | +| `OutputsResolved` | Every declared output has been resolved against the applied data-plane state | +| `Ready` | Aggregate condition over `Synced`, `ResourcesReady`, and `OutputsResolved` | +| `Finalizing` | Surfaced during deletion. Reason is `RetainHold` when `retainPolicy: Retain` blocks the finalizer | + +## Examples + +### Basic ResourceReleaseBinding + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: doclet-postgres-development + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-postgres + environment: development + resourceRelease: doclet-postgres-abc12345 +``` + +### Binding With Environment-Specific Overrides + +Use `resourceTypeEnvironmentConfigs` to apply per-environment values declared in the ResourceType's `environmentConfigs` schema. Combine with a `retainPolicy` override for environments where the type-level default does not apply. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: doclet-postgres-production + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-postgres + environment: production + resourceRelease: doclet-postgres-abc12345 + retainPolicy: Retain + resourceTypeEnvironmentConfigs: + memory: "2Gi" + storage: "100Gi" +``` + +### Pending Binding (No Release Pinned Yet) + +A binding can be created before any ResourceRelease has been cut. The binding stays `Synced=False, Reason=ResourceReleaseNotSet` until `spec.resourceRelease` is set: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceReleaseBinding +metadata: + name: doclet-postgres-development + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-postgres + environment: development + # resourceRelease intentionally unset; promote with: + # occ resource promote --env development doclet-postgres +``` + +## Promoting a Release + +Advance `spec.resourceRelease` manually when ready to roll a new release into the target environment. The `occ` CLI bundles the read-current-then-patch step: + +```bash +# Pin the binding to the Resource's latest release +occ resource promote --env development doclet-postgres + +# Equivalent kubectl flow +kubectl get resource doclet-postgres -o jsonpath='{.status.latestRelease.name}' +kubectl patch resourcereleasebinding doclet-postgres-development \ + --type merge -p '{"spec":{"resourceRelease":""}}' +``` + +There is no auto-advance in v1.1. Auto-advance is tracked as a forward-compatible additive `releasePolicy` field for a later release. + +## Retention and Deletion + +`retainPolicy` controls what happens to the emitted data-plane state on binding deletion: + +- **`Delete`** (default-via-fallback) — finalizer removes the emitted manifests as part of deletion +- **`Retain`** — finalizer holds; the binding stays in `Terminating` with `Finalizing` condition `Reason=RetainHold` and the data-plane state persists + +When unset on the binding, the effective policy is inherited from the referenced ResourceType's `spec.retainPolicy` (which itself defaults to `Delete`). + +To finalize a `Retain` binding, flip the policy and the controller's next reconcile will run the cascade: + +```bash +kubectl patch rrb doclet-postgres-production \ + --type merge -p '{"spec":{"retainPolicy":"Delete"}}' +``` + +See [Authoring ResourceTypes](../../../platform-engineer-guide/resource-types.md#retainpolicy) for the full retention pattern. + +## Authorization Context + +The binding controller checks RBAC against `{projectName, resourceName, environment}` for every operation. Cross-project access is rejected: a binding's `spec.owner.projectName` must match the Resource's `spec.owner.projectName`. A request that claims a different project in the body is rejected as a defense-in-depth check. + +## Related Resources + +- [Resource](../application/resource.md) — Owns the binding through `spec.owner.{projectName, resourceName}` +- [ResourceRelease](../runtime/resourcerelease.md) — Immutable snapshot pinned by `spec.resourceRelease` +- [ResourceType](./resourcetype.md) — Source of `resourceTypeEnvironmentConfigs` schema and `retainPolicy` default +- [Environment](./environment.md) — Target environment for the binding +- [RenderedRelease](../runtime/renderedrelease.md) — Final manifests produced by the binding controller +- [ReleaseBinding](./releasebinding.md) — Component-side counterpart +- [Authoring ResourceTypes (PE Guide)](../../../platform-engineer-guide/resource-types.md) diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcetype.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcetype.md new file mode 100644 index 00000000..8451ec2e --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/resourcetype.md @@ -0,0 +1,316 @@ +--- +title: ResourceType API Reference +description: Platform-defined template that provisions managed infrastructure and declares the outputs consumers bind to +--- + +# ResourceType + +A ResourceType is a platform-defined template that governs how managed infrastructure (databases, queues, caches, object stores) is provisioned on the data plane and exposed to consumers. It captures the manifests the platform emits, the parameters developers can supply, the environment-specific overrides bindings can apply, and the named outputs consumers wire into their containers. + +Resources reference a ResourceType (or [ClusterResourceType](./clusterresourcetype.md)) by name; each [ResourceReleaseBinding](./resourcereleasebinding.md) then renders the template per environment and applies the manifests to the data plane. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ResourceTypes are namespace-scoped resources typically created in a namespace to be available for Resources in that namespace. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceType +metadata: + name: + namespace: +``` + +**Short names:** `rt`, `rts` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | ----------------------------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `parameters` | [SchemaSection](#schemasection) | No | - | Schema for `Resource.spec.parameters` values. Validated by the Resource controller; failures surface via `status.conditions` | +| `environmentConfigs` | [SchemaSection](#schemasection) | No | - | Schema for `ResourceReleaseBinding.spec.resourceTypeEnvironmentConfigs` per-environment overrides | +| `retainPolicy` | string | No | `Delete` | Default retention behavior for bindings of this type: `Delete` removes emitted DP-side state on binding delete; `Retain` holds the binding's finalizer | +| `outputs` | [[ResourceTypeOutput](#resourcetypeoutput)] | No | [] | Named outputs that workloads consume through `Workload.spec.dependencies.resources[].envBindings` and `fileBindings` | +| `resources` | [[ResourceTypeManifest](#resourcetypemanifest)] | Yes | - | Kubernetes manifest templates the provisioner emits on the data plane. At least one entry is required | + +### ResourceTypeOutput + +Declares a single named output. Each output picks exactly one of `value`, `secretKeyRef`, or `configMapKeyRef`—setting more than one is a validation error. + +| Field | Type | Required | Default | Description | +| ----------------- | ----------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `name` | string | Yes | - | Unique output identifier within the ResourceType. Referenced by consumer `envBindings` / `fileBindings` keys (min: 1) | +| `value` | string | No | - | Literal value or `${...}` CEL expression evaluating to a string. Use for non-sensitive data; the resolved value transits to the CP | +| `secretKeyRef` | [SecretKeyRef](#secretkeyref) | No | - | Reference to a data-plane Secret. Use for sensitive credentials; only `{name, key}` transits to the CP | +| `configMapKeyRef` | [ConfigMapKeyRef](#configmapkeyref) | No | - | Reference to a data-plane ConfigMap. Both `name` and `key` support `${...}` CEL templating | + +`value`, `secretKeyRef.{name,key}`, and `configMapKeyRef.{name,key}` all accept `${...}` CEL expressions evaluated against `metadata.*`, `parameters.*`, `environmentConfigs.*`, `dataplane.*`, `gateway.*`, and `applied..status.*`. + +### ResourceTypeManifest + +Defines a single Kubernetes manifest the ResourceType emits on the data plane. + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | Yes | - | Unique identifier within the ResourceType. Referenced by `readyWhen` and `outputs` via `applied..status.*` (min: 1) | +| `includeWhen` | string | No | - | `${...}`-wrapped CEL expression returning a boolean. When `false`, the entry is omitted from the render and any prior object is GC'd | +| `template` | object | Yes | - | Kubernetes resource template with `${...}` CEL expressions for dynamic values | +| `readyWhen` | string | No | - | `${...}`-wrapped CEL expression evaluating after the manifest has been applied. When set, gates `ResourceReleaseBinding.status.conditions[ResourcesReady]` | + +When `readyWhen` is unset, readiness falls back to the per-Kind health heuristic in `RenderedRelease.status.resources[].healthStatus`. + +#### CEL Expression Surface + +Templates use CEL expressions enclosed in `${...}`. The available context bindings depend on the field being evaluated: + +| Context | In `template` | In `includeWhen` | In `readyWhen` | In `outputs` | Description | +| ---------------------- | :-----------: | :--------------: | :------------: | :----------: | ----------------------------------------------------------------------------------------------------- | +| `metadata.*` | yes | yes | yes | yes | Platform-injected naming, namespace, resource/project/env names + UIDs, labels, annotations | +| `parameters.*` | yes | yes | yes | yes | Values from `Resource.spec.parameters` with schema defaults applied | +| `environmentConfigs.*` | yes | yes | yes | yes | Values from `ResourceReleaseBinding.spec.resourceTypeEnvironmentConfigs` with schema defaults applied | +| `environment.*` | yes | yes | yes | yes | Per-environment surface including the merged effective gateway for this environment | +| `dataplane.*` | yes | yes | yes | yes | DataPlane attributes (`secretStore`, raw gateway, observability reference) | +| `gateway.*` | yes | yes | yes | yes | Effective gateway (Environment override merged onto DataPlane default) | +| `applied..*` | no | no | yes | yes | Status of resources after they have been applied to the data plane—reference by manifest `id` | + +##### metadata + +Platform-computed metadata for resource generation: + +| Field | Type | Description | +| ---------------------------- | ------ | -------------------------------------------------------------------------- | +| `metadata.name` | string | Platform-computed base name `{resource}-{env}-{hash}` for rendered objects | +| `metadata.namespace` | string | DP-side project-env mapped namespace | +| `metadata.resourceNamespace` | string | CP namespace where the Resource CR lives | +| `metadata.resourceName` | string | Name of the owning Resource | +| `metadata.resourceUID` | string | UID of the owning Resource | +| `metadata.projectName` | string | Name of the project | +| `metadata.projectUID` | string | UID of the project | +| `metadata.environmentName` | string | Name of the environment | +| `metadata.environmentUID` | string | UID of the environment | +| `metadata.dataPlaneName` | string | Name of the target data plane | +| `metadata.dataPlaneUID` | string | UID of the target data plane | +| `metadata.labels` | map | Platform-injected standard labels propagated to every rendered object | +| `metadata.annotations` | map | Annotations propagated from the Resource CR | + +For the full CEL surface (built-in functions, helpers), see the [CEL Reference](../../cel/context-variables.md). + +### SchemaSection + +Both `parameters` and `environmentConfigs` use the `SchemaSection` type, which holds a schema in `openAPIV3Schema` format: + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | -------------------------------------- | +| `openAPIV3Schema` | object | No | - | Standard OpenAPI v3 JSON Schema format | + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + version: + type: string + enum: ["7", "8"] + default: "8" +``` + +### SecretKeyRef + +References a key inside a Kubernetes Secret on the data plane. + +| Field | Type | Required | Description | +| ------ | ------ | -------- | ---------------------------------------------------------------- | +| `name` | string | Yes | Name of the Secret (supports `${...}` CEL templating; min: 1) | +| `key` | string | Yes | Key within the Secret (supports `${...}` CEL templating; min: 1) | + +### ConfigMapKeyRef + +References a key inside a Kubernetes ConfigMap on the data plane. + +| Field | Type | Required | Description | +| ------ | ------ | -------- | ------------------------------------------------------------------- | +| `name` | string | Yes | Name of the ConfigMap (supports `${...}` CEL templating; min: 1) | +| `key` | string | Yes | Key within the ConfigMap (supports `${...}` CEL templating; min: 1) | + +### Status Fields + +ResourceType currently has no status fields. + +## Examples + +### Simple Valkey Cache + +A namespace-scoped ResourceType emitting a StatefulSet-backed Valkey cache with a Secret, Service, and a single output for each connection detail. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceType +metadata: + name: valkey-cache + namespace: default +spec: + parameters: + openAPIV3Schema: + type: object + properties: + version: + type: string + enum: ["7", "8"] + default: "8" + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + memory: + type: string + default: "128Mi" + + retainPolicy: Delete + + outputs: + - name: host + value: "${metadata.name}.${metadata.namespace}.svc.cluster.local" + - name: port + value: "6379" + - name: password + secretKeyRef: + name: "${metadata.name}-creds" + key: password + + resources: + - id: password-secret + template: + apiVersion: v1 + kind: Secret + metadata: + name: ${metadata.name}-creds + namespace: ${metadata.namespace} + labels: ${metadata.labels} + type: Opaque + stringData: + password: "change-me" + + - id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + selector: + app: ${metadata.name} + ports: + - name: valkey + port: 6379 + targetPort: 6379 + + - id: statefulset + readyWhen: "${applied.statefulset.status.readyReplicas == applied.statefulset.status.replicas && applied.statefulset.status.replicas > 0}" + template: + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + serviceName: ${metadata.name} + replicas: 1 + selector: + matchLabels: + app: ${metadata.name} + template: + metadata: + labels: + app: ${metadata.name} + spec: + containers: + - name: valkey + image: valkey/valkey:${parameters.version}-alpine + resources: + limits: + memory: ${environmentConfigs.memory} + ports: + - containerPort: 6379 + name: valkey +``` + +### ResourceType With Conditional Resources + +`includeWhen` lets a single template handle both bare and admin-UI variants without duplicating templates: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceType +metadata: + name: redis-with-admin + namespace: default +spec: + environmentConfigs: + openAPIV3Schema: + type: object + properties: + adminEnabled: + type: boolean + default: false + + resources: + # ... bare cache resources omitted ... + + - id: admin-deployment + includeWhen: "${environmentConfigs.adminEnabled && has(gateway.ingress.external)}" + template: + # ... admin UI Deployment ... + + - id: admin-route + includeWhen: "${environmentConfigs.adminEnabled && has(gateway.ingress.external)}" + template: + # ... HTTPRoute exposing the admin UI ... +``` + +## Usage + +Developers reference a ResourceType from a Resource: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Resource +metadata: + name: order-cache + namespace: default +spec: + owner: + projectName: order-service + type: + kind: ResourceType + name: valkey-cache + parameters: + version: "8" +``` + +To deploy the Resource into an environment, a platform engineer creates a [ResourceReleaseBinding](./resourcereleasebinding.md) pinning a specific [ResourceRelease](../runtime/resourcerelease.md). + +## Best Practices + +1. **Generate credentials on the data plane.** Use ExternalSecret + a generator (Password, ECDSAKey, etc.) so secret material never enters the control plane. Surface credentials through `secretKeyRef` outputs. +2. **Match `readyWhen` to the provisioner.** For Crossplane claims, check the claim's `Ready` condition. For StatefulSets, check `readyReplicas == replicas`. Leave `readyWhen` unset only when the per-Kind health heuristic captures provisioner semantics correctly. +3. **Set `retainPolicy: Retain` on stateful templates.** Defaults are inherited by every binding of this type; per-environment overrides remain available. +4. **Keep outputs developer-friendly.** Compose useful values like full connection URLs through `value:` CEL when possible (for example, using `parameters.*` and `applied..status.*`)—but render credential-bearing values on the data plane via ExternalSecret templating so secret material does not transit the control plane. +5. **Document outputs.** Use `openchoreo.dev/description` annotations on the ResourceType to document the contract. + +## Related Resources + +- [ClusterResourceType](./clusterresourcetype.md) — Cluster-scoped variant of ResourceType +- [Resource](../application/resource.md) — Developer-facing CRD that references a ResourceType +- [ResourceRelease](../runtime/resourcerelease.md) — Immutable snapshot cut by the Resource controller +- [ResourceReleaseBinding](./resourcereleasebinding.md) — Per-environment binding that renders this template +- [Workload](../application/workload.md) — Consumes ResourceType outputs via `dependencies.resources[]` +- [Authoring ResourceTypes (PE Guide)](../../../platform-engineer-guide/resource-types.md) diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/secretreference.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/secretreference.md new file mode 100644 index 00000000..b8b19cd4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/secretreference.md @@ -0,0 +1,258 @@ +--- +title: SecretReference API Reference +description: Indirect reference to secrets stored in an external vault, usable by applications, workflows, and infrastructure resources +--- + +# SecretReference + +A SecretReference defines a mapping between external secret store entries and Kubernetes Secrets. It allows platform +engineers to declaratively specify how secrets from external providers (like HashiCorp Vault, AWS Secrets Manager, etc.) +should be synchronized into Kubernetes Secrets for use by applications. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +SecretReferences are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: + namespace: # Namespace for grouping secret references +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------- | ---------------------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `targetPlane` | [TargetPlaneRef](#targetplaneref) | No | - | Plane whose external secret store holds the secret value. When unset, the secret may live in any store reachable through `spec.data` refs. | +| `template` | [SecretTemplate](#secrettemplate) | Yes | - | Defines the structure of the resulting Kubernetes Secret | +| `data` | [][SecretDataSource](#secretdatasource) | Yes | - | Mapping of secret keys to external secret references (min: 1) | +| `refreshInterval` | [duration](https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration) | No | `1h` | How often to reconcile/refresh the secret from external stores | + +### TargetPlaneRef + +Identifies the plane whose external secret store holds the secret value referenced by this SecretReference. This is the same plane that `occ secret create --target-plane` pushes the value to. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ------------------------------------------------------------------------------------------- | +| `kind` | string | Yes | - | Plane kind. One of `WorkflowPlane`, `ClusterWorkflowPlane`, `DataPlane`, `ClusterDataPlane` | +| `name` | string | Yes | - | Name of the target plane resource | + +### SecretTemplate + +Defines the structure and metadata of the resulting Kubernetes Secret. + +| Field | Type | Required | Default | Description | +| ---------- | --------------------------------- | -------- | -------- | -------------------------------------------------- | +| `type` | string | No | `Opaque` | Type of the Kubernetes Secret | +| `metadata` | [SecretMetadata](#secretmetadata) | No | - | Additional metadata to add to the generated secret | + +#### Supported Secret Types + +- `Opaque` - Arbitrary user-defined data (default) +- `kubernetes.io/dockerconfigjson` - Docker registry credentials +- `kubernetes.io/dockercfg` - Legacy Docker registry credentials +- `kubernetes.io/basic-auth` - Basic authentication credentials +- `kubernetes.io/ssh-auth` - SSH authentication credentials +- `kubernetes.io/tls` - TLS certificate and key +- `bootstrap.kubernetes.io/token` - Bootstrap token data + +### SecretMetadata + +Additional metadata to add to the generated Kubernetes Secret. + +| Field | Type | Required | Default | Description | +| ------------- | ----------------- | -------- | ------- | -------------------------------- | +| `annotations` | map[string]string | No | - | Annotations to add to the secret | +| `labels` | map[string]string | No | - | Labels to add to the secret | + +### SecretDataSource + +Maps a key in the Kubernetes Secret to a value from an external secret store. + +| Field | Type | Required | Default | Description | +| ----------- | ----------------------------------- | -------- | ------- | ------------------------------------------- | +| `secretKey` | string | Yes | - | Key name in the resulting Kubernetes Secret | +| `remoteRef` | [RemoteReference](#remotereference) | Yes | - | Reference to the external secret location | + +### RemoteReference + +Points to a specific secret in an external secret store. + +| Field | Type | Required | Default | Description | +| ---------- | ------ | -------- | ------- | ------------------------------------------------------------------ | +| `key` | string | Yes | - | Path in the external secret store (e.g., `secret/data/github/pat`) | +| `property` | string | No | - | Specific field within the secret (e.g., `token`) | +| `version` | string | No | - | Version of the secret to fetch (provider-specific) | + +### Status Fields + +| Field | Type | Default | Description | +| ----------------- | -------------------------------------------------------------------------------- | ------- | ------------------------------------------------------ | +| `conditions` | [][Condition](https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Condition) | [] | Standard Kubernetes conditions tracking the sync state | +| `lastRefreshTime` | [Time](https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Time) | - | When the secret reference was last processed/refreshed | +| `secretStores` | [][SecretStoreReference](#secretstorereference) | [] | Tracks which secret stores are using this reference | + +#### SecretStoreReference + +Tracks where this SecretReference is being used. + +| Field | Type | Description | +| ----------- | ------ | -------------------------------------------------------- | +| `name` | string | Name of the secret store | +| `namespace` | string | Namespace where the ExternalSecret was created | +| `kind` | string | Kind of resource (ExternalSecret, ClusterExternalSecret) | + +#### Condition Types + +Common condition types for SecretReference resources: + +- `Ready` - Indicates if the secret has been successfully synchronized +- `SecretSynced` - Indicates if the secret data has been fetched from the external store + +## Examples + +### Basic Opaque Secret + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: github-credentials + namespace: default +spec: + targetPlane: + kind: ClusterWorkflowPlane + name: default + template: + type: Opaque + data: + - secretKey: token + remoteRef: + key: secret/data/github/pat + property: token +``` + +### Docker Registry Credentials + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: docker-registry-creds + namespace: default +spec: + template: + type: kubernetes.io/dockerconfigjson + metadata: + labels: + app: my-service + data: + - secretKey: .dockerconfigjson + remoteRef: + key: secret/data/docker/registry + property: config + refreshInterval: 30m +``` + +### TLS Certificate + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: api-tls-cert + namespace: default +spec: + template: + type: kubernetes.io/tls + metadata: + annotations: + cert-manager.io/common-name: api.example.com + data: + - secretKey: tls.crt + remoteRef: + key: secret/data/certs/api + property: certificate + - secretKey: tls.key + remoteRef: + key: secret/data/certs/api + property: private_key +``` + +### Database Credentials with Version + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: database-credentials + namespace: default +spec: + template: + type: Opaque + metadata: + labels: + app: backend + component: database + data: + - secretKey: username + remoteRef: + key: secret/data/db/postgres + property: username + version: "2" + - secretKey: password + remoteRef: + key: secret/data/db/postgres + property: password + version: "2" + refreshInterval: 15m +``` + +### Multiple Secrets from Different Paths + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: SecretReference +metadata: + name: app-secrets + namespace: default +spec: + template: + type: Opaque + data: + - secretKey: API_KEY + remoteRef: + key: secret/data/external-api/credentials + property: api_key + - secretKey: JWT_SECRET + remoteRef: + key: secret/data/auth/jwt + property: secret + - secretKey: ENCRYPTION_KEY + remoteRef: + key: secret/data/encryption/keys + property: primary + refreshInterval: 1h +``` + +## Annotations + +SecretReferences support the following annotations: + +| Annotation | Description | +| ----------------------------- | -------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the secret reference | + +## Related Resources + +- [Workload](../application/workload.md) - References SecretReference for injecting secrets into deployments +- [ReleaseBinding](./releasebinding.md) - References SecretReference for environment-specific secret configuration diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/trait.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/trait.md new file mode 100644 index 00000000..9f0e5c50 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/trait.md @@ -0,0 +1,477 @@ +--- +title: Trait API Reference +description: Namespace-scoped cross-cutting concern that extends component capabilities +--- + +# Trait + +A Trait represents a cross-cutting concern that can be attached to components to add additional capabilities like +persistent storage, observability, security policies, or service mesh integration. Traits modify or extend the resources +generated by ComponentTypes without requiring changes to the ComponentType itself. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Traits are namespace-scoped resources typically created in a namespace to be available for components in that namespace. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: + namespace: # Namespace for grouping traits +``` + +**Short names:** `trait`, `traits` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------- | +| `parameters` | [SchemaSection](#schemasection) | No | - | Developer-facing configurable parameters for this trait | +| `environmentConfigs` | [SchemaSection](#schemasection) | No | - | Parameters that can be overridden per environment | +| `validations` | [[ValidationRule](./componenttype.md#validationrule)] | No | [] | Deprecated alias for `preRenderValidations` (identical semantics); set only one of the two | +| `preRenderValidations` | [[ValidationRule](./componenttype.md#validationrule)] | No | [] | CEL-based rules evaluated before rendering against the trait's static context | +| `postRenderValidations` | [[PostRenderValidation](./componenttype.md#postrendervalidation)] | No | [] | CEL-based rules evaluated after all traits are applied, against the final rendered resources | +| `creates` | [[TraitCreate](#traitcreate)] | No | [] | New Kubernetes resources to create | +| `patches` | [[TraitPatch](#traitpatch)] | No | [] | Modifications to existing ComponentType resources | +| `removes` | [[TraitRemove](#traitremove)] | No | [] | Whole resources produced by the ComponentType or earlier traits to delete from the rendered output | + +### SchemaSection + +Defines the schema for configurable parameters using standard JSON Schema. + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | ------------------------------------------------------- | +| `openAPIV3Schema` | object | No | - | Standard OpenAPI v3 JSON Schema for defining parameters | + +**Example:** + +```yaml +parameters: + openAPIV3Schema: + type: object + properties: + volumeName: + type: string + mountPath: + type: string + containerName: + type: string + default: "app" + +environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: "10Gi" + storageClass: + type: string + default: "standard" +``` + +### TraitCreate + +Defines a new Kubernetes resource to be created when the trait is applied. + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ----------- | --------------------------------------------------------------------- | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `includeWhen` | string | No | - | CEL expression determining if resource should be created | +| `forEach` | string | No | - | CEL expression for generating multiple resources from list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if `forEach` is set) | +| `template` | object | Yes | - | Kubernetes resource template with CEL expressions | + +CEL expressions in trait templates have access to the following context variables: + +##### metadata + +Platform-computed metadata for resource generation (same as ComponentType): + +| Field | Type | Description | +| ----------------------------- | ------ | ------------------------------------------------------------------- | +| `metadata.name` | string | Base name for generated resources (e.g., `my-service-dev-a1b2c3d4`) | +| `metadata.namespace` | string | Target namespace for resources | +| `metadata.componentNamespace` | string | Target namespace of the component | +| `metadata.componentName` | string | Name of the component | +| `metadata.componentUID` | string | Unique identifier of the component | +| `metadata.projectName` | string | Name of the project | +| `metadata.projectUID` | string | Unique identifier of the project | +| `metadata.environmentName` | string | Name of the environment (e.g., `development`, `production`) | +| `metadata.environmentUID` | string | Unique identifier of the environment | +| `metadata.dataPlaneName` | string | Name of the data plane | +| `metadata.dataPlaneUID` | string | Unique identifier of the data plane | +| `metadata.labels` | map | Common labels to add to all resources | +| `metadata.annotations` | map | Common annotations to add to all resources | +| `metadata.podSelectors` | map | Platform-injected selectors for pod identity | + +##### trait + +Trait-specific metadata: + +| Field | Type | Description | +| -------------------- | ------ | ---------------------------------------------------------------- | +| `trait.name` | string | Name of the trait (e.g., `persistent-volume`) | +| `trait.instanceName` | string | Unique instance name within the component (e.g., `data-storage`) | + +##### parameters + +Trait instance parameters from `Component.spec.traits[].parameters` with schema defaults applied. Use for static configuration that doesn't change across environments. + +##### environmentConfigs + +Environment-specific configuration from `ReleaseBinding.spec.traitEnvironmentConfigs[instanceName]` with schema defaults applied. Use for values that vary per environment. + +##### dataplane + +Data plane configuration: + +| Field | Type | Description | +| ----------------------------- | ------ | --------------------------------------------------- | +| `dataplane.secretStore` | string | Name of the ClusterSecretStore for external secrets | +| `dataplane.publicVirtualHost` | string | Public virtual host for external access | + +##### Helper Functions + +| Function | Description | +| --------------------------- | ------------------------------------------------------------------------------------------ | +| `oc_generate_name(args...)` | Generate valid Kubernetes names with hash suffix for uniqueness | +| `oc_hash(string)` | Generate 8-character FNV-32a hash from input string | +| `oc_merge(map1, map2, ...)` | Shallow merge maps (later maps override earlier ones) | +| `oc_omit()` | Remove field/key from output when used in conditional expressions | +| `oc_dns_label(args...)` | Generate RFC 1123-compliant DNS label (≤63 chars) with hash suffix for HTTPRoute hostnames | + +### TraitPatch + +Defines modifications to existing resources generated by the ComponentType. + +| Field | Type | Required | Default | Description | +| ------------- | ------------------------------------------- | -------- | ----------- | ---------------------------------------------------------------- | +| `forEach` | string | No | - | CEL expression for iterating over a list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if forEach set) | +| `target` | [PatchTarget](#patchtarget) | Yes | - | Specifies which resource to patch | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | +| `operations` | [[JSONPatchOperation](#jsonpatchoperation)] | Yes | - | List of JSONPatch operations to apply | + +### TraitRemove + +Deletes whole resources produced by the ComponentType or earlier traits from the rendered output. Within a single +trait, removes run after its `creates` and `patches`. The primary workload cannot be removed: the admission webhook +rejects removes targeting `Deployment`, `StatefulSet`, `DaemonSet`, `CronJob`, or `Job` in the `apps`/`batch` groups. + +| Field | Type | Required | Default | Description | +| ------------- | --------------------------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------------- | +| `forEach` | string | No | - | CEL expression for iterating over a list | +| `var` | string | No | - | Variable name for `forEach` iterations (required if forEach set) | +| `target` | [PatchTarget](#patchtarget) | Yes | - | Resources to remove, selected by GVK with an optional `where` filter; matching resources are deleted entirely | +| `targetPlane` | string | No | `dataplane` | Target plane: `dataplane` or `observabilityplane` | + +**Example:** + +```yaml +removes: + - target: + group: "" + version: v1 + kind: ConfigMap + where: ${resource.metadata.name.endsWith("-debug")} +``` + +### PatchTarget + +Specifies which Kubernetes resource to modify. + +| Field | Type | Required | Description | +| --------- | ------ | -------- | --------------------------------------------------------------------------- | +| `group` | string | Yes | API group (e.g., `apps`, `batch`). Use empty string `""` for core resources | +| `version` | string | Yes | API version (e.g., `v1`, `v1beta1`) | +| `kind` | string | Yes | Resource type (e.g., `Deployment`, `StatefulSet`) | +| `where` | string | No | CEL expression to filter which resources to patch | + +### JSONPatchOperation + +Defines a modification using JSONPatch format (RFC 6902) with OpenChoreo extensions. + +| Field | Type | Required | Description | +| ------- | ------ | -------- | ------------------------------------- | +| `op` | string | Yes | Operation: `add`, `replace`, `remove` | +| `path` | string | Yes | JSON Pointer to the field (RFC 6901) | +| `value` | any | No | Value to set (not used for `remove`) | + +#### Supported Operations + +- **add**: Add a new field or array element +- **replace**: Replace an existing field value +- **remove**: Delete a field + +#### Path Syntax + +Supports array filters for targeting specific elements: + +``` +/spec/containers[?(@.name=='app')]/volumeMounts/- +``` + +## Examples + +### Persistent Volume Trait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: persistent-volume + namespace: default +spec: + parameters: + openAPIV3Schema: + type: object + properties: + volumeName: + type: string + mountPath: + type: string + containerName: + type: string + default: "app" + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: "10Gi" + storageClass: + type: string + default: "standard" + + creates: + - template: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: ${metadata.name}-${trait.instanceName} + namespace: ${metadata.namespace} + spec: + accessModes: + - ReadWriteOnce + storageClassName: ${environmentConfigs.storageClass} + resources: + requests: + storage: ${environmentConfigs.size} + + patches: + - target: + group: apps + version: v1 + kind: Deployment + operations: + - op: add + path: /spec/template/spec/containers[?(@.name=='${parameters.containerName}')]/volumeMounts/- + value: + name: ${parameters.volumeName} + mountPath: ${parameters.mountPath} + - op: add + path: /spec/template/spec/volumes/- + value: + name: ${parameters.volumeName} + persistentVolumeClaim: + claimName: ${metadata.name}-${trait.instanceName} +``` + +### Sidecar Container Trait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: logging-sidecar + namespace: default +spec: + parameters: + openAPIV3Schema: + type: object + properties: + logPath: + type: string + default: "/var/log/app" + sidecarImage: + type: string + default: "fluent/fluent-bit:latest" + + patches: + - target: + group: apps + version: v1 + kind: Deployment + operations: + - op: add + path: /spec/template/spec/containers/- + value: + name: log-collector + image: ${parameters.sidecarImage} + volumeMounts: + - name: logs + mountPath: ${parameters.logPath} + - op: add + path: /spec/template/spec/volumes/- + value: + name: logs + emptyDir: {} +``` + +### Resource Limits Trait + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: resource-limits + namespace: default +spec: + environmentConfigs: + openAPIV3Schema: + type: object + properties: + cpuLimit: + type: string + default: "1000m" + memoryLimit: + type: string + default: "512Mi" + + patches: + - target: + group: apps + version: v1 + kind: Deployment + operations: + - op: add + path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/cpu + value: ${environmentConfigs.cpuLimit} + - op: add + path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/memory + value: ${environmentConfigs.memoryLimit} +``` + +### Multi-Container Trait with forEach + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: multi-volume + namespace: default +spec: + parameters: + openAPIV3Schema: + type: object + properties: + mounts: + type: array + items: + type: object + properties: + name: + type: string + path: + type: string + + patches: + - target: + group: apps + version: v1 + kind: Deployment + forEach: ${parameters.mounts} + var: mount + operations: + - op: add + path: /spec/template/spec/volumes/- + value: + name: ${mount.name} + emptyDir: {} + - op: add + path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/- + value: + name: ${mount.name} + mountPath: ${mount.path} +``` + +## Usage + +Developers attach traits to components in the Component specification: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Component +metadata: + name: my-service +spec: + componentType: + kind: ComponentType + name: deployment/service + + traits: + - name: persistent-volume + kind: Trait + instanceName: data-storage + parameters: + volumeName: data + mountPath: /var/data + containerName: app +``` + +Platform engineers can set trait `environmentConfigs` in ReleaseBinding: + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: my-service-production + namespace: default +spec: + environment: production + owner: + componentName: my-service + projectName: default + + traitEnvironmentConfigs: + data-storage: # keyed by instanceName + size: 100Gi + storageClass: production-ssd +``` + +## Best Practices + +1. **Single Responsibility**: Each trait should address one cross-cutting concern +2. **Naming**: Use descriptive names that indicate the capability being added +3. **Parameters**: Provide sensible defaults for all non-required parameters +4. **Target Specificity**: Use `where` clauses when needed to avoid unintended modifications +5. **Testing**: Test traits with different ComponentTypes to ensure compatibility +6. **Documentation**: Document which ComponentTypes a trait is designed to work with +7. **Idempotency**: Ensure traits can be safely applied multiple times + +## Trait vs ComponentType + +| Aspect | ComponentType | Trait | +| ------------ | ---------------------------------- | -------------------------------------------------------- | +| Purpose | Defines core deployment pattern | Adds cross-cutting concerns | +| Scope | One per component | Multiple can be attached to one component | +| Resources | Creates primary workload resources | Creates supplementary resources or patches existing ones | +| Modification | Determines base resource structure | Modifies or extends ComponentType resources | +| Examples | Service, WebApp, ScheduledTask | Persistent Storage, Logging, Security | + +## Related Resources + +- [ClusterTrait](./clustertrait.md) - Cluster-scoped variant of Trait +- [ComponentType](componenttype.md) - Defines the base deployment pattern +- [Component](../application/component.md) - Attaches traits to components +- [ReleaseBinding](releasebinding.md) - Binds a ComponentRelease to an environment with trait parameter overrides diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflow.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflow.md new file mode 100644 index 00000000..d64f6f1f --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflow.md @@ -0,0 +1,484 @@ +--- +title: Workflow API Reference +description: Platform engineer-defined automation template for builds, pipelines, and other tasks +--- + +# Workflow + +A Workflow is a platform engineer-defined template for running automation tasks in OpenChoreo. Workflows provide +a flexible mechanism to execute any type of automation — component builds, infrastructure provisioning, data pipelines, +end-to-end testing, package publishing, and more. + +Workflows define a parameter schema, optional external references, and a run template that references a +ClusterWorkflowTemplate, bridging the control plane and workflow plane. + +A Workflow becomes a **component workflow** when it carries the `openchoreo.dev/workflow-type: "component"` label +and is listed in a ComponentType's `allowedWorkflows`. See [CI Governance](../../../platform-engineer-guide/workflows/ci-governance.md) +for details. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +Workflows are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: + namespace: +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | --------------------------------------- | -------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `workflowPlaneRef` | [WorkflowPlaneRef](#workflowplaneref) | No | `{kind: "ClusterWorkflowPlane", name: "default"}` | Reference to the WorkflowPlane or ClusterWorkflowPlane for this workflow's operations | +| `parameters` | [SchemaSection](#schemasection) | No | - | Developer-facing parameter schema | +| `runTemplate` | object | Yes | - | Kubernetes resource template (typically Argo Workflow) with template variables for runtime evaluation | +| `resources` | [][WorkflowResource](#workflowresource) | No | - | Additional Kubernetes resources to create alongside the workflow run | +| `externalRefs` | [][ExternalRef](#externalref) | No | - | References to external CRs resolved at runtime and injected into the CEL context | +| `ttlAfterCompletion` | string | No | - | Auto-delete duration after workflow run completion (e.g., `90d`, `1h30m`). Pattern: `^(\d+d)?(\d+h)?(\d+m)?(\d+s)?$` | + +### WorkflowPlaneRef + +References the workflow plane where workflows execute. This field is **immutable** after creation. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | ----------------------------------------------------------------------------- | +| `kind` | string | Yes | - | `WorkflowPlane` (namespace-scoped) or `ClusterWorkflowPlane` (cluster-scoped) | +| `name` | string | Yes | - | Name of the WorkflowPlane or ClusterWorkflowPlane resource | + +If not specified, the controller resolves the workflow plane in order: + +1. `WorkflowPlane` named `default` in the same namespace +2. `ClusterWorkflowPlane` named `default` (cluster-scoped fallback) + +### SchemaSection + +The `SchemaSection` type holds a schema in standard OpenAPI v3 JSON Schema format. + +| Field | Type | Required | Default | Description | +| ----------------- | ------ | -------- | ------- | -------------------------------------- | +| `openAPIV3Schema` | object | No | - | Standard OpenAPI v3 JSON Schema format | + +**Example:** + +```yaml +parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + commit: + type: string + default: "" + description: "Git commit SHA or reference (optional)" + appPath: + type: string + default: "." + description: "Path to the application directory" + docker: + type: object + default: {} + properties: + context: + type: string + default: "." + description: "Docker build context path" + filePath: + type: string + default: "./Dockerfile" + description: "Path to the Dockerfile" +``` + +### WorkflowResource + +Additional Kubernetes resources created alongside the workflow run (e.g., secrets, configmaps). + +| Field | Type | Required | Default | Description | +| ------------- | ------ | -------- | ------- | --------------------------------------------------------------------------------- | +| `id` | string | Yes | - | Unique identifier for this resource within the Workflow | +| `includeWhen` | string | No | - | CEL expression; if it evaluates to false, the resource is skipped | +| `template` | object | Yes | - | Kubernetes resource template with CEL expressions (same variables as runTemplate) | + +**Resource Lifecycle:** + +- Resources are rendered and created in the workflow plane before workflow execution begins +- Resources with `includeWhen` are only created if the condition evaluates to true +- Resource references are tracked in WorkflowRun status for cleanup +- When a WorkflowRun is deleted, the controller automatically cleans up all associated resources + +**Example with Conditional Creation:** + +```yaml +resources: + - id: git-secret + includeWhen: ${parameters.repository.secretRef != ""} + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${metadata.workflowRunName}-git-secret + namespace: workflows-${metadata.namespaceName} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${workflowplane.secretStore} + kind: ClusterSecretStore + target: + name: ${metadata.workflowRunName}-git-secret + creationPolicy: Owner + template: + type: ${externalRefs.repo-credentials.spec.template.type} + data: | + ${externalRefs.repo-credentials.spec.data.map(secret, { + "secretKey": secret.secretKey, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) ? secret.remoteRef.property : oc_omit() + } + })} +``` + +### ExternalRef + +Declares a reference to an external CR whose spec is resolved at runtime and injected into the CEL context. + +| Field | Type | Required | Default | Description | +| ------------ | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------ | +| `id` | string | Yes | - | CEL context key (2-63 chars, pattern: `^[a-z][a-z0-9-]*[a-z0-9]$`) | +| `apiVersion` | string | Yes | - | API version of the referenced resource | +| `kind` | string | Yes | - | Kind of the referenced resource. Currently only `SecretReference` is supported | +| `name` | string | Yes | - | Name of the referenced resource. Supports CEL expressions (e.g., `${parameters.repository.secretRef}`) | + +If the name evaluates to empty at runtime, the reference is silently skipped. + +**Example:** + +```yaml +externalRefs: + - id: repo-credentials + apiVersion: openchoreo.dev/v1alpha1 + kind: SecretReference + name: ${parameters.repository.secretRef} +``` + +Once resolved, the external ref's spec is available in CEL expressions as `${externalRefs.repo-credentials.spec.*}`. + +### Run Template + +The `runTemplate` field defines a Kubernetes resource template (typically an Argo Workflow) that gets rendered for each +execution. It references a ClusterWorkflowTemplate and uses template variables to inject runtime values. + +## Template Variables + +Workflow run templates support the following template variables: + +| Variable | Description | +| ------------------------------------------------ | ------------------------------------------------------------- | +| `${metadata.workflowRunName}` | WorkflowRun CR name (the execution instance) | +| `${metadata.namespaceName}` | Namespace name of the WorkflowRun | +| `${metadata.namespace}` | Enforced workflow plane namespace (e.g., `workflows-default`) | +| `${metadata.labels['openchoreo.dev/component']}` | Component name (for component workflow runs) | +| `${metadata.labels['openchoreo.dev/project']}` | Project name (for component workflow runs) | +| `${parameters.*}` | Developer-provided values from the parameter schema | +| `${externalRefs..spec.*}` | Resolved external reference spec fields | +| `${workflowplane.secretStore}` | ClusterSecretStore name from the referenced WorkflowPlane | + +## Examples + +### Docker Build Workflow + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: dockerfile-builder + namespace: default + labels: + openchoreo.dev/workflow-type: "component" + annotations: + openchoreo.dev/description: "Build with a provided Dockerfile/Containerfile/Podmanfile" +spec: + ttlAfterCompletion: "1d" + + parameters: + openAPIV3Schema: + type: object + required: + - repository + properties: + repository: + type: object + description: "Git repository configuration" + required: + - url + properties: + url: + type: string + description: "Git repository URL" + x-openchoreo-component-parameter-repository-url: true + secretRef: + type: string + default: "" + description: "Secret reference name for Git credentials" + x-openchoreo-component-parameter-repository-secret-ref: true + revision: + type: object + default: {} + properties: + branch: + type: string + default: main + description: "Git branch to checkout" + x-openchoreo-component-parameter-repository-branch: true + commit: + type: string + default: "" + description: "Git commit SHA or reference (optional)" + x-openchoreo-component-parameter-repository-commit: true + appPath: + type: string + default: "." + description: "Path to the application directory within the repository" + x-openchoreo-component-parameter-repository-app-path: true + docker: + type: object + default: {} + description: "Docker build configuration" + properties: + context: + type: string + default: "." + description: "Docker build context path relative to the repository root" + filePath: + type: string + default: "./Dockerfile" + description: "Path to the Dockerfile relative to the repository root" + + externalRefs: + - id: git-secret-reference + apiVersion: openchoreo.dev/v1alpha1 + kind: SecretReference + name: ${parameters.repository.secretRef} + + runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + name: ${metadata.workflowRunName} + namespace: ${metadata.namespace} + spec: + arguments: + parameters: + - name: component-name + value: ${metadata.labels['openchoreo.dev/component']} + - name: project-name + value: ${metadata.labels['openchoreo.dev/project']} + - name: workflowrun-name + value: ${metadata.workflowRunName} + - name: namespace-name + value: ${metadata.namespaceName} + - name: git-repo + value: ${parameters.repository.url} + - name: branch + value: ${parameters.repository.revision.branch} + - name: commit + value: ${parameters.repository.revision.commit} + - name: app-path + value: ${parameters.repository.appPath} + - name: docker-context + value: ${parameters.docker.context} + - name: dockerfile-path + value: ${parameters.docker.filePath} + - name: image-name + value: ${metadata.namespaceName}-${metadata.labels['openchoreo.dev/project']}-${metadata.labels['openchoreo.dev/component']} + - name: image-tag + value: v1 + - name: git-secret + value: ${metadata.workflowRunName}-git-secret + - name: registry-push-secret + value: ${metadata.workflowRunName}-registry-push-secret + serviceAccountName: workflow-sa + entrypoint: build-workflow + templates: + - name: build-workflow + steps: + - - name: checkout-source + templateRef: + name: checkout-source + clusterScope: true + template: checkout + - - name: build-image + templateRef: + name: containerfile-build + clusterScope: true + template: build-image + arguments: + parameters: + - name: git-revision + value: "{{steps.checkout-source.outputs.parameters.git-revision}}" + - - name: publish-image + templateRef: + name: publish-image + clusterScope: true + template: publish-image + arguments: + parameters: + - name: git-revision + value: "{{steps.checkout-source.outputs.parameters.git-revision}}" + - - name: generate-workload-cr + templateRef: + name: generate-workload + clusterScope: true + template: generate-workload-cr + arguments: + parameters: + - name: image + value: "{{steps.publish-image.outputs.parameters.image}}" + - name: run-name + value: "{{workflow.parameters.workflowrun-name}}" + volumeClaimTemplates: + - metadata: + name: workspace + spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 2Gi + + resources: + - id: git-secret + includeWhen: ${has(parameters.repository.secretRef) && parameters.repository.secretRef != ""} + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${metadata.workflowRunName}-git-secret + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + kind: ClusterSecretStore + name: ${workflowplane.secretStore} + target: + name: ${metadata.workflowRunName}-git-secret + creationPolicy: Owner + template: + type: ${externalRefs['git-secret-reference'].spec.template.type} + data: | + ${externalRefs['git-secret-reference'].spec.data.map(secret, { + "secretKey": secret.secretKey, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) && secret.remoteRef.property != "" ? secret.remoteRef.property : oc_omit() + } + })} +``` + +### Generic Automation Workflow + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Workflow +metadata: + name: github-stats-report + namespace: default + annotations: + openchoreo.dev/description: "Fetch GitHub repo statistics and generate a report" +spec: + ttlAfterCompletion: "1d" + + parameters: + openAPIV3Schema: + type: object + properties: + source: + type: object + default: {} + properties: + org: + type: string + default: "openchoreo" + description: "GitHub organization name" + repo: + type: string + default: "openchoreo" + description: "GitHub repository name" + output: + type: object + default: {} + properties: + format: + type: string + default: "table" + enum: + - table + - json + description: "Report output format" + + runTemplate: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + name: ${metadata.workflowRunName} + namespace: ${metadata.namespace} + spec: + arguments: + parameters: + - name: org + value: ${parameters.source.org} + - name: repo + value: ${parameters.source.repo} + - name: output-format + value: ${parameters.output.format} + serviceAccountName: workflow-sa + workflowTemplateRef: + clusterScope: true + name: github-stats-report +``` + +## Labels + +| Label | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `openchoreo.dev/workflow-type` | Set to `"component"` to mark this as a CI workflow for UI and CLI categorization. See [CI Governance](../../../platform-engineer-guide/workflows/ci-governance.md) | + +## Annotations + +| Annotation | Description | +| ----------------------------- | ------------------------------------ | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the Workflow | + +## Related Resources + +- [ClusterWorkflow](./clusterworkflow.md) - Cluster-scoped variant of Workflow +- [WorkflowRun](../application/workflowrun.md) - Runtime execution instances of Workflows +- [ComponentType](./componenttype.md) - Can restrict allowed workflows via `allowedWorkflows` +- [Component](../application/component.md) - References Workflows for building +- [Workflows Guide](../../../platform-engineer-guide/workflows/overview.md) - Guide for creating and using workflows diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflowplane.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflowplane.md new file mode 100644 index 00000000..cea20e2c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/platform/workflowplane.md @@ -0,0 +1,321 @@ +--- +title: WorkflowPlane API Reference +description: Namespace-scoped Kubernetes workflow plane cluster to execute workflows +--- + +# WorkflowPlane + +A WorkflowPlane represents the infrastructure layer responsible for executing workflow workloads in OpenChoreo. It provides the necessary compute resources and configuration for running CI/CD pipelines, typically using Argo Workflows or similar build orchestration systems. Each WorkflowPlane is associated with a specific Kubernetes cluster where workflow jobs are executed. + +OpenChoreo uses **agent-based communication** where the control plane communicates with the workflow plane cluster through a WebSocket agent running in the WorkflowPlane cluster. The cluster agent establishes a secure WebSocket connection to the control plane's cluster gateway. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +WorkflowPlanes are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: WorkflowPlane +metadata: + name: + namespace: # Namespace for grouping workflowplanes +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ----------------------- | ----------------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- | +| `planeID` | string | No | CR name | Identifies the logical plane this CR connects to. Must match `clusterAgent.planeId` Helm value. | +| `clusterAgent` | [ClusterAgentConfig](#clusteragentconfig) | Yes | - | Configuration for cluster agent-based communication | +| `secretStoreRef` | [SecretStoreRef](#secretstoreref) | No | - | Reference to External Secrets Operator ClusterSecretStore in the WorkflowPlane | +| `observabilityPlaneRef` | [ObservabilityPlaneRef](#observabilityplaneref) | No | - | Reference to the ObservabilityPlane or ClusterObservabilityPlane resource for monitoring and logging | + +### PlaneID + +The `planeID` identifies the logical plane this WorkflowPlane CR connects to. Multiple WorkflowPlane CRs can share the same `planeID` to connect to the same physical cluster while maintaining separate configurations for multi-tenancy scenarios. + +**Validation Rules:** + +- Maximum length: 63 characters +- Pattern: `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` (lowercase alphanumeric, hyphens allowed) +- Examples: `"shared-builder"`, `"ci-cluster"`, `"us-west-2"` + +:::important PlaneID Consistency +The `planeID` in the WorkflowPlane CR must match the `clusterAgent.planeId` Helm value configured during workflow plane installation. If not specified, it defaults to the CR name for backwards compatibility. +::: + +### ClusterAgentConfig + +Configuration for cluster agent-based communication with the workflow plane cluster. The cluster agent establishes a WebSocket connection to the control plane's cluster gateway. + +| Field | Type | Required | Default | Description | +| ---------- | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | +| `clientCA` | [ValueFrom](#valuefrom) | Yes | - | CA certificate to verify the agent's client certificate (base64-encoded PEM) | + +### SecretStoreRef + +Reference to an External Secrets Operator ClusterSecretStore. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | ------- | --------------------------------------------------- | +| `name` | string | Yes | - | Name of the ClusterSecretStore in the WorkflowPlane | + +### ObservabilityPlaneRef + +Reference to an ObservabilityPlane or ClusterObservabilityPlane for monitoring and logging. + +| Field | Type | Required | Default | Description | +| ------ | ------ | -------- | -------------------- | ------------------------------------------------------------------------------------- | +| `kind` | string | No | `ObservabilityPlane` | Kind of the observability plane (`ObservabilityPlane` or `ClusterObservabilityPlane`) | +| `name` | string | Yes | - | Name of the observability plane resource | + +### ValueFrom + +Common pattern for referencing secrets or providing inline values. Either `secretKeyRef` or `value` should be specified. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------- | -------- | ------- | ------------------------------------------------- | +| `secretKeyRef` | [SecretKeyReference](#secretkeyreference) | No | - | Reference to a secret key | +| `value` | string | No | - | Inline value (not recommended for sensitive data) | + +### SecretKeyReference + +Reference to a specific key in a Kubernetes secret. + +| Field | Type | Required | Default | Description | +| ----------- | ------ | -------- | ----------------------- | ----------------------- | +| `name` | string | Yes | - | Name of the secret | +| `namespace` | string | No | Same as parent resource | Namespace of the secret | +| `key` | string | Yes | - | Key within the secret | + +### Status Fields + +| Field | Type | Default | Description | +| -------------------- | ----------------------------------------------- | ------- | --------------------------------------------------------------- | +| `observedGeneration` | integer | 0 | The generation observed by the controller | +| `conditions` | []Condition | [] | Standard Kubernetes conditions tracking the WorkflowPlane state | +| `agentConnection` | [AgentConnectionStatus](#agentconnectionstatus) | - | Tracks the status of cluster agent connections | + +#### AgentConnectionStatus + +| Field | Type | Default | Description | +| ---------------------- | --------- | ------- | -------------------------------------------------------------------- | +| `connected` | boolean | false | Whether any cluster agent is currently connected | +| `connectedAgents` | integer | 0 | Number of cluster agents currently connected | +| `lastConnectedTime` | timestamp | - | When an agent last successfully connected | +| `lastDisconnectedTime` | timestamp | - | When the last agent disconnected | +| `lastHeartbeatTime` | timestamp | - | When the control plane last received any communication from an agent | +| `message` | string | - | Additional information about the agent connection status | + +## Getting the Agent CA Certificate + +The cluster agent automatically generates its CA certificate when deployed to the workflow plane cluster. This certificate is used by the control plane to verify the identity of the workflow plane agent during mTLS authentication. + +### Extracting the CA Certificate + +You can extract the CA certificate using: + +```bash +# For multi-cluster setups, specify the workflow plane cluster context +kubectl --context get secret cluster-agent-tls \ + -n openchoreo-workflow-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d + +# Example for k3d multi-cluster setup: +kubectl --context k3d-openchoreo-wp get secret cluster-agent-tls \ + -n openchoreo-workflow-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d +``` + +:::important +In multi-cluster setups, you **must** specify the `--context` flag to target the workflow plane cluster, not the control plane cluster. The `cluster-agent-tls` secret exists in the workflow plane cluster where the agent is deployed. +::: + +### Adding the Certificate to the WorkflowPlane CR + +You can add the CA certificate to the WorkflowPlane CR in two ways: + +**Option 1: Inline value (for testing/development)** + +```bash +# Extract the CA certificate from the workflow plane cluster +WP_CA_CERT=$(kubectl --context get secret cluster-agent-tls \ + -n openchoreo-workflow-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d) + +# Create WorkflowPlane in the control plane with inline CA certificate +kubectl --context apply -f - < get secret cluster-agent-tls \ + -n openchoreo-workflow-plane \ + -o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/workflowplane-ca.crt + +# Create a secret in the control plane cluster +kubectl --context create secret generic workflowplane-agent-ca \ + --from-file=ca.crt=/tmp/workflowplane-ca.crt \ + -n my-org + +# Create WorkflowPlane in the control plane referencing the secret +kubectl --context apply -f - < + namespace: # Namespace for grouping component releases +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| ------------------ | ------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------- | +| `owner` | [ComponentReleaseOwner](#componentreleaseowner) | Yes | - | Ownership information linking the release to a project and component | +| `componentType` | [ComponentTypeSpec](../platform/componenttype.md#spec-fields) | Yes | - | Immutable snapshot of the ComponentType at release time | +| `traits` | map[string][TraitSpec](../platform/trait.md#spec-fields) | No | {} | Immutable snapshot of trait specifications at release time | +| `componentProfile` | [ComponentProfile](#componentprofile) | Yes | - | Immutable snapshot of parameter values and trait configurations | +| `workload` | [WorkloadTemplateSpec](#workloadtemplatespec) | Yes | - | Immutable snapshot of the workload specification with the built image | + +### ComponentReleaseOwner + +| Field | Type | Required | Default | Description | +| --------------- | ------ | -------- | ------- | ---------------------------------------------------- | +| `projectName` | string | Yes | - | Name of the project that owns this component release | +| `componentName` | string | Yes | - | Name of the component this release belongs to | + +### ComponentProfile + +ComponentProfile contains the frozen parameter values and trait configurations at the time of release. + +| Field | Type | Required | Default | Description | +| ------------ | --------------------------------------------------------------------------------------- | -------- | ------- | ---------------------------------------------------- | +| `parameters` | [runtime.RawExtension](https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime#RawExtension) | No | - | Snapshot of parameter values from the Component spec | +| `traits` | [[ComponentTrait](#componenttrait)] | No | [] | Trait instances with their configurations | + +### ComponentTrait + +| Field | Type | Required | Default | Description | +| -------------- | --------------------------------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------- | +| `name` | string | Yes | - | Name of the Trait resource | +| `kind` | string | No | `Trait` | Kind of trait resource: `Trait` (namespace-scoped) or `ClusterTrait` (cluster-scoped) | +| `instanceName` | string | Yes | - | Unique identifier for this trait instance within the component | +| `parameters` | [runtime.RawExtension](https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime#RawExtension) | No | - | Trait parameter values conforming to the trait's schema | + +### WorkloadTemplateSpec + +The WorkloadTemplateSpec contains the complete workload specification with the built container image. + +| Field | Type | Required | Default | Description | +| -------------- | -------------------------------------------------------------------------- | -------- | ------- | ---------------------------------------------------------- | +| `container` | [Container](../application/workload.md#container) | Yes | - | Container specification for the workload | +| `endpoints` | map[string][WorkloadEndpoint](../application/workload.md#workloadendpoint) | No | {} | Network endpoints for port exposure keyed by endpoint name | +| `dependencies` | [WorkloadDependencies](../application/workload.md#workloaddependencies) | No | - | Dependencies on other component endpoints | + +### Status Fields + +Currently, ComponentRelease does not have any status fields defined. + +## Examples + +### Basic ComponentRelease for a Service Component + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentRelease +metadata: + name: customer-service-v1.0.0 + namespace: default +spec: + owner: + projectName: my-project + componentName: customer-service + componentType: + workloadType: deployment + parameters: + openAPIV3Schema: + type: object + properties: + runtime: + type: object + default: {} + properties: + port: + type: integer + default: 8080 + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: "${metadata.name}" + spec: + replicas: 1 + template: + spec: + containers: + - name: main + image: "${workload.container.image}" + ports: + - containerPort: "${parameters.runtime.port}" + componentProfile: + parameters: + runtime: + port: 8080 + workload: + container: + image: myregistry/customer-service@sha256:abc123... + env: + - key: LOG_LEVEL + value: info + endpoints: + api: + type: HTTP + port: 8080 +``` + +### ComponentRelease with Traits + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentRelease +metadata: + name: order-service-v2.1.0 + namespace: default +spec: + owner: + projectName: my-project + componentName: order-service + componentType: + workloadType: deployment + parameters: + openAPIV3Schema: + type: object + properties: + runtime: + type: object + default: {} + properties: + replicas: + type: integer + default: 1 + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: "${metadata.name}" + spec: + replicas: "${spec.parameters.runtime.replicas}" + traits: + persistent-volume: + parameters: + openAPIV3Schema: + type: object + required: + - volumeName + - mountPath + properties: + volumeName: + type: string + mountPath: + type: string + environmentConfigs: + openAPIV3Schema: + type: object + properties: + size: + type: string + default: 10Gi + patches: + - target: + id: deployment + operations: + - op: add + path: /spec/template/spec/volumes/- + value: + name: "${spec.traits.volumeName}" + componentProfile: + parameters: + runtime: + replicas: 3 + traits: + - name: persistent-volume + kind: Trait + instanceName: data-volume + parameters: + volumeName: data + mountPath: /var/data + size: 20Gi + workload: + container: + image: myregistry/order-service@sha256:def456... + env: + - key: DATA_DIR + value: /var/data + endpoints: + order-api: + type: HTTP + port: 8080 + dependencies: + endpoints: + - project: my-project + component: postgres-db + name: tcp-endpoint + visibility: project + envBindings: + host: DATABASE_HOST + port: DATABASE_PORT +``` + +## Immutability + +ComponentRelease is designed to be immutable once created. All spec fields have validation rules that prevent modifications after creation: + +- `spec.componentType` - Immutable +- `spec.traits` - Immutable +- `spec.componentProfile` - Immutable +- `spec.workload` - Immutable + +This ensures that a ComponentRelease always represents the exact state of the component at a specific point in time, enabling reliable rollbacks and auditing. + +## Annotations + +ComponentReleases support the following annotations: + +| Annotation | Description | +| ----------------------------- | --------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the component release | +| `openchoreo.dev/version` | Semantic version or tag for this release | + +## Related Resources + +- [Component](../application/component.md) - Components that ComponentReleases are created from +- [ComponentType](../platform/componenttype.md) - Component type definitions captured in releases +- [Trait](../platform/trait.md) - Trait specifications captured in releases +- [Workload](../application/workload.md) - Workload specifications captured in releases +- [ReleaseBinding](../platform/releasebinding.md) - Binds a ComponentRelease to a target environment for deployment diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/renderedrelease.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/renderedrelease.md new file mode 100644 index 00000000..b8721a9a --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/renderedrelease.md @@ -0,0 +1,163 @@ +--- +title: RenderedRelease API Reference +description: Final Kubernetes resources deployed to a target plane by the ReleaseBinding controller +--- + +# RenderedRelease + +A RenderedRelease represents the actual deployment of application resources to a target plane (DataPlane or +ObservabilityPlane) in OpenChoreo. It is created by the ReleaseBinding controller and contains the complete set of +Kubernetes resources that need to be applied to the target plane. RenderedReleases manage the lifecycle and health +monitoring of deployed resources. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +RenderedReleases are namespace-scoped resources. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: RenderedRelease +metadata: + name: + namespace: # Namespace for grouping rendered releases +``` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| --------------------- | --------------------------------------------- | -------- | --------- | ------------------------------------------------------------------------------------ | +| `owner` | [RenderedReleaseOwner](#renderedreleaseowner) | Yes | - | Ownership information linking the rendered release to a project and component | +| `environmentName` | string | Yes | - | Name of the target environment for this rendered release | +| `resources` | [[Resource](#resource)] | No | [] | List of Kubernetes resources to apply to the target plane | +| `interval` | Duration | No | 5m | Watch interval for resources when stable | +| `progressingInterval` | Duration | No | 10s | Watch interval for resources when transitioning | +| `targetPlane` | string | No | dataplane | Which plane this release should be deployed to (`dataplane` or `observabilityplane`) | + +### RenderedReleaseOwner + +| Field | Type | Required | Default | Description | +| --------------- | ------ | -------- | ------- | ----------------------------------------------------- | +| `projectName` | string | Yes | - | Name of the project that owns this rendered release | +| `componentName` | string | Yes | - | Name of the component that owns this rendered release | + +### Resource + +| Field | Type | Required | Default | Description | +| -------- | -------------------- | -------- | ------- | -------------------------------------------------------- | +| `id` | string | Yes | - | Unique identifier for the resource | +| `object` | runtime.RawExtension | Yes | - | Complete Kubernetes resource definition in raw JSON/YAML | + +### Status Fields + +| Field | Type | Default | Description | +| ------------ | ----------------------------------- | ------- | ------------------------------------------------------------------------- | +| `resources` | [[ResourceStatus](#resourcestatus)] | [] | List of resources that have been successfully applied to the target plane | +| `conditions` | [[Condition](#conditions)] | [] | Conditions tracking the rendered release state | + +### ResourceStatus + +| Field | Type | Default | Description | +| ------------------ | ----------------------------- | ------- | ---------------------------------------------------------- | +| `id` | string | - | Corresponds to the resource ID in spec.resources | +| `group` | string | "" | API group of the resource (e.g., "apps", "batch") | +| `version` | string | - | API version of the resource (e.g., "v1", "v1beta1") | +| `kind` | string | - | Type of the resource (e.g., "Deployment", "Service") | +| `name` | string | - | Name of the resource in the target plane | +| `namespace` | string | "" | Namespace of the resource in the target plane | +| `status` | runtime.RawExtension | - | Entire .status field of the resource from the target plane | +| `healthStatus` | [HealthStatus](#healthstatus) | - | Health of the resource in the target plane | +| `lastObservedTime` | Time | - | Last time the status was observed | + +### HealthStatus + +| Value | Description | +| ------------- | -------------------------------------------------------------------------------- | +| `Unknown` | Health of the resource is not known | +| `Progressing` | Resource is in a transitioning state to become healthy | +| `Healthy` | Resource is healthy and operating as expected | +| `Suspended` | Resource is intentionally paused (e.g., CronJob, Deployment with paused rollout) | +| `Degraded` | Resource is not healthy and not operating as expected | + +### Conditions + +RenderedReleases report their state through standard Kubernetes conditions. The following condition types are used: + +| Type | Description | +| ------------ | ------------------------------------------------------------------------------------------------------- | +| `Finalizing` | Indicates the RenderedRelease is being deleted and resources are being cleaned up from the target plane | + +## Examples + +### Basic RenderedRelease with Deployment and Service + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: RenderedRelease +metadata: + name: customer-service-prod-renderedrelease + namespace: default +spec: + owner: + projectName: my-project + componentName: customer-service + environmentName: production + interval: 5m + progressingInterval: 10s + resources: + - id: deployment + object: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: customer-service + namespace: prod-data-plane + spec: + replicas: 3 + selector: + matchLabels: + app: customer-service + template: + metadata: + labels: + app: customer-service + spec: + containers: + - name: main + image: myregistry/customer-service:v1.0.0 + ports: + - containerPort: 8080 + - id: service + object: + apiVersion: v1 + kind: Service + metadata: + name: customer-service + namespace: prod-data-plane + spec: + selector: + app: customer-service + ports: + - port: 80 + targetPort: 8080 +``` + +## Annotations + +RenderedReleases support the following annotations: + +| Annotation | Description | +| ----------------------------- | -------------------------------------------- | +| `openchoreo.dev/display-name` | Human-readable name for UI display | +| `openchoreo.dev/description` | Detailed description of the rendered release | + +## Related Resources + +- [Environment](../platform/environment.md) - Target environments for rendered releases +- [DataPlane](../platform/dataplane.md) - Data planes where application resources are deployed +- [ObservabilityPlane](../platform/observabilityplane.md) - Observability planes where monitoring resources are deployed diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/resourcerelease.md b/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/resourcerelease.md new file mode 100644 index 00000000..45a4237c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/api/runtime/resourcerelease.md @@ -0,0 +1,162 @@ +--- +title: ResourceRelease API Reference +description: Immutable snapshot of a Resource and its ResourceType at a point in time +--- + +# ResourceRelease + +A ResourceRelease is an immutable snapshot of a [Resource](../application/resource.md) and the referenced [ResourceType](../platform/resourcetype.md) or [ClusterResourceType](../platform/clusterresourcetype.md) at the moment it was cut. ResourceReleases ensure reproducibility and enable reliable rollback by preserving the exact state used to render the binding for each environment. + +ResourceReleases are created exclusively by the Resource controller. When the hash of `Resource.spec` plus the referenced ResourceType's spec changes, a new ResourceRelease is cut with the name `{resource}-{hash}`. They are deleted by the Resource finalizer when the parent Resource is torn down. + +## API Version + +`openchoreo.dev/v1alpha1` + +## Resource Definition + +### Metadata + +ResourceReleases are namespace-scoped resources created in the same namespace as the Resource. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceRelease +metadata: + name: - + namespace: +``` + +The name shape mirrors the ComponentRelease pattern: a stable prefix derived from the Resource name plus a content-addressed hash discriminator. Two ResourceReleases for the same Resource can therefore coexist during a rolling promotion. + +### Spec Fields + +The entire spec is immutable after creation. Edits are rejected by a CEL validation rule on the CRD. + +| Field | Type | Required | Default | Description | +| -------------- | ----------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------- | +| `owner` | [ResourceReleaseOwner](#resourcereleaseowner) | Yes | - | Identifies the Resource and project this snapshot belongs to | +| `resourceType` | [ResourceReleaseResourceType](#resourcereleaseresourcetype) | Yes | - | Frozen snapshot of the (Cluster)ResourceType resource at release time | +| `parameters` | object | No | - | Frozen snapshot of `Resource.spec.parameters` at release time | + +### ResourceReleaseOwner + +| Field | Type | Required | Description | +| -------------- | ------ | -------- | ----------------------------------------------------- | +| `projectName` | string | Yes | Name of the project that owns this Resource (min: 1) | +| `resourceName` | string | Yes | Name of the Resource this release belongs to (min: 1) | + +### ResourceReleaseResourceType + +Captures both the identity (Kind + Name) and the full spec of the referenced (Cluster)ResourceType at release time, so a namespace-scoped ResourceType and a cluster-scoped ClusterResourceType with the same name can coexist in the snapshot history. + +| Field | Type | Required | Description | +| ------ | ----------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------- | +| `kind` | string | Yes | Either `ResourceType` (namespace-scoped) or `ClusterResourceType` (cluster-scoped) | +| `name` | string | Yes | Name of the (Cluster)ResourceType resource (min: 1) | +| `spec` | [ResourceTypeSpec](../platform/resourcetype.md#spec-fields) | Yes | Frozen specification of the (Cluster)ResourceType | + +ClusterResourceType snapshots currently share the namespaced ResourceType spec shape; if ClusterResourceType later gains cluster-only fields, snapshots taken from a ClusterResourceType source will not preserve them—mirrors the ComponentRelease precedent. + +### Status Fields + +ResourceRelease currently has no status fields. Observed deployment state (per-environment readiness, output resolution, finalization) lives on the [ResourceReleaseBinding](../platform/resourcereleasebinding.md) that pins this snapshot. + +## Examples + +### Basic ResourceRelease + +A snapshot cut by the Resource controller after a developer creates a Resource referencing the `postgres` ClusterResourceType. + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceRelease +metadata: + name: doclet-postgres-abc12345 + namespace: default +spec: + owner: + projectName: doclet + resourceName: doclet-postgres + resourceType: + kind: ClusterResourceType + name: postgres + spec: + parameters: + openAPIV3Schema: + type: object + properties: + database: + type: string + default: postgres + environmentConfigs: + openAPIV3Schema: + type: object + properties: + storage: + type: string + default: "10Gi" + retainPolicy: Retain + outputs: + - name: host + value: "${metadata.name}.${metadata.namespace}.svc.cluster.local" + - name: port + value: "5432" + - name: password + secretKeyRef: + name: "${metadata.name}-creds" + key: password + resources: + - id: password-secret + template: + # ... ExternalSecret or Password generator manifest ... + - id: statefulset + readyWhen: "${applied.statefulset.status.readyReplicas == 1}" + template: + # ... Postgres StatefulSet ... + parameters: + database: doclet +``` + +### ResourceRelease From a Namespace-Scoped ResourceType + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ResourceRelease +metadata: + name: order-cache-def67890 + namespace: default +spec: + owner: + projectName: order-service + resourceName: order-cache + resourceType: + kind: ResourceType + name: valkey-cache + spec: + # ... frozen ResourceType spec at release time ... + parameters: + version: "8" +``` + +## Immutability + +ResourceRelease's spec is enforced immutable by a CEL validation rule (`self == oldSelf`). All fields—`owner`, `resourceType`, `parameters`—are part of the snapshot guarantee: + +- Spec edits via `kubectl edit` or API PATCH are rejected. +- The Resource controller cuts a new ResourceRelease (new hash, new name) when either the Resource spec or the referenced (Cluster)ResourceType spec changes. The previous snapshot is left untouched until the Resource finalizer GC's it. + +## Lifecycle + +1. **Create.** Resource controller computes the hash of `Resource.spec + (Cluster)ResourceType.spec`. If no ResourceRelease with that hash exists, it creates one named `{resource}-{hash}` and updates `Resource.status.latestRelease`. +2. **Promote.** A platform engineer or GitOps process updates a `ResourceReleaseBinding.spec.resourceRelease` to point at this snapshot. The binding controller renders the snapshot's `resourceType.spec` with the snapshot's `parameters` and the binding's `resourceTypeEnvironmentConfigs`, then applies the resulting manifests to the data plane. +3. **Delete.** When the parent Resource is deleted, the Resource finalizer's second phase removes all owned ResourceReleases (matched by `spec.owner.resourceName`). Direct `kubectl delete resourcerelease ...` is not blocked by a finalizer but breaks the binding chain if any binding still references the snapshot. + +## Related Resources + +- [Resource](../application/resource.md) — Owns this snapshot through `spec.owner.{projectName, resourceName}` +- [ResourceType](../platform/resourcetype.md) — Source template captured in `spec.resourceType.spec` +- [ClusterResourceType](../platform/clusterresourcetype.md) — Cluster-scoped variant of the source template +- [ResourceReleaseBinding](../platform/resourcereleasebinding.md) — Pins this snapshot to a specific environment +- [RenderedRelease](./renderedrelease.md) — Final manifests produced by the binding controller +- [ComponentRelease](./componentrelease.md) — Component-side counterpart diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/cel/built-in-functions.md b/versioned_docs/version-v1.2.0-rc.2/reference/cel/built-in-functions.md new file mode 100644 index 00000000..82e22e0b --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/cel/built-in-functions.md @@ -0,0 +1,228 @@ +--- +title: Built-in Functions +description: OpenChoreo CEL built-in functions for templates +--- + +# Built-in Functions + +OpenChoreo provides several built-in CEL functions for common operations in ComponentType and Trait templates. + +## oc_omit() + +Removes fields from output. Has two distinct behaviors depending on usage context. + +### Field-level Omission + +When used as a standalone value, removes the entire YAML key from the template: + +```yaml +resources: + limits: + memory: ${parameters.memoryLimit} + cpu: ${has(parameters.cpuLimit) ? parameters.cpuLimit : oc_omit()} + # When cpuLimit is missing, the entire 'cpu:' line is removed + +metadata: + name: ${metadata.name} + annotations: ${has(parameters.annotations) ? parameters.annotations : oc_omit()} + # When annotations is missing, the entire 'annotations:' key is removed +``` + +### Expression-level Omission + +When used inside a CEL map expression, removes the key from the map: + +```yaml +# Use CEL's optional key syntax for simple optional fields +container: | + ${{ + "image": parameters.image, + ?"cpu": parameters.?cpu, + ?"memory": parameters.?memory + }} + # Keys are only included if the value exists + +# Use oc_omit() when conditional logic is involved +container: | + ${{ + "image": parameters.image, + "cpu": parameters.cpuLimit > 0 ? parameters.cpuLimit : oc_omit(), + "debug": parameters.environment == "dev" ? true : oc_omit() + }} + # Keys are conditionally included based on logic, not just existence +``` + +## oc_merge(base, override, ...) + +Shallow merge two or more maps. Later maps override earlier ones for conflicting keys. + +**Parameters:** + +- `base` - Base map +- `override` - Map to merge (overrides base) +- `...` - Additional maps (optional) + +**Returns:** Merged map + +```yaml +# Merge default and custom labels +labels: | + ${oc_merge({"app": metadata.name, "version": "v1"}, parameters.customLabels)} + +# Merge multiple maps (later maps take precedence) +config: ${oc_merge(defaults, layer1, layer2, layer3)} + +# Common pattern: merge platform labels with user labels +metadata: + labels: ${oc_merge(metadata.labels, parameters.customLabels)} +``` + +## oc_generate_name(...args) + +Generate valid Kubernetes resource names with a hash suffix for uniqueness. Converts input to lowercase, replaces invalid characters with hyphens, and appends an 8-character hash. + +**Parameters:** + +- `...args` - One or more strings to combine into a name + +**Returns:** Kubernetes-compliant name string (lowercase, alphanumeric, hyphens, max 63 chars) + +```yaml +# Create ConfigMap name with hash +name: ${oc_generate_name(metadata.name, "config", parameters.environment)} +# Result: "myapp-config-prod-a1b2c3d4" + +# Handle special characters automatically +name: ${oc_generate_name("My_App", "Service!")} +# Result: "my-app-service-e5f6g7h8" + +# Single argument also gets hash +name: ${oc_generate_name("Hello World!")} +# Result: "hello-world-7f83b165" +``` + +**Notes:** + +- The hash is deterministic: same inputs always produce the same output +- Useful for generating unique names for resources created in `forEach` loops +- Ensures names comply with Kubernetes naming requirements + +## oc_dns_label(...args) + +Generate an RFC 1123-compliant DNS label name (≤63 characters) with a hash suffix, suitable for use as hostname subdomains in HTTPRoutes. Combines input strings with hyphens, lowercases them, replaces invalid characters, and appends an 8-character hash. + +**Parameters:** + +- `...args` - One or more strings to combine into a DNS label + +**Returns:** RFC 1123-compliant DNS label string (≤63 chars, lowercase alphanumeric and hyphens) + +```yaml +# Build a hostname subdomain from endpoint and component identity +hostnames: | + ${[gateway.ingress.external.?http, gateway.ingress.external.?https] + .filter(g, g.hasValue()).map(g, g.value().host).distinct() + .map(h, oc_dns_label(endpoint, metadata.componentName, metadata.environmentName, metadata.componentNamespace) + "." + h)} + +# Result: "api-my-service-dev-default-a1b2c3d4.apps.example.com" +``` + +**Notes:** + +- The hash is deterministic: same inputs always produce the same output +- Designed for subdomain generation where the combined string may exceed 63 characters +- Differs from `oc_generate_name` in that it is optimized for DNS subdomain labels rather than Kubernetes resource names + +## oc_hash(string) + +Generate an 8-character FNV-32a hash from an input string. Useful for creating unique identifiers or suffixes. + +**Parameters:** + +- `string` - Input string to hash + +**Returns:** 8-character hexadecimal hash string + +```yaml +# Generate hash for volume name uniqueness +volumeName: main-file-mount-${oc_hash(config.mountPath + "/" + config.name)} + +# Use in resource naming +suffix: ${oc_hash(parameters.uniqueKey)} +``` + +**Notes:** + +- Hash is deterministic: same input always produces the same output +- Used internally by `oc_generate_name()` to create the hash suffix + +## Usage Examples + +### Complete ComponentType Example + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: web-service +spec: + workloadType: deployment + + parameters: + openAPIV3Schema: + type: object + properties: + port: + type: integer + default: 8080 + customLabels: + type: object + default: {} + additionalProperties: + type: string + cpuLimit: + type: string + configFiles: + type: array + default: [] + items: + type: object + additionalProperties: + type: string + + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + # Merge platform labels with custom labels + labels: ${oc_merge(metadata.labels, parameters.customLabels)} + spec: + template: + spec: + containers: + - name: app + image: ${workload.container.image} + resources: + limits: + # Only include cpu if specified + cpu: ${has(parameters.cpuLimit) ? parameters.cpuLimit : oc_omit()} + + # Generate ConfigMaps with unique names + - id: configs + forEach: ${parameters.configFiles} + var: config + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${oc_generate_name(metadata.name, config.name)} +``` + +## Related Resources + +- [Context Variables](./context-variables.md) - Variables available in templates +- [Configuration Helpers](./helper-functions.md) - Helper functions for configurations +- [Templating Syntax](../../platform-engineer-guide/component-types/templating-syntax.md) - Expression syntax and resource control diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/cel/context-variables.md b/versioned_docs/version-v1.2.0-rc.2/reference/cel/context-variables.md new file mode 100644 index 00000000..e39411d8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/cel/context-variables.md @@ -0,0 +1,462 @@ +--- +title: Context Variables +description: Variables available in Workflow, ComponentType, and Trait templates +--- + +# Context Variables + +This reference documents all context variables available in Workflow, ComponentType, and Trait templates. + +## Workflow Variables + +The following variables are available in Workflow and ClusterWorkflow `runTemplate` and `resources` templates. + +### metadata + +Platform-computed metadata for workflow execution. + +| Field | Type | Description | +| -------------------------- | ------ | ------------------------------------------------------------------------------- | +| `metadata.workflowRunName` | string | Name of the WorkflowRun CR | +| `metadata.namespaceName` | string | Namespace name of the WorkflowRun | +| `metadata.namespace` | string | Enforced workflow plane namespace (e.g., `workflows-default`) | +| `metadata.labels` | map | WorkflowRun labels (e.g., `openchoreo.dev/component`, `openchoreo.dev/project`) | + +**Usage:** + +```yaml +metadata: + name: ${metadata.workflowRunName} + namespace: ${metadata.namespace} +spec: + arguments: + parameters: + - name: component-name + value: ${metadata.labels['openchoreo.dev/component']} + - name: project-name + value: ${metadata.labels['openchoreo.dev/project']} +``` + +### parameters + +Developer-provided values from `WorkflowRun.spec.workflow.parameters`, with schema defaults from the Workflow's `openAPIV3Schema` applied. + +```yaml +# Access parameters defined in the Workflow schema +- name: git-repo + value: ${parameters.repository.url} +- name: branch + value: ${parameters.repository.revision.branch} +``` + +### workflowplane + +Workflow plane configuration, resolved from the Workflow's `workflowPlaneRef`. + +| Field | Type | Description | +| --------------------------- | ------ | ---------------------------------------------------------------- | +| `workflowplane.secretStore` | string | Name of the ClusterSecretStore from the referenced WorkflowPlane | + +**Usage:** + +```yaml +# ExternalSecret configuration in workflow resources +spec: + secretStoreRef: + name: ${workflowplane.secretStore} + kind: ClusterSecretStore +``` + +### externalRefs + +Resolved external CR specs, keyed by the `id` declared in the Workflow's `externalRefs`. Only present when the Workflow declares external references. See [ExternalRef](../api/platform/workflow.md#externalref). + +```yaml +# Access resolved SecretReference spec +template: + type: ${externalRefs['git-secret-reference'].spec.template.type} + +# Iterate over secret data +data: | + ${externalRefs['git-secret-reference'].spec.data.map(secret, { + "secretKey": secret.secretKey, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) && secret.remoteRef.property != "" ? secret.remoteRef.property : oc_omit() + } + })} +``` + +--- + +## ComponentType Variables + +The following variables are available in ComponentType resource templates. + +### metadata + +Platform-computed metadata for resource generation. + +| Field | Type | Description | +| ----------------------------- | ------ | ------------------------------------------------------------------- | +| `metadata.name` | string | Base name for generated resources (e.g., `my-service-dev-a1b2c3d4`) | +| `metadata.namespace` | string | Target namespace for resources | +| `metadata.componentNamespace` | string | Target namespace of the component | +| `metadata.componentName` | string | Name of the component | +| `metadata.componentUID` | string | Unique identifier of the component | +| `metadata.projectName` | string | Name of the project | +| `metadata.projectUID` | string | Unique identifier of the project | +| `metadata.environmentName` | string | Name of the environment (e.g., `development`, `production`) | +| `metadata.environmentUID` | string | Unique identifier of the environment | +| `metadata.dataPlaneName` | string | Name of the data plane | +| `metadata.dataPlaneUID` | string | Unique identifier of the data plane | +| `metadata.labels` | map | Common labels to add to all resources | +| `metadata.annotations` | map | Common annotations to add to all resources | +| `metadata.podSelectors` | map | Platform-injected selectors for pod identity | + +**Usage:** + +```yaml +metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} +spec: + selector: + matchLabels: ${metadata.podSelectors} +``` + +### parameters + +Component parameters from `Component.spec.parameters` with schema defaults applied. Use for static configuration that doesn't change across environments. + +```yaml +# Access parameters defined in schema.parameters +replicas: ${parameters.replicas} +port: ${parameters.port} + +# Nested parameters +database: + host: ${parameters.database.host} + port: ${parameters.database.port} +``` + +### environmentConfigs + +Environment-specific configuration from `ReleaseBinding.spec.componentTypeEnvironmentConfigs`, pruned to the ComponentType's `environmentConfigs` schema with defaults applied. Use for values that vary per environment (resources, replicas, etc.). + +```yaml +# Access environment-specific values +replicas: ${environmentConfigs.replicas} +resources: + limits: + cpu: ${environmentConfigs.resources.cpu} + memory: ${environmentConfigs.resources.memory} +``` + +### workload + +Workload specification from the Workload resource. + +| Field | Type | Description | +| ------------------------------------- | ----------------- | ------------------------------------------------------------------------- | +| `workload.container` | object | Container configuration | +| `workload.container.image` | string | Container image | +| `workload.container.command` | []string | Container command | +| `workload.container.args` | []string | Container arguments | +| `workload.endpoints` | map[string]object | Network endpoints keyed by endpoint name | +| `workload.endpoints[name].type` | string | Endpoint protocol (`HTTP`, `gRPC`, `GraphQL`, `Websocket`, `TCP`, `UDP`) | +| `workload.endpoints[name].port` | int32 | Port number | +| `workload.endpoints[name].basePath` | string | Base path prefix (optional, default `"/"`) | +| `workload.endpoints[name].visibility` | []string | Visibility scopes: `"project"`, `"namespace"`, `"internal"`, `"external"` | +| `workload.endpoints[name].schema` | object | Optional API schema definition | + +**Usage:** + +```yaml +containers: + - name: main + image: ${workload.container.image} + command: ${workload.container.command} + args: ${workload.container.args} + +# Iterate over endpoints with external visibility +- id: httproute-external + forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility && ep.type in ["HTTP", "GraphQL", "Websocket"]) ? [name] : []).flatten()}' + var: endpoint + template: + # ... + spec: + backendRefs: + - name: ${metadata.componentName} + port: ${workload.endpoints[endpoint].port} +``` + +**Helper methods:** The `workload` object exposes two endpoint helpers: + +- `workload.toServicePorts()`: converts the endpoints map into Kubernetes Service ports. +- `workload.toEndpointResources(endpointName)`: opt-in; parses the named endpoint's `schema` (OpenAPI for HTTP, protobuf for gRPC) into a CEL optional wrapping a list of `{kind, service, method, path}` routes, for rendering exact per-route gateway matches. Consume it with `.orValue([])` or `.hasValue()`/`.value()`. + +See [Helper Functions - Workload Helpers](./helper-functions.md#workload-helpers) for details. + +### configurations + +Configuration and secret references extracted from the workload container. + +| Field | Type | Description | +| ------------------------------ | -------- | -------------------------------------------------------- | +| `configurations.configs.envs` | []object | Environment variable configs (each has `name`, `value`) | +| `configurations.configs.files` | []object | File configs (each has `name`, `mountPath`, `value`) | +| `configurations.secrets.envs` | []object | Secret env vars (each has `name`, `value`, `remoteRef`) | +| `configurations.secrets.files` | []object | Secret files (each has `name`, `mountPath`, `remoteRef`) | + +The `remoteRef` object contains: `key`, `property` (optional), `version` (optional). + +**Usage:** + +```yaml +# Access config envs +env: | + ${configurations.configs.envs.map(e, {"name": e.name, "value": e.value})} + +# Check if there are config files +includeWhen: ${has(configurations.configs.files) && configurations.configs.files.size() > 0} +``` + +See [Configuration Helpers](./helper-functions.md) for helper functions that simplify working with configurations. + +### dependencies + +Resolved dependency metadata and environment variables from the component's Workload connections. Dependencies represent how this component consumes endpoints exposed by other components. The platform resolves connection targets at deployment time and provides the resulting addresses as environment variables. + +| Field | Type | Description | +| -------------------------------------- | -------- | ---------------------------------------------------------- | +| `dependencies.items` | []object | List of individual connection entries with target metadata | +| `dependencies.items[].namespace` | string | Namespace of the target component | +| `dependencies.items[].project` | string | Project of the target component | +| `dependencies.items[].component` | string | Name of the target component | +| `dependencies.items[].endpoint` | string | Name of the target endpoint | +| `dependencies.items[].visibility` | string | Visibility level (`project`, `namespace`) | +| `dependencies.items[].envVars` | []object | Resolved environment variables for this connection | +| `dependencies.items[].envVars[].name` | string | Environment variable name (from Workload `envBindings`) | +| `dependencies.items[].envVars[].value` | string | Resolved value (e.g., `http://svc-a:8080/api`) | +| `dependencies.envVars` | []object | Flat merged list of all env vars from all dependencies | +| `dependencies.envVars[].name` | string | Environment variable name | +| `dependencies.envVars[].value` | string | Resolved value | + +The `envVars` top-level field is automatically merged from all `items[].envVars`, providing a flat list suitable for injecting directly into container `env` blocks. + +**Usage:** + +```yaml +# Inject all dependency env vars into a container using the helper macro +containers: + - name: main + image: ${workload.container.image} + env: ${dependencies.toContainerEnvs()} + +# Access the flat envVars list directly (equivalent to toContainerEnvs()) +env: ${dependencies.envVars} + +# Conditional: only include env if there are dependencies +env: | + ${dependencies.envVars.size() > 0 ? dependencies.envVars : oc_omit()} +``` + +#### dependencies.toContainerEnvs() + +A helper macro that returns the merged list of all dependency environment variables. This is a compile-time rewrite to `dependencies.envVars` and is the recommended way to inject dependency env vars into containers. + +**Returns:** List of objects with `name` (string) and `value` (string). + +**Example:** + +```yaml +spec: + containers: + - name: main + image: ${workload.container.image} + env: ${dependencies.toContainerEnvs()} + envFrom: ${configurations.toContainerEnvFrom()} +``` + +### dataplane + +Data plane configuration. + +| Field | Type | Description | +| ----------------------- | ------ | --------------------------------------------------- | +| `dataplane.secretStore` | string | Name of the ClusterSecretStore for external secrets | + +**Usage:** + +```yaml +# ExternalSecret configuration +spec: + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore +``` + +### gateway + +Ingress gateway configuration for routing traffic to components. + +| Field | Type | Description | +| ------------------------------------ | ------ | ------------------------------------------------------------------ | +| `gateway.ingress.external.name` | string | Name of the external ingress Gateway resource | +| `gateway.ingress.external.namespace` | string | Namespace of the external ingress Gateway resource | +| `gateway.ingress.external.http` | object | HTTP listener config (optional; has `.host`) | +| `gateway.ingress.external.https` | object | HTTPS listener config (optional; has `.host`) | +| `gateway.ingress.internal.name` | string | Name of the internal ingress Gateway resource | +| `gateway.ingress.internal.namespace` | string | Namespace of the internal ingress Gateway resource | +| `gateway.ingress.internal.http` | object | HTTP listener config for internal gateway (optional; has `.host`) | +| `gateway.ingress.internal.https` | object | HTTPS listener config for internal gateway (optional; has `.host`) | + +**Usage:** + +```yaml +# HTTPRoute targeting the external gateway +parentRefs: + - name: ${gateway.ingress.external.name} + namespace: ${gateway.ingress.external.namespace} + +# Build hostnames from available HTTP/HTTPS listeners +hostnames: | + ${[gateway.ingress.external.?http, gateway.ingress.external.?https] + .filter(g, g.hasValue()).map(g, g.value().host).distinct() + .map(h, oc_dns_label(endpoint, metadata.componentName, metadata.environmentName, metadata.componentNamespace) + "." + h)} +``` + +## Trait Variables + +Traits have access to all the same variables as ComponentTypes, plus trait-specific variables. + +### trait + +Trait-specific metadata. + +| Field | Type | Description | +| -------------------- | ------ | ---------------------------------------------------------------- | +| `trait.name` | string | Name of the trait (e.g., `persistent-volume`) | +| `trait.instanceName` | string | Unique instance name within the component (e.g., `data-storage`) | + +**Usage:** + +```yaml +# Use trait instance name for resource naming +metadata: + name: ${metadata.name}-${trait.instanceName} + +# Use trait name in labels +labels: + trait: ${trait.name} + instance: ${trait.instanceName} +``` + +### parameters (Traits) + +Trait instance parameters from `Component.spec.traits[].parameters` with schema defaults applied. + +```yaml +# Access trait-specific parameters +volumeMounts: + - name: ${parameters.volumeName} + mountPath: ${parameters.mountPath} +``` + +### environmentConfigs (Traits) + +Environment-specific configuration from `ReleaseBinding.spec.traitEnvironmentConfigs[instanceName]`, pruned to the Trait's `environmentConfigs` schema with defaults applied. + +```yaml +# Access environment-specific trait values +resources: + requests: + storage: ${environmentConfigs.size} +storageClassName: ${environmentConfigs.storageClass} +``` + +## Variable Availability Summary + +| Variable | Workflow | ComponentType | Trait creates | Trait patches | +| ------------------------- | -------- | ------------- | ------------- | ---------------- | +| `metadata.*` | Yes | Yes | Yes | Yes | +| `parameters` | Yes | Yes | Yes | Yes | +| `externalRefs` | Yes | No | No | No | +| `workflowplane.*` | Yes | No | No | No | +| `environmentConfigs` | No | Yes | Yes | Yes | +| `workload.container.*` | No | Yes | No | No | +| `workload.endpoints.*` | No | Yes | No | No | +| `configurations.*` | No | Yes | No | No | +| `dependencies.*` | No | Yes | Yes | Yes | +| `dataplane.*` | No | Yes | Yes | Yes | +| `gateway.*` | No | Yes | Yes | Yes | +| `trait.*` | No | No | Yes | Yes | +| `resource` (patch target) | No | No | No | Yes (in `where`) | + +## Examples + +### ComponentType Using All Variables + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: ComponentType +metadata: + name: web-service +spec: + workloadType: deployment + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + labels: ${metadata.labels} + spec: + replicas: ${environmentConfigs.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${metadata.podSelectors} + spec: + containers: + - name: main + image: ${workload.container.image} + ports: + - containerPort: ${parameters.port} + env: ${dependencies.toContainerEnvs()} + envFrom: ${configurations.toContainerEnvFrom()} +``` + +### Trait Using Trait-Specific Variables + +```yaml +apiVersion: openchoreo.dev/v1alpha1 +kind: Trait +metadata: + name: persistent-volume +spec: + creates: + - template: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: ${metadata.name}-${trait.instanceName} + namespace: ${metadata.namespace} + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: ${environmentConfigs.storageClass} + resources: + requests: + storage: ${environmentConfigs.size} +``` + +## Related Resources + +- [Built-in Functions](./built-in-functions.md) - Functions available in templates +- [Configuration Helpers](./helper-functions.md) - Helper functions for configurations +- [Templating Syntax](../../platform-engineer-guide/component-types/templating-syntax.md) - Expression syntax and resource control diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/cel/helper-functions.md b/versioned_docs/version-v1.2.0-rc.2/reference/cel/helper-functions.md new file mode 100644 index 00000000..c4c36bec --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/cel/helper-functions.md @@ -0,0 +1,786 @@ +--- +title: Helper Functions +description: CEL extension functions for working with configurations, dependencies, and workloads in ComponentType templates +--- + +# Helper Functions + +Helper functions are CEL extension functions that provide convenient methods to work with context objects in your templates. They reduce boilerplate and make templates more readable. + +## Configuration Helpers + +These helpers simplify working with container configurations, environment variables, and file mounts. All configuration helper functions are available on the `configurations` context object. + +### toContainerEnvFrom() + +Generates an `envFrom` array for the container configuration, creating `configMapRef` and `secretRef` entries based on available environment variables. + +**Parameters:** None + +**Returns:** List of envFrom entries, each containing either: + +| Field | Type | Description | +| -------------- | ---- | ------------------------------------------------------------------ | +| `configMapRef` | map | Reference to ConfigMap (only present if container has config envs) | +| `secretRef` | map | Reference to Secret (only present if container has secret envs) | + +**Examples:** + +```yaml +# Using helper function +spec: + template: + spec: + containers: + - name: main + image: myapp:latest + envFrom: ${configurations.toContainerEnvFrom()} + +# Equivalent manual implementation +envFrom: | + ${(has(configurations.configs.envs) && configurations.configs.envs.size() > 0 ? + [{ + "configMapRef": { + "name": oc_generate_name(metadata.name, "env-configs") + } + }] : []) + + (has(configurations.secrets.envs) && configurations.secrets.envs.size() > 0 ? + [{ + "secretRef": { + "name": oc_generate_name(metadata.name, "env-secrets") + } + }] : [])} + +# Combine with additional envFrom entries +envFrom: | + ${configurations.toContainerEnvFrom() + + [{"configMapRef": {"name": "external-config"}}]} +``` + +### toConfigEnvsByContainer() + +Generates a list of objects for creating ConfigMaps from environment variables. Each object contains the container name, generated resource name, and environment variables. + +**Parameters:** None + +**Returns:** List of objects, each containing: + +| Field | Type | Description | +| -------------- | ------ | --------------------------------------------------------------------------------------- | +| `container` | string | Name of the container | +| `resourceName` | string | Generated ConfigMap name (componentName-environmentName-containerName-env-configs-hash) | +| `envs` | array | List of environment variable objects with `name` and `value` | + +**Examples:** + +```yaml +# Using helper function +- id: env-config + forEach: ${configurations.toConfigEnvsByContainer()} + var: envConfig + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${envConfig.resourceName} + namespace: ${metadata.namespace} + data: | + ${envConfig.envs.transformMapEntry(index, env, {env.name: env.value})} + +# Equivalent manual implementation +- id: env-config + forEach: | + ${configurations.transformList(containerName, cfg, + { + "container": containerName, + "resourceName": oc_generate_name(metadata.name, containerName, "env-configs"), + "envs": cfg.configs.envs + } + )} + var: envConfig + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${envConfig.resourceName} + namespace: ${metadata.namespace} + data: | + ${envConfig.envs.transformMapEntry(index, env, {env.name: env.value})} +``` + +**Notes:** + +- Only returns entries for containers that have config environment variables +- Skips containers with no config envs or only secret envs +- Generated resource names include container name and a hash for uniqueness + +### toSecretEnvsByContainer() + +Generates a list of objects for creating ExternalSecrets from secret environment variables. Each object contains the container name, generated resource name, and secret environment variables. + +**Parameters:** None + +**Returns:** List of objects, each containing: + +| Field | Type | Description | +| -------------- | ------ | -------------------------------------------------------------------------------------------- | +| `container` | string | Name of the container | +| `resourceName` | string | Generated ExternalSecret name (componentName-environmentName-containerName-env-secrets-hash) | +| `envs` | array | List of secret environment variable objects with `name` and `remoteRef` | + +**Examples:** + +```yaml +# Using helper function +- id: secret-env-external + forEach: ${configurations.toSecretEnvsByContainer()} + var: secretEnv + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${secretEnv.resourceName} + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: ${secretEnv.resourceName} + creationPolicy: Owner + data: | + ${secretEnv.envs.map(secret, { + "secretKey": secret.name, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) ? secret.remoteRef.property : oc_omit() + } + })} + +# Equivalent manual implementation +- id: secret-env-external + forEach: | + ${configurations.transformList(containerName, cfg, + { + "container": containerName, + "resourceName": oc_generate_name(metadata.name, containerName, "env-secrets"), + "envs": cfg.secrets.envs + } + )} + var: secretEnv + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${secretEnv.resourceName} + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: ${secretEnv.resourceName} + creationPolicy: Owner + data: | + ${secretEnv.envs.map(secret, { + "secretKey": secret.name, + "remoteRef": { + "key": secret.remoteRef.key, + "property": has(secret.remoteRef.property) ? secret.remoteRef.property : oc_omit() + } + })} +``` + +**Notes:** + +- Only returns entries for containers that have secret environment variables +- Skips containers with no secret envs or only config envs +- Generated resource names include container name and a hash for uniqueness + +### toConfigFileList() + +Flattens `configs.files` from all containers into a single list. Each file includes a generated `resourceName` for creating ConfigMaps. + +**Parameters:** None + +**Returns:** List of file objects, each containing: + +| Field | Type | Description | +| -------------- | ------ | ---------------------------------------------------------------------------------------------------------- | +| `name` | string | File name | +| `mountPath` | string | Mount path | +| `value` | string | File content (empty string if using remoteRef) | +| `resourceName` | string | Generated Kubernetes-compliant resource name (componentName-environmentName-containerName-config-fileName) | +| `remoteRef` | map | Remote reference (only present if the file uses a secret reference) | + +**Examples:** + +```yaml +# Generate a ConfigMap for each config file +- id: file-configs + forEach: ${configurations.toConfigFileList()} + var: config + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${config.resourceName} + namespace: ${metadata.namespace} + data: + ${config.name}: | + ${config.value} +``` + +**Equivalent CEL expression:** + +If you need additional fields (e.g., `container` name) or different behavior, use the underlying data directly: + +```yaml +forEach: | + ${configurations.transformList(containerName, cfg, + cfg.configs.files.map(f, oc_merge(f, { + "container": containerName, + "resourceName": oc_generate_name(metadata.name, containerName, "config", f.name.replace(".", "-")) + })) + ).flatten()} +``` + +### toSecretFileList() + +Flattens `secrets.files` from all containers into a single list. Each file includes a generated `resourceName` for creating Secrets or ExternalSecrets. + +**Parameters:** None + +**Returns:** List of file objects, each containing: + +| Field | Type | Description | +| -------------- | ------ | ---------------------------------------------------------------------------------------------------------- | +| `name` | string | File name | +| `mountPath` | string | Mount path | +| `value` | string | File content (empty string if using remoteRef) | +| `resourceName` | string | Generated Kubernetes-compliant resource name (componentName-environmentName-containerName-secret-fileName) | +| `remoteRef` | map | Remote reference (only present if the file uses a secret reference) | + +**Examples:** + +```yaml +# Generate ExternalSecrets for secret files +- id: file-secrets + forEach: ${configurations.toSecretFileList()} + var: secret + includeWhen: ${has(secret.remoteRef)} + template: + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: ${secret.resourceName} + namespace: ${metadata.namespace} + spec: + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: ${secret.resourceName} + creationPolicy: Owner + data: + - secretKey: ${secret.name} + remoteRef: + key: ${secret.remoteRef.key} + property: ${secret.remoteRef.property} + +# Generate Secrets for files with inline values +- id: inline-file-secrets + forEach: ${configurations.toSecretFileList()} + var: secret + includeWhen: ${!has(secret.remoteRef) && secret.value != ""} + template: + apiVersion: v1 + kind: Secret + metadata: + name: ${secret.resourceName} + namespace: ${metadata.namespace} + data: + ${secret.name}: ${base64.encode(secret.value)} +``` + +**Equivalent CEL expression:** + +```yaml +forEach: | + ${configurations.transformList(containerName, cfg, + cfg.secrets.files.map(f, oc_merge(f, { + "container": containerName, + "resourceName": oc_generate_name(metadata.name, containerName, "secret", f.name.replace(".", "-")) + })) + ).flatten()} +``` + +### toContainerVolumeMounts() + +Generates a `volumeMounts` array for the container's config and secret files. + +**Parameters:** None + +**Returns:** List of volumeMount entries, each containing: + +| Field | Type | Description | +| ----------- | ------ | -------------------------------------------- | +| `name` | string | Volume name (`file-mount-{hash}` format) | +| `mountPath` | string | Full mount path (mountPath + "/" + filename) | +| `subPath` | string | Filename to mount as subPath | + +**Examples:** + +```yaml +# Using helper function +spec: + template: + spec: + containers: + - name: main + image: myapp:latest + volumeMounts: ${configurations.toContainerVolumeMounts()} + +# Equivalent manual implementation +volumeMounts: | + ${has(configurations.configs.files) && configurations.configs.files.size() > 0 || has(configurations.secrets.files) && configurations.secrets.files.size() > 0 ? + (has(configurations.configs.files) && configurations.configs.files.size() > 0 ? + configurations.configs.files.map(f, { + "name": "file-mount-"+oc_hash(f.mountPath+"/"+f.name), + "mountPath": f.mountPath+"/"+f.name , + "subPath": f.name + }) : []) + + (has(configurations.secrets.files) && configurations.secrets.files.size() > 0 ? + configurations.secrets.files.map(f, { + "name": "file-mount-"+oc_hash(f.mountPath+"/"+f.name), + "mountPath": f.mountPath+"/"+f.name, + "subPath": f.name + }) : []) + : oc_omit()} + +# Combine with additional volume mounts +volumeMounts: | + ${configurations.toContainerVolumeMounts() + + [{"name": "cache", "mountPath": "/cache"}]} +``` + +### toVolumes() + +Generates a `volumes` array for all containers' config and secret files. + +**Parameters:** None + +**Returns:** List of volume entries, each containing: + +| Field | Type | Description | +| ----------- | ------ | ------------------------------------------------------------ | +| `name` | string | Volume name (generated using hash of mountPath and filename) | +| `configMap` | map | ConfigMap volume source (only present for config files) | +| `secret` | map | Secret volume source (only present for secret files) | + +**Examples:** + +```yaml +# Using helper function +spec: + template: + spec: + containers: + - name: main + image: myapp:latest + volumeMounts: ${configurations.toContainerVolumeMounts()} + volumes: ${configurations.toVolumes()} + +# Equivalent manual implementation +volumes: | + ${has(configurations.configs.files) && configurations.configs.files.size() > 0 || has(configurations.secrets.files) && configurations.secrets.files.size() > 0 ? + (has(configurations.configs.files) && configurations.configs.files.size() > 0 ? + configurations.configs.files.map(f, { + "name": "file-mount-"+oc_hash(f.mountPath+"/"+f.name), + "configMap": { + "name": oc_generate_name(metadata.name, "config", f.name).replace(".", "-") + } + }) : []) + + (has(configurations.secrets.files) && configurations.secrets.files.size() > 0 ? + configurations.secrets.files.map(f, { + "name": "file-mount-"+oc_hash(f.mountPath+"/"+f.name), + "secret": { + "secretName": oc_generate_name(metadata.name, "secret", f.name).replace(".", "-") + } + }) : []) + : oc_omit()} + +# Combine with inline volumes +volumes: | + ${configurations.toVolumes() + + [{"name": "extra-volume", "emptyDir": {}}]} +``` + +## Dependency Helpers + +These helpers simplify injecting resolved dependency environment variables into containers. Available on the `dependencies` context object. + +### dependencies.toContainerEnvs() + +Returns the merged flat list of all dependency environment variables. This is a compile-time macro that rewrites to `dependencies.envVars` and is the recommended way to inject dependency env vars into containers. + +**Parameters:** None + +**Returns:** List of environment variable objects, each containing: + +| Field | Type | Description | +| ------- | ------ | ------------------------------------------------------- | +| `name` | string | Environment variable name (from Workload `envBindings`) | +| `value` | string | Resolved value (e.g., `http://svc-a:8080/api`) | + +**Examples:** + +```yaml +# Using helper function +spec: + template: + spec: + containers: + - name: main + image: ${workload.container.image} + env: ${dependencies.toContainerEnvs()} + +# Equivalent manual implementation +env: ${dependencies.envVars} +``` + +**Notes:** + +- Each dependency item in `dependencies.items[]` has its own `envVars` list; this helper merges all of them into a single flat list +- If there are no dependencies, returns an empty list `[]` +- For per-dependency details (target component, endpoint, visibility), use `dependencies.items` directly + +## Workload Helpers + +These helpers simplify working with endpoint configurations. Available on the `workload` context object. + +### workload.toServicePorts() + +Converts a workload's endpoints into Kubernetes Service port definitions, automatically mapping endpoint configurations to the proper service port format. + +**Parameters:** None (operates on workload.endpoints) + +**Returns:** List of service port objects, each containing: + +| Field | Type | Description | +| ------------ | ------- | --------------------------------------------------------------------------- | +| `name` | string | Port name (derived from endpoint name, DNS-compliant) | +| `port` | integer | Service port number (from endpoint.port) | +| `targetPort` | integer | Target port on pods (from endpoint.targetPort or defaults to endpoint.port) | +| `protocol` | string | Protocol (derived from endpoint.type, defaults to "TCP") | + +**Endpoint Type Mapping:** + +| Endpoint Type | Service Protocol | +| ----------------- | ---------------- | +| `HTTP`, `GraphQL` | `TCP` | +| `gRPC` | `TCP` | +| `Websocket` | `TCP` | +| `TCP` | `TCP` | +| `UDP` | `UDP` | + +**Examples:** + +```yaml +# Service resource using helper function +- id: service + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.componentName} + namespace: ${metadata.namespace} + spec: + selector: ${metadata.podSelectors} + ports: ${workload.toServicePorts()} + +# Equivalent manual implementation +ports: | + ${workload.endpoints.map(name, ep, { + "name": oc_dns_label(name), + "port": ep.port, + "targetPort": has(ep.targetPort) ? ep.targetPort : ep.port, + "protocol": ep.type in ["UDP"] ? "UDP" : "TCP" + })} +``` + +**Input Requirements:** + +- `workload.endpoints` must be a map where each key is an endpoint name +- Each endpoint must have a `port` field (integer, 1-65535) +- Each endpoint should have a `type` field for protocol mapping +- Each endpoint may have a `targetPort` field (integer, defaults to `port` value) +- Each endpoint may have a `visibility` field (array of visibility levels: `external`, `internal`, `namespace`, `project`) +- Each endpoint may have `displayName` and `basePath` fields for documentation and routing + +**Behavior:** + +- Filters out any endpoints without a valid `port` field +- Generates DNS-compliant port names using `oc_dns_label()` +- Maps endpoint types to appropriate Kubernetes service protocols +- Uses `targetPort` if specified, otherwise defaults to `port` value +- Includes all endpoints regardless of visibility level (visibility is handled separately in routing resources) +- Returns empty list if no valid endpoints are found + +**Edge Cases:** + +- Empty `workload.endpoints`: Returns empty array `[]` +- Endpoint missing `port`: Endpoint is skipped +- Endpoint missing `type`: Defaults to "TCP" protocol +- Endpoint missing `targetPort`: Uses `port` value for `targetPort` +- Invalid endpoint names: Converted to DNS-compliant format using `oc_dns_label()` + +**Usage in Templates:** + +```yaml +# Basic service +spec: + selector: ${metadata.podSelectors} + ports: ${workload.toServicePorts()} + +# Service with additional ports +spec: + selector: ${metadata.podSelectors} + ports: | + ${workload.toServicePorts() + [ + {"name": "metrics", "port": 9090, "targetPort": 9090} + ]} + +# Conditional service creation +- id: service + includeWhen: ${size(workload.endpoints) > 0} + template: + apiVersion: v1 + kind: Service + metadata: + name: ${metadata.componentName} + spec: + ports: ${workload.toServicePorts()} + +# HTTPRoute using endpoint details directly (not toServicePorts()) +- id: httproute-external + forEach: '${workload.endpoints.transformList(name, ep, ("external" in ep.visibility) ? [name] : []).flatten()}' + var: endpoint + template: + apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: ${oc_generate_name(metadata.componentName, endpoint)} + spec: + rules: + - matches: + - path: + type: PathPrefix + value: /${metadata.componentName}-${endpoint} + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: '${workload.endpoints[endpoint].?basePath.orValue("/")}' + backendRefs: + - name: ${metadata.componentName} + port: ${workload.endpoints[endpoint].port} +``` + +**Notes:** + +- This helper only works with Service resources; for HTTPRoute backend references, use `workload.endpoints[endpointName].port` directly +- Port names are automatically generated and may differ from original endpoint names to ensure DNS compliance +- The helper maintains a consistent mapping between endpoint configurations and service definitions +- **Visibility handling**: The `visibility` attribute is not processed by this helper. Use visibility in routing resources (HTTPRoute, Gateway) to control endpoint exposure: + - `external`: Accessible from outside the cluster + - `internal`: Accessible within the cluster but not externally + - `namespace`: Accessible only within the same namespace + - `project`: Accessible only within the same project (implicit for all endpoints) +- **BasePath usage**: For HTTPRoute path rewriting, use `workload.endpoints[endpointName].basePath` to configure URL path prefixes +- **TargetPort distinction**: `targetPort` (container listening port) vs `port` (service port) - the helper uses the correct values for each + +### workload.toEndpointResources(endpointName) + +Parses a single endpoint's API schema (the OpenAPI document for HTTP endpoints, the protobuf definition for gRPC endpoints) and returns the flat list of routes it declares. This lets a ComponentType render **exact** per-route gateway matches (one match per OpenAPI path/method, or per gRPC service/method) instead of a single catch-all rule. + +This helper is **opt-in**: endpoint schemas are only parsed when a template actually calls `workload.toEndpointResources(...)`, so templates that don't use it pay no parsing cost. + +**Parameters:** + +| Parameter | Type | Description | +| -------------- | ------ | ------------------------------------------------------------------------------------ | +| `endpointName` | string | The endpoint map key (e.g. `"http"`, `"grpc"`), the key used in `workload.endpoints` | + +**Returns:** a CEL **optional** wrapping a list of route objects. Consume it with `.orValue([])`, or guard with `.hasValue()` / `.value()`. Each route object contains: + +| Field | Type | Description | +| --------- | ------ | --------------------------------------------------------------------------------------- | +| `kind` | string | Protocol of the route: `"HTTP"` or `"gRPC"` | +| `service` | string | Fully-qualified gRPC service name (e.g. `greeter.Greeter`). Empty for HTTP routes | +| `method` | string | HTTP verb (`GET`/`POST`/...) for HTTP routes, or the gRPC method name (e.g. `SayHello`) | +| `path` | string | HTTP path template (e.g. `/v1/pets/{id}`). Empty for gRPC routes | + +Routes are returned in a deterministic (sorted) order so rendered output is stable. + +:::note Best-effort extraction +A missing, empty, or unparseable schema (or an endpoint protocol with no extractor, such as TCP/UDP) yields an empty list, never a render failure. Schema format is inferred from the endpoint type (`HTTP` → OpenAPI, `gRPC` → protobuf) unless `workload.endpoints[name].schema.type` overrides it. Only OpenAPI and protobuf extractors exist today; GraphQL and AsyncAPI are reserved and currently degrade to an empty list. +::: + +**Examples:** + +```yaml +# gRPC: render one GRPCRoute match per (service, method) from the proto schema. +# Falls back to a catch-all rule (no matches) when the endpoint has no parseable schema. +rules: + - matches: >- + ${workload.toEndpointResources(endpoint.key).hasValue() + ? workload.toEndpointResources(endpoint.key).value().map(r, + {"method": {"type": "Exact", "service": r.service, "method": r.method}}) + : oc_omit()} + backendRefs: + - name: ${metadata.componentName} + port: ${endpoint.value.port} +``` + +```yaml +# HTTP: render one HTTPRoute rule per (path, method) from the OpenAPI schema. +# Parameterized paths (/books/{id}) become a RegularExpression match; static paths use Exact. +rules: >- + ${workload.toEndpointResources(endpoint.key).orValue([]).map(r, { + "matches": [{ + "path": { + "type": r.path.contains("{") ? "RegularExpression" : "Exact", + "value": r.path.contains("{") + ? r.path.split("/").map(s, s.startsWith("{") ? "[^/]+" : s).join("/") + : r.path + }, + "method": r.method + }], + "backendRefs": [{"name": metadata.componentName, "port": endpoint.value.port}] + })} +``` + +**Notes:** + +- Returns a CEL optional, not a plain list, so always unwrap with `.orValue([])` or `.hasValue()`/`.value()`. +- Reads from `workload.endpoints[endpointName].schema`; an endpoint with no schema yields an empty list. +- Complete, runnable ComponentType examples ship in the OpenChoreo repo under `samples/component-types/component-grpc-service/` and `samples/component-types/component-http-openapi-service/`. + +## Common Usage Patterns + +### Complete Deployment with Configurations + +```yaml +spec: + workloadType: deployment + resources: + - id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + replicas: ${parameters.replicas} + selector: + matchLabels: ${metadata.podSelectors} + template: + metadata: + labels: ${oc_merge(metadata.labels, metadata.podSelectors)} + spec: + containers: + - name: main + image: ${workload.container.image} + env: ${dependencies.toContainerEnvs()} + envFrom: ${configurations.toContainerEnvFrom()} + volumeMounts: ${configurations.toContainerVolumeMounts()} + volumes: ${configurations.toVolumes()} + + # Generate ConfigMaps for environment variables + - id: env-configs + forEach: ${configurations.toConfigEnvsByContainer()} + var: envConfig + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${envConfig.resourceName} + namespace: ${metadata.namespace} + data: | + ${envConfig.envs.transformMapEntry(i, e, {e.name: e.value})} + + # Generate ExternalSecrets for secret environment variables + - id: env-secrets + forEach: ${configurations.toSecretEnvsByContainer()} + var: secretEnv + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: ${secretEnv.resourceName} + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: ${secretEnv.resourceName} + creationPolicy: Owner + data: | + ${secretEnv.envs.map(e, { + "secretKey": e.name, + "remoteRef": { + "key": e.remoteRef.key, + "property": has(e.remoteRef.property) ? e.remoteRef.property : oc_omit() + } + })} + + # Generate ConfigMaps for config files + - id: config-files + forEach: ${configurations.toConfigFileList()} + var: config + template: + apiVersion: v1 + kind: ConfigMap + metadata: + name: ${config.resourceName} + namespace: ${metadata.namespace} + data: + ${config.name}: | + ${config.value} + + # Generate ExternalSecrets for secret files + - id: secret-files + forEach: ${configurations.toSecretFileList()} + var: secret + includeWhen: ${has(secret.remoteRef)} + template: + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: ${secret.resourceName} + namespace: ${metadata.namespace} + spec: + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: ${secret.resourceName} + creationPolicy: Owner + data: + - secretKey: ${secret.name} + remoteRef: + key: ${secret.remoteRef.key} + property: ${secret.remoteRef.property} +``` + +## See Also + +- [ComponentType API Reference](../api/platform/componenttype.md) - ComponentType resource documentation +- [Context Variables](./context-variables.md) - Complete workload context reference diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/cli-reference.md b/versioned_docs/version-v1.2.0-rc.2/reference/cli-reference.md new file mode 100644 index 00000000..4262842d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/cli-reference.md @@ -0,0 +1,3160 @@ +--- +title: CLI Reference +description: Command-line reference for the occ tool to manage OpenChoreo resources +--- + +# CLI Reference + +The `occ` (OpenChoreo CLI) is a command-line interface tool for interacting with OpenChoreo. It provides commands to manage namespaces, projects, components, deployments, and other OpenChoreo resources. + +## CLI Management + +### completion + +Generate shell completion scripts for `occ`. The generated script provides auto-completion for commands, subcommands, flags, and resource names. + +**Usage:** + +```bash +occ completion +``` + +**Supported shells:** `bash`, `zsh`, `fish` + +**Examples:** + +```bash +# Generate bash completion script +occ completion bash + +# Generate zsh completion script +occ completion zsh + +# Generate fish completion script +occ completion fish + +# Load bash completions in the current session +source <(occ completion bash) + +# Load zsh completions in the current session +source <(occ completion zsh) +``` + +--- + +### config + +Manage CLI configuration including contexts, control planes, and credentials. + +**Usage:** + +```bash +occ config [flags] +``` + +The CLI stores its configuration in `~/.occ/config.yaml`. The configuration is made up of three concepts: + +- **Control planes**: API server endpoints that the CLI connects to (see [`config controlplane`](#config-controlplane)) +- **Credentials**: Authentication tokens for connecting to control planes (see [`config credentials`](#config-credentials)) +- **Contexts**: Named sets of defaults (namespace, project, etc.) that reference a control plane and credentials (see [`config context`](#config-context)) + +A typical setup flow is: add a control plane, add credentials, then create a context that ties them together. + +**Configuration file structure:** + +```yaml +currentContext: my-context +controlplanes: + - name: production + url: https://api.openchoreo.example.com +credentials: + - name: my-creds + clientId: + clientSecret: + token: + refreshToken: + authMethod: pkce # or "client_credentials" +contexts: + - name: my-context + controlplane: production + credentials: my-creds + namespace: acme-corp + project: online-store + component: product-catalog + mode: api-server # or "file-system" + rootDirectoryPath: /path/to/resources # for file-system mode +``` + +**Modes:** + +The CLI supports two modes: + +1. **API Server Mode** (`api-server`): Connects to an OpenChoreo API server to manage resources remotely. This is the default mode. +2. **File System Mode** (`file-system`): Works with resources stored as YAML files in a directory structure. Useful for GitOps workflows and local development. + +#### config controlplane + +Manage control plane configurations that define OpenChoreo API server endpoints. A control plane must be configured before it can be referenced in a context. + +##### config controlplane add + +Add a new control plane configuration. + +**Usage:** + +```bash +occ config controlplane add [flags] +``` + +**Flags:** + +- `--url` - OpenChoreo API server endpoint URL (required) + +**Examples:** + +```bash +# Add a remote control plane +occ config controlplane add production --url https://api.openchoreo.example.com + +# Add a local control plane (for development) +occ config controlplane add local --url http://api.openchoreo.localhost:8080 +``` + +##### config controlplane list + +List all control plane configurations. + +**Usage:** + +```bash +occ config controlplane list +``` + +**Examples:** + +```bash +# Show all control planes +occ config controlplane list +``` + +##### config controlplane update + +Update a control plane configuration. + +**Usage:** + +```bash +occ config controlplane update [flags] +``` + +**Flags:** + +- `--url` - OpenChoreo API server endpoint URL + +**Examples:** + +```bash +# Update control plane URL +occ config controlplane update production --url https://new-api.openchoreo.example.com +``` + +##### config controlplane delete + +Delete a control plane configuration. + +**Usage:** + +```bash +occ config controlplane delete +``` + +**Examples:** + +```bash +# Delete a control plane +occ config controlplane delete old-prod +``` + +#### config credentials + +Manage authentication credentials for connecting to control planes. Credentials must be configured before they can be referenced in a context. + +##### config credentials add + +Add new authentication credentials. + +**Usage:** + +```bash +occ config credentials add +``` + +**Examples:** + +```bash +# Add new credentials (prompts for login) +occ config credentials add my-creds +``` + +##### config credentials list + +List all saved credentials. + +**Usage:** + +```bash +occ config credentials list +``` + +**Examples:** + +```bash +# Show all credentials +occ config credentials list +``` + +##### config credentials delete + +Delete saved credentials. + +**Usage:** + +```bash +occ config credentials delete +``` + +**Examples:** + +```bash +# Delete credentials +occ config credentials delete old-creds +``` + +#### config context + +Manage configuration contexts that store default values (e.g., namespace, project, component) for occ commands. A context references a [control plane](#config-controlplane) and [credentials](#config-credentials), which must be configured first. + +##### config context add + +Create a new configuration context. + +**Usage:** + +```bash +occ config context add [flags] +``` + +**Flags:** + +- `--controlplane` - Control plane name (required, see [`config controlplane add`](#config-controlplane-add)) +- `--credentials` - Credentials name (required, see [`config credentials add`](#config-credentials-add)) +- `-n, --namespace` - Namespace name stored in this configuration context +- `-p, --project` - Project name stored in this configuration context +- `-c, --component` - Component name stored in this configuration context + +**Examples:** + +```bash +# Create a new context with control plane and credentials +occ config context add acme-corp-context --controlplane production \ + --credentials my-creds --namespace acme-corp --project online-store + +# Create a minimal context +occ config context add dev-context --controlplane local --credentials dev-creds +``` + +##### config context list + +List all available configuration contexts. + +**Usage:** + +```bash +occ config context list +``` + +**Examples:** + +```bash +# Show all configuration contexts +occ config context list +``` + +##### config context update + +Update an existing configuration context. + +**Usage:** + +```bash +occ config context update [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name stored in this configuration context +- `-p, --project` - Project name stored in this configuration context +- `-c, --component` - Component name stored in this configuration context +- `--controlplane` - Control plane name +- `--credentials` - Credentials name + +**Examples:** + +```bash +# Update namespace and project +occ config context update acme-corp-context --namespace acme-corp --project online-store + +# Update control plane +occ config context update acme-corp-context --controlplane production +``` + +##### config context use + +Switch to a specified configuration context. + +**Usage:** + +```bash +occ config context use +``` + +**Examples:** + +```bash +# Switch to the configuration context named acme-corp-context +occ config context use acme-corp-context +``` + +##### config context delete + +Delete a configuration context. + +**Usage:** + +```bash +occ config context delete +``` + +**Examples:** + +```bash +# Delete a context +occ config context delete old-context +``` + +--- + +### login + +Login to OpenChoreo CLI. + +**Usage:** + +```bash +occ login [flags] +``` + +**Flags:** + +- `--client-credentials` - Use OAuth2 client credentials flow for authentication +- `--client-id` - OAuth2 client ID for service account authentication +- `--client-secret` - OAuth2 client secret for service account authentication +- `--credential` - Name to save the credential as in config + +**Examples:** + +```bash +# Interactive login (default PKCE flow) +occ login + +# Service account login with client credentials +occ login --client-credentials --client-id --client-secret +``` + +--- + +### logout + +Logout from OpenChoreo CLI. + +**Usage:** + +```bash +occ logout +``` + +**Examples:** + +```bash +occ logout +``` + +--- + +### version + +Print version information for both the CLI client and the OpenChoreo server. + +**Usage:** + +```bash +occ version +``` + +**Examples:** + +```bash +occ version +``` + +--- + +## Resource Management + +### apply + +Apply a configuration file to create or update OpenChoreo resources. + +**Usage:** + +```bash +occ apply -f +``` + +**Flags:** + +- `-f, --file` - Path to the YAML file containing resource definitions + +**Examples:** + +```bash +# Apply a namespace configuration +occ apply -f namespace.yaml + +# Apply a component configuration +occ apply -f my-component.yaml +``` + +--- + +### authzrole + +Manage authorization roles in OpenChoreo. + +**Usage:** + +```bash +occ authzrole [flags] +``` + +**Aliases:** `authzroles`, `ar` + +#### authzrole list + +List all authorization roles in a namespace. + +**Usage:** + +```bash +occ authzrole list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all authz roles in a namespace +occ authzrole list --namespace acme-corp +``` + +#### authzrole get + +Get details of a specific authorization role. + +**Usage:** + +```bash +occ authzrole get [NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific authz role +occ authzrole get developer --namespace acme-corp +``` + +#### authzrole delete + +Delete an authorization role. + +**Usage:** + +```bash +occ authzrole delete [NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete an authz role +occ authzrole delete developer --namespace acme-corp +``` + +--- + +### authzrolebinding + +Manage authorization role bindings in OpenChoreo. + +**Usage:** + +```bash +occ authzrolebinding [flags] +``` + +**Aliases:** `authzrolebindings`, `arb` + +#### authzrolebinding list + +List all authorization role bindings in a namespace. + +**Usage:** + +```bash +occ authzrolebinding list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all authz role bindings in a namespace +occ authzrolebinding list --namespace acme-corp +``` + +#### authzrolebinding get + +Get details of a specific authorization role binding. + +**Usage:** + +```bash +occ authzrolebinding get [NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific authz role binding +occ authzrolebinding get dev-binding --namespace acme-corp +``` + +#### authzrolebinding delete + +Delete an authorization role binding. + +**Usage:** + +```bash +occ authzrolebinding delete [NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete an authz role binding +occ authzrolebinding delete dev-binding --namespace acme-corp +``` + +--- + +### clusterauthzrole + +Manage authorization cluster roles in OpenChoreo. + +**Usage:** + +```bash +occ clusterauthzrole [flags] +``` + +**Aliases:** `clusterauthzroles`, `car` + +#### clusterauthzrole list + +List all authorization cluster roles. + +**Usage:** + +```bash +occ clusterauthzrole list +``` + +**Examples:** + +```bash +# List all authz cluster roles +occ clusterauthzrole list +``` + +#### clusterauthzrole get + +Get details of a specific authorization cluster role. + +**Usage:** + +```bash +occ clusterauthzrole get [NAME] +``` + +**Examples:** + +```bash +# Get a specific authz cluster role +occ clusterauthzrole get platform-admin +``` + +#### clusterauthzrole delete + +Delete an authorization cluster role. + +**Usage:** + +```bash +occ clusterauthzrole delete [NAME] +``` + +**Examples:** + +```bash +# Delete an authz cluster role +occ clusterauthzrole delete platform-admin +``` + +--- + +### clusterauthzrolebinding + +Manage authorization cluster role bindings in OpenChoreo. + +**Usage:** + +```bash +occ clusterauthzrolebinding [flags] +``` + +**Aliases:** `clusterauthzrolebindings`, `carb` + +#### clusterauthzrolebinding list + +List all authorization cluster role bindings. + +**Usage:** + +```bash +occ clusterauthzrolebinding list +``` + +**Examples:** + +```bash +# List all authz cluster role bindings +occ clusterauthzrolebinding list +``` + +#### clusterauthzrolebinding get + +Get details of a specific authorization cluster role binding. + +**Usage:** + +```bash +occ clusterauthzrolebinding get [NAME] +``` + +**Examples:** + +```bash +# Get a specific authz cluster role binding +occ clusterauthzrolebinding get admin-binding +``` + +#### clusterauthzrolebinding delete + +Delete an authorization cluster role binding. + +**Usage:** + +```bash +occ clusterauthzrolebinding delete [NAME] +``` + +**Examples:** + +```bash +# Delete an authz cluster role binding +occ clusterauthzrolebinding delete admin-binding +``` + +--- + +### clustercomponenttype + +Manage cluster-scoped component types in OpenChoreo. + +**Usage:** + +```bash +occ clustercomponenttype [flags] +``` + +**Aliases:** `cct`, `clustercomponenttypes` + +#### clustercomponenttype list + +List all cluster component types. + +**Usage:** + +```bash +occ clustercomponenttype list +``` + +**Examples:** + +```bash +# List all cluster component types +occ clustercomponenttype list +``` + +#### clustercomponenttype get + +Get details of a specific cluster component type. + +**Usage:** + +```bash +occ clustercomponenttype get [CLUSTER_COMPONENT_TYPE_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster component type +occ clustercomponenttype get web-app +``` + +#### clustercomponenttype delete + +Delete a cluster component type. + +**Usage:** + +```bash +occ clustercomponenttype delete [CLUSTER_COMPONENT_TYPE_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster component type +occ clustercomponenttype delete web-app +``` + +--- + +### clusterdataplane + +Manage cluster-scoped data planes in OpenChoreo. + +**Usage:** + +```bash +occ clusterdataplane +``` + +**Aliases:** `clusterdataplanes`, `cdp` + +#### clusterdataplane list + +List all cluster data planes. + +**Usage:** + +```bash +occ clusterdataplane list +``` + +**Examples:** + +```bash +# List all cluster data planes +occ clusterdataplane list +``` + +#### clusterdataplane get + +Get details of a specific cluster data plane. + +**Usage:** + +```bash +occ clusterdataplane get [CLUSTER_DATA_PLANE_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster data plane +occ clusterdataplane get default +``` + +#### clusterdataplane delete + +Delete a cluster data plane. + +**Usage:** + +```bash +occ clusterdataplane delete [CLUSTER_DATA_PLANE_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster data plane +occ clusterdataplane delete default +``` + +--- + +### clusterobservabilityplane + +Manage cluster-scoped observability planes in OpenChoreo. + +**Usage:** + +```bash +occ clusterobservabilityplane +``` + +**Aliases:** `clusterobservabilityplanes`, `cop` + +#### clusterobservabilityplane list + +List all cluster observability planes. + +**Usage:** + +```bash +occ clusterobservabilityplane list +``` + +**Examples:** + +```bash +# List all cluster observability planes +occ clusterobservabilityplane list +``` + +#### clusterobservabilityplane get + +Get details of a specific cluster observability plane. + +**Usage:** + +```bash +occ clusterobservabilityplane get [CLUSTER_OBSERVABILITY_PLANE_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster observability plane +occ clusterobservabilityplane get default +``` + +#### clusterobservabilityplane delete + +Delete a cluster observability plane. + +**Usage:** + +```bash +occ clusterobservabilityplane delete [CLUSTER_OBSERVABILITY_PLANE_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster observability plane +occ clusterobservabilityplane delete default +``` + +--- + +### clustertrait + +Manage cluster-scoped traits in OpenChoreo. + +**Usage:** + +```bash +occ clustertrait [flags] +``` + +**Aliases:** `clustertraits` + +#### clustertrait list + +List all cluster traits. + +**Usage:** + +```bash +occ clustertrait list +``` + +**Examples:** + +```bash +# List all cluster traits +occ clustertrait list +``` + +#### clustertrait get + +Get details of a specific cluster trait. + +**Usage:** + +```bash +occ clustertrait get [CLUSTER_TRAIT_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster trait +occ clustertrait get ingress +``` + +#### clustertrait delete + +Delete a cluster trait. + +**Usage:** + +```bash +occ clustertrait delete [CLUSTER_TRAIT_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster trait +occ clustertrait delete ingress +``` + +--- + +### clusterworkflow + +Manage cluster-scoped workflows in OpenChoreo. + +**Usage:** + +```bash +occ clusterworkflow [flags] +``` + +**Aliases:** `clusterworkflows` + +#### clusterworkflow list + +List all cluster workflows. + +**Usage:** + +```bash +occ clusterworkflow list +``` + +**Examples:** + +```bash +# List all cluster workflows +occ clusterworkflow list +``` + +#### clusterworkflow get + +Get details of a specific cluster workflow. + +**Usage:** + +```bash +occ clusterworkflow get [CLUSTER_WORKFLOW_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster workflow +occ clusterworkflow get build-go +``` + +#### clusterworkflow delete + +Delete a cluster workflow. + +**Usage:** + +```bash +occ clusterworkflow delete [CLUSTER_WORKFLOW_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster workflow +occ clusterworkflow delete build-go +``` + +#### clusterworkflow run + +Run a cluster workflow with optional parameters. Requires `--namespace` to specify where the workflow run will be created. + +**Usage:** + +```bash +occ clusterworkflow run CLUSTER_WORKFLOW_NAME [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace where the workflow run will be created (required) +- `--set` - Workflow parameters (can be used multiple times) + +**Examples:** + +```bash +# Run a cluster workflow +occ clusterworkflow run dockerfile-builder --namespace acme-corp + +# Run with parameters +occ clusterworkflow run dockerfile-builder --namespace acme-corp \ + --set spec.workflow.parameters.repository.url=https://github.com/example/repo +``` + +#### clusterworkflow logs + +Get logs for a cluster workflow. + +**Usage:** + +```bash +occ clusterworkflow logs CLUSTER_WORKFLOW_NAME [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace where the workflow run exists (required) +- `-f, --follow` - Follow the logs in real-time +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h) +- `--workflowrun` - Workflow run name (defaults to latest run) + +**Examples:** + +```bash +# Get logs for a cluster workflow +occ clusterworkflow logs dockerfile-builder --namespace acme-corp + +# Follow logs in real-time +occ clusterworkflow logs dockerfile-builder --namespace acme-corp -f + +# Get logs for a specific workflow run +occ clusterworkflow logs dockerfile-builder --namespace acme-corp --workflowrun build-run-1 +``` + +--- + +### clusterworkflowplane + +Manage cluster-scoped workflow planes in OpenChoreo. + +**Usage:** + +```bash +occ clusterworkflowplane +``` + +**Aliases:** `clusterworkflowplanes`, `cwp` + +#### clusterworkflowplane list + +List all cluster workflow planes. + +**Usage:** + +```bash +occ clusterworkflowplane list +``` + +**Examples:** + +```bash +# List all cluster workflow planes +occ clusterworkflowplane list +``` + +#### clusterworkflowplane get + +Get details of a specific cluster workflow plane. + +**Usage:** + +```bash +occ clusterworkflowplane get [CLUSTER_WORKFLOW_PLANE_NAME] +``` + +**Examples:** + +```bash +# Get a specific cluster workflow plane +occ clusterworkflowplane get default +``` + +#### clusterworkflowplane delete + +Delete a cluster workflow plane. + +**Usage:** + +```bash +occ clusterworkflowplane delete [CLUSTER_WORKFLOW_PLANE_NAME] +``` + +**Examples:** + +```bash +# Delete a cluster workflow plane +occ clusterworkflowplane delete default +``` + +--- + +### component + +Manage components in OpenChoreo. + +**Usage:** + +```bash +occ component [flags] +``` + +**Aliases:** `comp`, `components` + +#### component list + +List all components in a project. + +**Usage:** + +```bash +occ component list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name + +**Examples:** + +```bash +# List all components in a project +occ component list --namespace acme-corp --project online-store +``` + +#### component get + +Get details of a specific component. + +**Usage:** + +```bash +occ component get [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific component +occ component get product-catalog --namespace acme-corp +``` + +#### component delete + +Delete a component. + +**Usage:** + +```bash +occ component delete [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a component +occ component delete product-catalog --namespace acme-corp +``` + +#### component scaffold + +Scaffold a Component YAML from ComponentType and Traits. + +Use `--componenttype`/`--traits`/`--workflow` for namespace-scoped resources, or `--clustercomponenttype`/`--clustertraits`/`--clusterworkflow` for cluster-scoped resources. Each pair is mutually exclusive. + +**Usage:** + +```bash +occ component scaffold COMPONENT_NAME [flags] +``` + +**Flags:** + +- `--componenttype` - Namespace-scoped component type in format `workloadType/componentTypeName` (e.g., `deployment/web-app`) +- `--clustercomponenttype` - Cluster-scoped component type in format `workloadType/componentTypeName` +- `--traits` - Comma-separated list of namespace-scoped Trait names to include +- `--clustertraits` - Comma-separated list of cluster-scoped ClusterTrait names to include +- `--workflow` - Namespace-scoped Workflow name +- `--clusterworkflow` - Cluster-scoped ClusterWorkflow name +- `-n, --namespace` - Namespace name (can be omitted if set in context) +- `-p, --project` - Project name (can be omitted if set in context) +- `-o, --output-file` - Write output to specified file instead of stdout +- `--skip-comments` - Skip section headers and field description comments for minimal output +- `--skip-optional` - Skip optional fields without defaults (show only required fields) + +**Examples:** + +```bash +# Scaffold using a cluster-scoped ClusterComponentType +occ component scaffold my-app --clustercomponenttype deployment/web-app + +# Scaffold using a namespace-scoped ComponentType +occ component scaffold my-app --componenttype deployment/web-app + +# Scaffold with cluster-scoped traits +occ component scaffold my-app --clustercomponenttype deployment/web-app --clustertraits storage,ingress + +# Scaffold with cluster-scoped workflow +occ component scaffold my-app --clustercomponenttype deployment/web-app --clusterworkflow docker-build + +# Output to file +occ component scaffold my-app --clustercomponenttype deployment/web-app -o my-app.yaml + +# Minimal output without comments +occ component scaffold my-app --clustercomponenttype deployment/web-app --skip-comments --skip-optional +``` + +#### component deploy + +Deploy or promote a component to an environment. + +**Usage:** + +```bash +occ component deploy [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `--release` - Specific component release to deploy +- `--to` - Target environment to promote to +- `--set` - Override values (can be used multiple times) +- `-o, --output` - Output format + +**Examples:** + +```bash +# Deploy latest release to root environment +occ component deploy api-service --namespace acme-corp --project online-store + +# Deploy specific release +occ component deploy api-service --release api-service-20260126-143022-1 + +# Promote to next environment +occ component deploy api-service --to staging + +# Deploy with overrides +occ component deploy api-service --set spec.componentTypeEnvironmentConfigs.replicas=3 +``` + +#### component logs + +Retrieve and display logs for a component from a specific environment. + +**Usage:** + +```bash +occ component logs COMPONENT_NAME [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `--env` - Environment where the component is deployed (e.g., dev, staging, production). If not specified, uses the lowest environment from the deployment pipeline +- `-f, --follow` - Follow the logs in real-time (streams new logs as they appear) +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h). Default: 1h +- `--tail` - Number of lines to show from the end of logs (0 means no limit) + +**Examples:** + +```bash +# Get logs for a component (auto-detects lowest environment) +occ component logs my-app --namespace acme-corp --project online-store + +# Get logs from a specific environment +occ component logs my-app --env dev + +# Get logs from the last 30 minutes +occ component logs my-app --env dev --since 30m + +# Follow logs in real-time +occ component logs my-app --env dev -f + +# Follow logs with custom since duration +occ component logs my-app --env dev -f --since 5m + +# Get the last 100 lines of logs +occ component logs my-app --env dev --tail 100 +``` + +#### component workflow + +Manage workflows for a specific component. + +##### component workflow run + +Run a component's workflow. + +**Usage:** + +```bash +occ component workflow run [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `--set` - Build parameters (can be used multiple times) + +**Examples:** + +```bash +# Run a component workflow +occ component workflow run api-service --namespace acme-corp --project online-store + +# Run with parameters +occ component workflow run api-service --set spec.workflow.parameters.source.org=openchoreo +``` + +##### component workflow logs + +Get logs for a component's workflow. + +**Usage:** + +```bash +occ component workflow logs [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-f, --follow` - Follow the logs in real-time +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h) +- `--workflowrun` - Workflow run name (defaults to latest run) + +**Examples:** + +```bash +# Get workflow logs for a component +occ component workflow logs api-service --namespace acme-corp + +# Follow workflow logs +occ component workflow logs api-service -f +``` + +#### component workflowrun + +Manage workflow runs for a specific component. + +##### component workflowrun list + +List workflow runs for a component. + +**Usage:** + +```bash +occ component workflowrun list [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all workflow runs for a component +occ component workflowrun list api-service --namespace acme-corp +``` + +##### component workflowrun logs + +Get logs for a component's workflow run. + +**Usage:** + +```bash +occ component workflowrun logs [COMPONENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-f, --follow` - Follow the logs in real-time +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h) +- `--workflowrun` - Workflow run name (defaults to latest run) + +**Examples:** + +```bash +# Get latest workflow run logs for a component +occ component workflowrun logs api-service --namespace acme-corp + +# Get logs for a specific workflow run +occ component workflowrun logs api-service --workflowrun api-service-build-abc123 + +# Follow workflow run logs +occ component workflowrun logs api-service -f +``` + +#### component exec + +Open an interactive exec session to a component's running pod. + +**Usage:** + +```bash +occ component exec COMPONENT_NAME [-- COMMAND [args...]] [flags] +``` + +If no command is specified after `--`, defaults to `/bin/sh`. If `--env` is not specified, uses the lowest environment from the deployment pipeline. + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `--env` - Environment name (e.g., dev, staging, production) +- `-c, --container` - Container name (defaults to first container) +- `-i, --stdin` - Pass stdin to the container +- `-t, --tty` - Allocate a pseudo-TTY + +**Examples:** + +```bash +# Interactive shell in a component's pod +occ component exec my-service -n acme-corp -p online-store -it + +# Run a specific command +occ component exec my-service -n acme-corp -p online-store -- ls /app + +# Specify environment and container +occ component exec my-service -n acme-corp -p online-store --env dev --container app -- curl localhost:8080/health +``` + +:::info Prerequisites +The `occ component exec` command requires WebSocket support on the control plane gateway. The OpenChoreo control-plane Helm chart enables this by default (an `HTTPListenerPolicy` on the default gateway), so no manual setup is needed. + +The user must also have the `component:exec` permission in their authorization role. +::: + +--- + +### componentrelease + +Manage component releases in OpenChoreo. + +**Usage:** + +```bash +occ componentrelease [flags] +``` + +**Aliases:** `componentreleases`, `cr` + +#### componentrelease generate + +:::note +This subcommand only works in file-system mode. Set your context mode to `file-system` before using this command. +::: + +Generate ComponentRelease resources from Component, Workload, ComponentType, and Trait definitions. + +**Usage:** + +```bash +occ componentrelease generate [flags] +``` + +**Flags:** + +- `--all` - Process all resources +- `-p, --project` - Project name +- `-c, --component` - Component name (requires `--project`) +- `--output-path` - Custom output directory path +- `--dry-run` - Preview changes without writing files + +**Examples:** + +```bash +# Generate releases for all components +occ componentrelease generate --all + +# Generate releases for all components in a specific project +occ componentrelease generate --project demo-project + +# Generate release for a specific component (requires --project) +occ componentrelease generate --project demo-project --component greeter-service + +# Dry run (preview without writing) +occ componentrelease generate --all --dry-run + +# Custom output path +occ componentrelease generate --all --output-path /custom/path +``` + +#### componentrelease list + +List all component releases for a specific component. + +**Usage:** + +```bash +occ componentrelease list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `-c, --component` - Component name + +**Examples:** + +```bash +# List all component releases for a component +occ componentrelease list --namespace acme-corp --project online-store --component product-catalog +``` + +#### componentrelease get + +Get details of a specific component release. + +**Usage:** + +```bash +occ componentrelease get [COMPONENT_RELEASE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific component release +occ componentrelease get product-catalog-20260126-143022-1 --namespace acme-corp +``` + +#### componentrelease delete + +Delete a component release. + +**Usage:** + +```bash +occ componentrelease delete [COMPONENT_RELEASE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a component release +occ componentrelease delete product-catalog-20260126-143022-1 --namespace acme-corp +``` + +--- + +### componenttype + +Manage component types in OpenChoreo. + +**Usage:** + +```bash +occ componenttype [flags] +``` + +**Aliases:** `ct`, `componenttypes` + +#### componenttype list + +List all component types available in a namespace. + +**Usage:** + +```bash +occ componenttype list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all component types in a namespace +occ componenttype list --namespace acme-corp +``` + +#### componenttype get + +Get details of a specific component type. + +**Usage:** + +```bash +occ componenttype get [COMPONENT_TYPE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific component type +occ componenttype get web-app --namespace acme-corp +``` + +#### componenttype delete + +Delete a component type. + +**Usage:** + +```bash +occ componenttype delete [COMPONENT_TYPE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a component type +occ componenttype delete web-app --namespace acme-corp +``` + +--- + +### dataplane + +Manage data planes in OpenChoreo. + +**Usage:** + +```bash +occ dataplane [flags] +``` + +**Aliases:** `dp`, `dataplanes` + +#### dataplane list + +List all data planes in a namespace. + +**Usage:** + +```bash +occ dataplane list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all data planes in a namespace +occ dataplane list --namespace acme-corp +``` + +#### dataplane get + +Get details of a specific data plane. + +**Usage:** + +```bash +occ dataplane get [DATAPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific data plane +occ dataplane get us-west-1 --namespace acme-corp +``` + +#### dataplane delete + +Delete a data plane. + +**Usage:** + +```bash +occ dataplane delete [DATAPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a data plane +occ dataplane delete us-west-1 --namespace acme-corp +``` + +--- + +### deploymentpipeline + +Manage deployment pipelines in OpenChoreo. + +**Usage:** + +```bash +occ deploymentpipeline [flags] +``` + +**Aliases:** `deppipe`, `deploymentpipelines` + +#### deploymentpipeline list + +List all deployment pipelines in a namespace. + +**Usage:** + +```bash +occ deploymentpipeline list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all deployment pipelines in a namespace +occ deploymentpipeline list --namespace acme-corp +``` + +#### deploymentpipeline get + +Get details of a specific deployment pipeline. + +**Usage:** + +```bash +occ deploymentpipeline get [DEPLOYMENT_PIPELINE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific deployment pipeline +occ deploymentpipeline get default-pipeline --namespace acme-corp +``` + +#### deploymentpipeline delete + +Delete a deployment pipeline. + +**Usage:** + +```bash +occ deploymentpipeline delete [DEPLOYMENT_PIPELINE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a deployment pipeline +occ deploymentpipeline delete default-pipeline --namespace acme-corp +``` + +--- + +### environment + +Manage environments in OpenChoreo. + +**Usage:** + +```bash +occ environment [flags] +``` + +**Aliases:** `env`, `environments`, `envs` + +#### environment list + +List all environments in a namespace. + +**Usage:** + +```bash +occ environment list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all environments in a namespace +occ environment list --namespace acme-corp +``` + +#### environment get + +Get details of a specific environment. + +**Usage:** + +```bash +occ environment get [ENVIRONMENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific environment +occ environment get dev --namespace acme-corp +``` + +#### environment delete + +Delete an environment. + +**Usage:** + +```bash +occ environment delete [ENVIRONMENT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete an environment +occ environment delete dev --namespace acme-corp +``` + +--- + +### namespace + +Manage namespaces in OpenChoreo. + +**Usage:** + +```bash +occ namespace [flags] +``` + +**Aliases:** `ns`, `namespaces` + +#### namespace list + +List all namespaces. + +**Usage:** + +```bash +occ namespace list +``` + +**Examples:** + +```bash +# List all namespaces +occ namespace list +``` + +#### namespace get + +Get details of a specific namespace. + +**Usage:** + +```bash +occ namespace get [NAMESPACE_NAME] +``` + +**Examples:** + +```bash +# Get a specific namespace +occ namespace get acme-corp +``` + +#### namespace delete + +Delete a namespace. + +**Usage:** + +```bash +occ namespace delete [NAMESPACE_NAME] +``` + +**Examples:** + +```bash +# Delete a namespace +occ namespace delete acme-corp +``` + +--- + +### observabilityalertsnotificationchannel + +Manage observability alerts notification channels in OpenChoreo. + +**Usage:** + +```bash +occ observabilityalertsnotificationchannel [flags] +``` + +**Aliases:** `oanc`, `obsnotificationchannel`, `observabilityalertsnotificationchannels` + +#### observabilityalertsnotificationchannel list + +List all observability alerts notification channels in a namespace. + +**Usage:** + +```bash +occ observabilityalertsnotificationchannel list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all notification channels in a namespace +occ observabilityalertsnotificationchannel list --namespace acme-corp +``` + +#### observabilityalertsnotificationchannel get + +Get details of a specific notification channel. + +**Usage:** + +```bash +occ observabilityalertsnotificationchannel get [CHANNEL_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific notification channel +occ observabilityalertsnotificationchannel get slack-alerts --namespace acme-corp +``` + +#### observabilityalertsnotificationchannel delete + +Delete a notification channel. + +**Usage:** + +```bash +occ observabilityalertsnotificationchannel delete [CHANNEL_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a notification channel +occ observabilityalertsnotificationchannel delete slack-alerts --namespace acme-corp +``` + +--- + +### observabilityplane + +Manage observability planes in OpenChoreo. + +**Usage:** + +```bash +occ observabilityplane [flags] +``` + +**Aliases:** `op`, `observabilityplanes` + +#### observabilityplane list + +List all observability planes in a namespace. + +**Usage:** + +```bash +occ observabilityplane list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all observability planes in a namespace +occ observabilityplane list --namespace acme-corp +``` + +#### observabilityplane get + +Get details of a specific observability plane. + +**Usage:** + +```bash +occ observabilityplane get [OBSERVABILITYPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific observability plane +occ observabilityplane get default --namespace acme-corp +``` + +#### observabilityplane delete + +Delete an observability plane. + +**Usage:** + +```bash +occ observabilityplane delete [OBSERVABILITYPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete an observability plane +occ observabilityplane delete default --namespace acme-corp +``` + +--- + +### project + +Manage projects in OpenChoreo. + +**Usage:** + +```bash +occ project [flags] +``` + +**Aliases:** `proj`, `projects` + +#### project list + +List all projects in a namespace. + +**Usage:** + +```bash +occ project list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all projects in a namespace +occ project list --namespace acme-corp +``` + +#### project get + +Get details of a specific project. + +**Usage:** + +```bash +occ project get [PROJECT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific project +occ project get online-store --namespace acme-corp +``` + +#### project delete + +Delete a project. + +**Usage:** + +```bash +occ project delete [PROJECT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a project +occ project delete online-store --namespace acme-corp +``` + +--- + +### releasebinding + +Manage release bindings in OpenChoreo. + +**Usage:** + +```bash +occ releasebinding [flags] +``` + +**Aliases:** `releasebindings`, `rb` + +#### releasebinding generate + +:::note +This subcommand only works in file-system mode. Set your context mode to `file-system` before using this command. +::: + +Generate ReleaseBinding resources that bind component releases to environments. + +**Usage:** + +```bash +occ releasebinding generate [flags] +``` + +**Flags:** + +- `-e, --target-env` - Target environment for the release binding (required) +- `--use-pipeline` - Deployment pipeline name for environment validation (required) +- `--all` - Process all resources +- `-p, --project` - Project name +- `-c, --component` - Component name (requires `--project`) +- `--component-release` - Explicit component release name (only valid with `--project` and `--component`) +- `--output-path` - Custom output directory path +- `--dry-run` - Preview changes without writing files + +**Examples:** + +```bash +# Generate bindings for all components in development environment +occ releasebinding generate --target-env development --use-pipeline default-pipeline --all + +# Generate bindings for all components in a specific project +occ releasebinding generate --target-env staging --use-pipeline default-pipeline \ + --project demo-project + +# Generate binding for a specific component +occ releasebinding generate --target-env production --use-pipeline default-pipeline \ + --project demo-project --component greeter-service + +# Generate binding with explicit component release +occ releasebinding generate --target-env production --use-pipeline default-pipeline \ + --project demo-project --component greeter-service \ + --component-release greeter-service-20251222-3 + +# Dry run (preview without writing) +occ releasebinding generate --target-env development --use-pipeline default-pipeline \ + --all --dry-run + +# Custom output path +occ releasebinding generate --target-env development --use-pipeline default-pipeline \ + --all --output-path /custom/path +``` + +#### releasebinding list + +List all release bindings for a specific component. + +**Usage:** + +```bash +occ releasebinding list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `-c, --component` - Component name + +**Examples:** + +```bash +# List all release bindings for a component +occ releasebinding list --namespace acme-corp --project online-store --component product-catalog +``` + +#### releasebinding get + +Get details of a specific release binding. + +**Usage:** + +```bash +occ releasebinding get [RELEASE_BINDING_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific release binding +occ releasebinding get product-catalog-dev-binding --namespace acme-corp +``` + +#### releasebinding delete + +Delete a release binding. + +**Usage:** + +```bash +occ releasebinding delete [RELEASE_BINDING_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a release binding +occ releasebinding delete product-catalog-dev-binding --namespace acme-corp +``` + +--- + +### secret + +Manage secrets that are pushed to a target plane's external secret store. + +**Usage:** + +```bash +occ secret [flags] +``` + +**Aliases:** `secrets` + +The read paths (`list`, `get`) surface only secrets that target a plane. The write paths (`create`, `update`, `delete`) call the secret API which provisions, mutates, or removes the secret on the target plane's external secret store. + +#### secret list + +List secrets in a namespace. + +**Usage:** + +```bash +occ secret list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all secrets in a namespace +occ secret list --namespace acme-corp +``` + +#### secret get + +Get a secret and display its details in YAML format. + +**Usage:** + +```bash +occ secret get [SECRET_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a secret +occ secret get my-secret --namespace acme-corp +``` + +#### secret create + +Create a secret of the specified type on a target plane. The create command groups three subcommands that share common flags: + +- `-n, --namespace` - Namespace name +- `--target-plane` - Target plane in `Kind/Name` form (e.g. `DataPlane/dp-prod`) +- `--category` - Secret category: `generic` (default) or `git-credentials` +- `--from-literal` - `key=value` literal (repeatable) +- `--from-file` - `key=path` or `path` (repeatable). Key defaults to the filename. +- `--from-env-file` - Path to a `KEY=VALUE` env file (repeatable) + +##### secret create generic + +Create an Opaque secret from literals, files, or env files. Use `--type` to create a typed Kubernetes secret (e.g. `kubernetes.io/basic-auth`, `kubernetes.io/ssh-auth`) while still sourcing data the same way. + +**Usage:** + +```bash +occ secret create generic [SECRET_NAME] [flags] +``` + +**Flags:** + +- Common create flags listed above +- `--type` - Kubernetes secret type override (e.g. `kubernetes.io/basic-auth`) + +**Examples:** + +```bash +# Create an Opaque secret from literal values +occ secret create generic db-creds \ + --namespace acme-corp \ + --target-plane DataPlane/dp-prod \ + --from-literal=username=admin \ + --from-literal=password=s3cret + +# Create a basic-auth secret +occ secret create generic basic --type=kubernetes.io/basic-auth \ + --namespace acme-corp --target-plane DataPlane/dp-prod \ + --from-literal=username=admin --from-literal=password=s3cret + +# Create a git-credentials category secret +occ secret create generic github-pat \ + --namespace acme-corp --target-plane DataPlane/dp-prod \ + --category git-credentials \ + --from-literal=username=git --from-literal=password=ghp_xxx +``` + +##### secret create docker-registry + +Create a `kubernetes.io/dockerconfigjson` secret from registry credentials. + +**Usage:** + +```bash +occ secret create docker-registry [SECRET_NAME] [flags] +``` + +**Flags:** + +- Common create flags listed above +- `--docker-server` - Docker registry server URL +- `--docker-username` - Docker registry username +- `--docker-password` - Docker registry password +- `--docker-email` - Docker registry email (optional) + +**Examples:** + +```bash +# Create a Docker registry secret +occ secret create docker-registry regcred \ + --namespace acme-corp --target-plane DataPlane/dp-prod \ + --docker-server=https://index.docker.io/v1/ \ + --docker-username=jdoe --docker-password=hunter2 \ + --docker-email=jdoe@example.com +``` + +##### secret create tls + +Create a `kubernetes.io/tls` secret from a certificate and key pair. + +**Usage:** + +```bash +occ secret create tls [SECRET_NAME] [flags] +``` + +**Flags:** + +- Common create flags listed above +- `--cert` - Path to PEM-encoded certificate file +- `--key` - Path to PEM-encoded private key file + +**Examples:** + +```bash +# Create a TLS secret +occ secret create tls my-tls \ + --namespace acme-corp --target-plane DataPlane/dp-prod \ + --cert=./tls.crt --key=./tls.key +``` + +#### secret update + +Update the data of an existing secret. + +By default the update merges: keys passed via `--from-literal`, `--from-file`, or `--from-env-file` are set or added, and every other existing key is left unchanged. Use `--replace` to set the data to exactly what the `--from-*` flags specify, pruning any keys not listed. + +The secret type, target plane, and category cannot be changed. To change them, delete the secret with `occ secret delete` and recreate it with `occ secret create`. + +**Usage:** + +```bash +occ secret update [SECRET_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `--from-literal` - `key=value` literal to set (repeatable) +- `--from-file` - `key=path` or `path` to set (repeatable). Key defaults to the filename. +- `--from-env-file` - Path to a `KEY=VALUE` env file (repeatable) +- `--replace` - Replace the secret data with exactly the `--from-*` keys, pruning all others + +**Examples:** + +```bash +# Rotate one key, keep the rest +occ secret update db-creds --namespace acme-corp \ + --from-literal=password=n3ws3cret + +# Add a key from a file +occ secret update db-creds --namespace acme-corp \ + --from-file=ca.crt=./ca.crt + +# Replace the data with exactly these keys +occ secret update db-creds --namespace acme-corp --replace \ + --from-literal=username=admin --from-literal=password=n3ws3cret +``` + +#### secret delete + +Delete a secret from the external secret store. + +**Usage:** + +```bash +occ secret delete [SECRET_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a secret +occ secret delete my-secret --namespace acme-corp +``` + +--- + +### secretreference + +Manage secret references in OpenChoreo. + +**Usage:** + +```bash +occ secretreference [flags] +``` + +**Aliases:** `sr`, `secretreferences`, `secretref` + +#### secretreference list + +List all secret references in a namespace. + +**Usage:** + +```bash +occ secretreference list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all secret references in a namespace +occ secretreference list --namespace acme-corp +``` + +#### secretreference get + +Get details of a specific secret reference. + +**Usage:** + +```bash +occ secretreference get [SECRET_REFERENCE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific secret reference +occ secretreference get db-credentials --namespace acme-corp +``` + +#### secretreference delete + +Delete a secret reference. + +**Usage:** + +```bash +occ secretreference delete [SECRET_REFERENCE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a secret reference +occ secretreference delete db-credentials --namespace acme-corp +``` + +--- + +### trait + +Manage traits in OpenChoreo. + +**Usage:** + +```bash +occ trait [flags] +``` + +**Aliases:** `traits` + +#### trait list + +List all traits available in a namespace. + +**Usage:** + +```bash +occ trait list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all traits in a namespace +occ trait list --namespace acme-corp +``` + +#### trait get + +Get details of a specific trait. + +**Usage:** + +```bash +occ trait get [TRAIT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific trait +occ trait get ingress --namespace acme-corp +``` + +#### trait delete + +Delete a trait. + +**Usage:** + +```bash +occ trait delete [TRAIT_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a trait +occ trait delete ingress --namespace acme-corp +``` + +--- + +### workflow + +Manage workflows in OpenChoreo. + +**Usage:** + +```bash +occ workflow [flags] +``` + +**Aliases:** `wf`, `workflows` + +#### workflow list + +List all workflows available in a namespace. + +**Usage:** + +```bash +occ workflow list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all workflows in a namespace +occ workflow list --namespace acme-corp +``` + +#### workflow get + +Get details of a specific workflow. + +**Usage:** + +```bash +occ workflow get [WORKFLOW_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific workflow +occ workflow get database-migration --namespace acme-corp +``` + +#### workflow run + +Run a workflow with optional parameters. + +**Usage:** + +```bash +occ workflow run WORKFLOW_NAME [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `--set` - Workflow parameters (can be used multiple times) + +**Examples:** + +```bash +# Run a workflow +occ workflow run database-migration --namespace acme-corp + +# Run with parameters +occ workflow run github-stats-report --namespace acme-corp --set spec.workflow.parameters.source.org=openchoreo --set spec.workflow.parameters.output.format=json +``` + +#### workflow logs + +Get logs for a workflow. + +**Usage:** + +```bash +occ workflow logs WORKFLOW_NAME [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-f, --follow` - Follow the logs in real-time +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h) +- `--workflowrun` - Workflow run name (defaults to latest run) + +**Examples:** + +```bash +# Get logs for a workflow +occ workflow logs database-migration --namespace acme-corp + +# Follow logs in real-time +occ workflow logs database-migration --namespace acme-corp -f + +# Get logs for a specific workflow run +occ workflow logs database-migration --workflowrun migration-run-1 +``` + +#### workflow delete + +Delete a workflow. + +**Usage:** + +```bash +occ workflow delete [WORKFLOW_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a workflow +occ workflow delete database-migration --namespace acme-corp +``` + +--- + +### workflowplane + +Manage workflow planes in OpenChoreo. + +**Usage:** + +```bash +occ workflowplane [flags] +``` + +**Aliases:** `wp`, `workflowplanes` + +#### workflowplane list + +List all workflow planes in a namespace. + +**Usage:** + +```bash +occ workflowplane list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all workflow planes in a namespace +occ workflowplane list --namespace acme-corp +``` + +#### workflowplane get + +Get details of a specific workflow plane. + +**Usage:** + +```bash +occ workflowplane get [WORKFLOWPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific workflow plane +occ workflowplane get default --namespace acme-corp +``` + +#### workflowplane delete + +Delete a workflow plane. + +**Usage:** + +```bash +occ workflowplane delete [WORKFLOWPLANE_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a workflow plane +occ workflowplane delete default --namespace acme-corp +``` + +--- + +### workflowrun + +Manage workflow runs in OpenChoreo. + +**Usage:** + +```bash +occ workflowrun [flags] +``` + +**Aliases:** `wr`, `workflowruns` + +#### workflowrun list + +List all workflow runs in a namespace. + +**Usage:** + +```bash +occ workflowrun list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# List all workflow runs in a namespace +occ workflowrun list --namespace acme-corp +``` + +#### workflowrun get + +Get details of a specific workflow run. + +**Usage:** + +```bash +occ workflowrun get [WORKFLOW_RUN_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific workflow run +occ workflowrun get migration-run-1 --namespace acme-corp +``` + +#### workflowrun logs + +Get logs for a workflow run. + +**Usage:** + +```bash +occ workflowrun logs [WORKFLOW_RUN_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name +- `-f, --follow` - Follow the logs in real-time +- `--since` - Only return logs newer than a relative duration (e.g., 5m, 1h, 24h) + +**Examples:** + +```bash +# Get logs for a workflow run +occ workflowrun logs migration-run-1 --namespace acme-corp + +# Follow logs in real-time +occ workflowrun logs migration-run-1 --namespace acme-corp -f +``` + +--- + +### workload + +Manage workloads in OpenChoreo. + +**Usage:** + +```bash +occ workload [flags] +``` + +**Aliases:** `wl`, `workloads` + +#### workload create + +Create a workload from a descriptor file. + +**Usage:** + +```bash +occ workload create [flags] +``` + +**Flags:** + +- `--name` - Name of the workload +- `-n, --namespace` - Namespace name +- `-p, --project` - Project name +- `-c, --component` - Component name +- `--image` - Docker image name (e.g., `product-catalog:latest`) +- `--descriptor` - Path to the workload descriptor file +- `-o, --output` - Output format (`yaml`) +- `--dry-run` - Preview changes without writing files +- `--mode` - Operational mode: `api-server` (default) or `file-system` +- `--root-dir` - Root directory path for file-system mode (defaults to current directory) + +**Examples:** + +```bash +# Create a workload from a descriptor +occ workload create --name my-workload --namespace acme-corp --project online-store \ + --component product-catalog --descriptor workload.yaml + +# Create a workload from an image +occ workload create --name my-workload --namespace acme-corp --project online-store \ + --component product-catalog --image product-catalog:latest + +# Dry run to preview +occ workload create --name my-workload --namespace acme-corp --project online-store \ + --component product-catalog --descriptor workload.yaml --dry-run +``` + +#### workload list + +List all workloads in a namespace. + +**Usage:** + +```bash +occ workload list [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +:::note +The `workload list` command does not currently support `--project` or `--component` filtering flags. It returns all workloads in the namespace. +::: + +**Examples:** + +```bash +# List all workloads in a namespace +occ workload list --namespace acme-corp +``` + +#### workload get + +Get details of a specific workload. + +**Usage:** + +```bash +occ workload get [WORKLOAD_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Get a specific workload +occ workload get my-workload --namespace acme-corp +``` + +#### workload delete + +Delete a workload. + +**Usage:** + +```bash +occ workload delete [WORKLOAD_NAME] [flags] +``` + +**Flags:** + +- `-n, --namespace` - Namespace name + +**Examples:** + +```bash +# Delete a workload +occ workload delete my-workload --namespace acme-corp +``` diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/faq.md b/versioned_docs/version-v1.2.0-rc.2/reference/faq.md new file mode 100644 index 00000000..e26a6d9c --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/faq.md @@ -0,0 +1,146 @@ +--- +title: Frequently Asked Questions (FAQ) +description: Answers to common questions about OpenChoreo concepts, architecture, and usage +--- + +# Frequently Asked Questions (FAQ) + +## General Questions + +### What is OpenChoreo? + +OpenChoreo is an open-source Internal Developer Platform (IDP) that simplifies cloud-native application development by providing developer-friendly abstractions over complex Kubernetes and cloud-native technologies. + +### How is OpenChoreo different from other platforms? + +OpenChoreo focuses on: + +- **Developer Experience**: Simple abstractions without losing Kubernetes power +- **Security by Default**: Built-in security with cell-based architecture +- **CNCF Integration**: Orchestrates best-in-class cloud-native tools +- **Open Source**: Community-driven development with no vendor lock-in + +### What are the main benefits of using OpenChoreo? + +- **Faster Time to Market**: Deploy applications in minutes instead of days +- **Reduced Complexity**: Focus on business logic instead of infrastructure +- **Production Ready**: Enterprise-grade capabilities from day one +- **Consistent Environments**: Identical configurations across all stages + +--- + +## Getting Started + +### What are the prerequisites for OpenChoreo? + +- **Kubernetes Cluster**: Version 1.32 or later +- **kubectl**: v1.32+ configured to access your cluster +- **Helm**: Version 3.x (for installation) +- **Container Registry**: For storing application images (required for CI workflows) + +### How do I install OpenChoreo? + +Choose your path: + +- **Quick Try**: [Run Locally](../getting-started/try-it-out/on-k3d-locally.mdx) or [On Your Environment](../getting-started/try-it-out/on-your-environment.mdx) +- **Production**: See the [Platform Engineer Guide](../platform-engineer-guide/deployment-topology.mdx) for production configuration + +### Can I try OpenChoreo locally? + +Yes! The [local setup guide](../getting-started/try-it-out/on-k3d-locally.mdx) lets you try OpenChoreo on your laptop with k3d. + +### What's the simplest way to deploy my first application? + +Follow [Deploy and Explore](../getting-started/deploy-and-explore.mdx) + +--- + +## Architecture & Concepts + +### What is a "Cell" in OpenChoreo? + +A Cell is OpenChoreo's security boundary that: + +- Isolates applications using Kubernetes namespaces +- Enforces network policies with Cilium +- Provides encrypted communication with mTLS +- Implements identity-based access controls +- Usually this is a Project in OpenChoreo + +### How does OpenChoreo handle multi-environment deployments? + +OpenChoreo uses Environment abstractions that: + +- Define deployment targets (dev, staging, prod) +- Apply environment-specific configurations +- Enforce resource quotas and policies +- Enable promotion workflows between environments + +### What's the difference between a Project and a Component? + +- **Project**: A logical grouping of related components (e.g., an e-commerce platform) +- **Component**: An individual deployable unit (e.g., user-service, payment-api) + +### How does OpenChoreo integrate with existing CI/CD pipelines? + +OpenChoreo supports two approaches: + +- **Built-in CI**: Argo Workflows-based pipelines with Dockerfile and buildpack builders, configured by platform engineers and triggered by developers or Git webhooks (auto-build) +- **External CI**: Use Jenkins, GitHub Actions, or other CI platforms to build images and call the OpenChoreo [Workload API](../platform-engineer-guide/workflows/external-ci.mdx) to create deployments +- **`occ` CLI**: The OpenChoreo CLI can trigger builds, monitor workflow runs, and manage deployments from any CI system + +--- + +## Performance & Deployment + +### What are the resource requirements for OpenChoreo? + +**Control Plane (minimum)**: + +- **CPU**: 2 cores +- **Memory**: 4 GB RAM (8 GB recommended with observability plane) +- **Storage**: 20 GB + +### Can OpenChoreo work with multiple clusters? + +Yes, you can setup the following patterns + +- **All in one cluster**: Where all the planes are in a single cluster +- **Combined clusters**: Where a combination of planes are together spread across multiple clusters + e.g. control plane separate and others together, observability plane separate and others together +- **Totally separated clusters**: Where each plane has its own cluster. Note that this is not usually for a local setup. + +--- + +## Licensing & Support + +### What license does OpenChoreo use? + +OpenChoreo is licensed under the **Apache 2.0 License**, ensuring: + +- **Free commercial use** +- **No vendor lock-in** +- **Community contributions welcome** +- **Enterprise-friendly terms** + +### Where can I get help? + +- **Documentation**: Comprehensive guides at [openchoreo.dev](../overview/what-is-openchoreo.mdx) +- **Community Forum**: GitHub Discussions for questions +- **Chat**: Real-time help on [CNCF Slack (#openchoreo)](https://cloud-native.slack.com/archives/C0ABYRG1MND) +- **Issues**: Bug reports on [GitHub Issues](https://github.com/openchoreo/openchoreo/issues) + +### How can I contribute to OpenChoreo? + +- **Code Contributions**: Submit pull requests on GitHub +- **Documentation**: Improve guides and tutorials +- **Community Support**: Help answer questions +- **Bug Reports**: File issues with detailed information + +--- + +**Can't find your question?** + +- Search our [documentation](../overview/what-is-openchoreo.mdx) +- Ask in [GitHub Discussions](https://github.com/openchoreo/openchoreo/discussions) +- Join [CNCF Slack (#openchoreo)](https://cloud-native.slack.com/archives/C0ABYRG1MND) diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/helm/_category_.json b/versioned_docs/version-v1.2.0-rc.2/reference/helm/_category_.json new file mode 100644 index 00000000..b1048be0 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/helm/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Helm Charts", + "position": 2, + "collapsed": false +} diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/helm/control-plane.mdx b/versioned_docs/version-v1.2.0-rc.2/reference/helm/control-plane.mdx new file mode 100644 index 00000000..998ffaa8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/helm/control-plane.mdx @@ -0,0 +1,390 @@ +--- +title: Control Plane +description: Helm chart values reference for openchoreo-control-plane. +sidebar_position: 1 +--- + +## Backstage + +Backstage UI configuration + +| Parameter | Description | Type | Default | +| :-------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :--------------------------------- | +| `backstage.affinity` | Affinity rules | `object` | `{}` | +| `backstage.auth.clientId` | OAuth client ID | `string` | `openchoreo-backstage-client` | +| `backstage.auth.redirectUrls` | OAuth redirect URLs | `array` | `[]` | +| `backstage.autoscaling.behavior.scaleDown.policies` | Scale-down policies | `array` | | +| `backstage.autoscaling.behavior.scaleDown.stabilizationWindowSeconds` | Stabilization window in seconds | `integer` | `300` | +| `backstage.autoscaling.behavior.scaleUp.policies` | Scale-up policies | `array` | | +| `backstage.autoscaling.behavior.scaleUp.selectPolicy` | Policy selection strategy | `string` | `Max` | +| `backstage.autoscaling.behavior.scaleUp.stabilizationWindowSeconds` | Stabilization window in seconds | `integer` | `0` | +| `backstage.autoscaling.enabled` | Enable HPA | `boolean` | `false` | +| `backstage.autoscaling.maxReplicas` | Maximum replicas | `integer` | `3` | +| `backstage.autoscaling.minReplicas` | Minimum replicas | `integer` | `1` | +| `backstage.autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage | `integer` | `70` | +| `backstage.autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization percentage | `integer` | `80` | +| `backstage.baseUrl` | Backstage public base URL | `string` | `http://openchoreo.invalid` | +| `backstage.containerSecurityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `backstage.containerSecurityContext.appArmorProfile.type` | AppArmor profile type | `string` | `Unconfined` | +| `backstage.containerSecurityContext.capabilities.drop` | Capabilities to drop | `array` | | +| `backstage.containerSecurityContext.readOnlyRootFilesystem` | Read-only root filesystem | `boolean` | `false` | +| `backstage.containerSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `backstage.database.postgresql.ssl` | Enable SSL for the PostgreSQL connection (sets PGSSLMODE=require) | `boolean` | `false` | +| `backstage.database.sqlite.mountPath` | Mount path for database directory inside container | `string` | `/app/.config/backstage` | +| `backstage.database.sqlite.persistence.accessMode` | PVC access mode | `string` | `ReadWriteOnce` | +| `backstage.database.sqlite.persistence.enabled` | Enable PVC for persistence (false = emptyDir) | `boolean` | `false` | +| `backstage.database.sqlite.persistence.size` | PVC storage size | `string` | `1Gi` | +| `backstage.database.sqlite.persistence.storageClassName` | Storage class name (empty = default storage class) | `string` | | +| `backstage.database.type` | Database type | `string` | `sqlite` | +| `backstage.enabled` | Enable Backstage UI deployment | `boolean` | `true` | +| `backstage.env` | Environment variables for the Backstage container | `array` | | +| `backstage.externalCI.jenkins.baseUrl` | Jenkins server base URL (e.g., https://jenkins.example.com) | `string` | | +| `backstage.externalCI.jenkins.enabled` | Enable Jenkins integration by injecting environment variables | `boolean` | `false` | +| `backstage.externalCI.jenkins.username` | Jenkins username for API authentication | `string` | | +| `backstage.extraEnv` | Additional environment variables to merge with the default env array. Use this instead of overriding backstage.env to avoid sparse array issues with --set. | `array` | | +| `backstage.features.auth.redirectFlow.enabled` | Enable experimental redirect flow - silently redirects to IDP instead of showing sign-in popup | `boolean` | `true` | +| `backstage.features.observability.enabled` | Enable Metrics, Traces, Runtime Logs tabs and RuntimeHealthCard in entity pages | `boolean` | `true` | +| `backstage.features.workflows.enabled` | Enable Workflows tab and WorkflowsOverviewCard in entity pages | `boolean` | `true` | +| `backstage.http.annotations` | HTTPRoute annotations | `object` | `{}` | +| `backstage.http.enabled` | Enable HTTPRoute | `boolean` | `true` | +| `backstage.http.hostnames` | HTTPRoute hostnames | `array` | `["openchoreo.invalid"]` | +| `backstage.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `backstage.image.repository` | Docker image repository | `string` | `ghcr.io/openchoreo/openchoreo-ui` | +| `backstage.image.tag` | Image tag. If empty, uses Chart.AppVersion | `string` | | +| `backstage.metrics.enabled` | Enable Prometheus metrics | `boolean` | `true` | +| `backstage.metrics.serviceMonitor.enabled` | Create ServiceMonitor resource | `boolean` | `false` | +| `backstage.metrics.serviceMonitor.interval` | Scrape interval | `string` | `30s` | +| `backstage.metrics.serviceMonitor.labels.prometheus` | | `string` | `kube-prometheus` | +| `backstage.metrics.serviceMonitor.namespace` | Namespace for ServiceMonitor | `string` | `monitoring` | +| `backstage.metrics.serviceMonitor.relabelings` | Metric relabeling rules | `array` | `[]` | +| `backstage.metrics.serviceMonitor.scrapeTimeout` | Scrape timeout | `string` | `10s` | +| `backstage.name` | Static name for all backstage resources (Service, Deployment, etc.) | `string` | `backstage` | +| `backstage.networkPolicy.egress` | Egress rules | `array` | `[]` | +| `backstage.networkPolicy.enabled` | Enable NetworkPolicy | `boolean` | `false` | +| `backstage.networkPolicy.ingress` | Ingress rules | `array` | `[]` | +| `backstage.nodeSelector` | Node selector | `object` | `{}` | +| `backstage.openchoreoApi.url` | OpenChoreo API URL. If empty, auto-derived from internal service | `string` | | +| `backstage.podDisruptionBudget.enabled` | Enable PDB | `boolean` | `false` | +| `backstage.podDisruptionBudget.minAvailable` | Minimum available pods | `integer` | `1` | +| `backstage.podSecurityContext.fsGroup` | Filesystem group | `integer` | `1000` | +| `backstage.podSecurityContext.runAsGroup` | Group ID | `integer` | `1000` | +| `backstage.podSecurityContext.runAsNonRoot` | Run as non-root user | `boolean` | `true` | +| `backstage.podSecurityContext.runAsUser` | User ID | `integer` | `1000` | +| `backstage.podSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `backstage.priorityClass.create` | Create a priority class | `boolean` | `false` | +| `backstage.priorityClass.name` | Priority class name | `string` | `openchoreo-backstage` | +| `backstage.priorityClass.value` | Priority class value | `integer` | `800000` | +| `backstage.replicas` | Number of Backstage replicas | `integer` | `1` | +| `backstage.resources.limits.cpu` | CPU limit | `string` | `2000m` | +| `backstage.resources.limits.memory` | Memory limit | `string` | `2Gi` | +| `backstage.resources.requests.cpu` | CPU request | `string` | `200m` | +| `backstage.resources.requests.memory` | Memory request | `string` | `256Mi` | +| `backstage.secretName` | Name of a Secret containing backstage credentials. Required keys: backend-secret, client-secret, jenkins-api-key. When database.type=postgresql, also requires: postgres-host, postgres-port, postgres-user, postgres-password, postgres-db. | `string` | | +| `backstage.service.nodePort` | NodePort (only used if service.type is NodePort) | `integer,null` | `null` | +| `backstage.service.port` | Service port | `integer` | `7007` | +| `backstage.service.type` | Service type | `string` | `ClusterIP` | +| `backstage.serviceAccount.annotations` | Service account annotations | `object` | `{}` | +| `backstage.serviceAccount.name` | Service account name | `string` | `openchoreo-backstage` | +| `backstage.tls.enabled` | Enable TLS/HTTPS for Backstage | `boolean` | `false` | +| `backstage.tolerations` | Tolerations | `array` | `[]` | +| `backstage.topologySpreadConstraints` | Topology spread constraints | `array` | | + +## Cluster Gateway + +Cluster Gateway configuration - manages WebSocket connections from cluster agents + +| Parameter | Description | Type | Default | +| :-------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :----------------------------------- | +| `clusterGateway.affinity` | Affinity rules | `object` | `{}` | +| `clusterGateway.heartbeatInterval` | Heartbeat interval for agent connections | `string` | `30s` | +| `clusterGateway.heartbeatTimeout` | Heartbeat timeout for agent connections | `string` | `90s` | +| `clusterGateway.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `clusterGateway.image.repository` | Docker image repository | `string` | `ghcr.io/openchoreo/cluster-gateway` | +| `clusterGateway.image.tag` | Image tag. If empty, uses Chart.AppVersion | `string` | | +| `clusterGateway.internalMtls.caSecretName` | Name of the secret holding the internal CA used to sign and verify internal API client certificates | `string` | `cluster-gateway-internal-ca` | +| `clusterGateway.internalMtls.clientCertDuration` | Internal API client certificate validity duration (90 days) | `string` | `2160h` | +| `clusterGateway.internalMtls.clientCertRenewBefore` | Internal API client certificate renewal threshold (15 days before expiry) | `string` | `360h` | +| `clusterGateway.internalMtls.enabled` | Require and verify client certificates on the cluster gateway internal API. Disabling this restores unauthenticated access to the internal API - for development only. | `boolean` | `true` | +| `clusterGateway.logLevel` | Log level | `string` | `info` | +| `clusterGateway.name` | Name of the cluster gateway deployment | `string` | `cluster-gateway` | +| `clusterGateway.nodeSelector` | Node selector | `object` | `{}` | +| `clusterGateway.podSecurityContext.fsGroup` | Filesystem group | `integer` | `1000` | +| `clusterGateway.podSecurityContext.runAsNonRoot` | Run as non-root user | `boolean` | `true` | +| `clusterGateway.podSecurityContext.runAsUser` | User ID | `integer` | `1000` | +| `clusterGateway.port` | WebSocket port for agent connections | `integer` | `8443` | +| `clusterGateway.priorityClass.create` | Create a priority class | `boolean` | `false` | +| `clusterGateway.priorityClass.name` | Priority class name | `string` | `cluster-gateway` | +| `clusterGateway.priorityClass.value` | Priority class value | `integer` | `900000` | +| `clusterGateway.replicas` | Number of cluster gateway replicas. Must be `1` — the gateway holds cluster-agent WebSocket connections in process memory and cannot be horizontally scaled. Support for multiple replicas is planned for a future release. | `integer` | `1` | +| `clusterGateway.resources.limits.cpu` | CPU limit | `string` | `500m` | +| `clusterGateway.resources.limits.memory` | Memory limit | `string` | `256Mi` | +| `clusterGateway.resources.requests.cpu` | CPU request | `string` | `100m` | +| `clusterGateway.resources.requests.memory` | Memory request | `string` | `64Mi` | +| `clusterGateway.securityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `clusterGateway.securityContext.capabilities.drop` | Capabilities to drop | `array` | | +| `clusterGateway.securityContext.readOnlyRootFilesystem` | Read-only root filesystem | `boolean` | `true` | +| `clusterGateway.service.clusterIP` | Cluster IP (set to None for headless service) | `string,null` | `null` | +| `clusterGateway.service.loadBalancerIP` | LoadBalancer IP (only used if service.type is LoadBalancer) | `string,null` | `null` | +| `clusterGateway.service.nodePort` | NodePort (only used if service.type is NodePort) | `integer,null` | `null` | +| `clusterGateway.service.port` | Service port | `integer` | `8443` | +| `clusterGateway.service.type` | Service type | `string` | `ClusterIP` | +| `clusterGateway.serviceAccount.annotations` | Service account annotations | `object` | `{}` | +| `clusterGateway.serviceAccount.create` | Create a service account | `boolean` | `true` | +| `clusterGateway.serviceAccount.name` | Service account name | `string` | `cluster-gateway` | +| `clusterGateway.tls.dnsNames` | DNS names for the certificate | `array` | | +| `clusterGateway.tls.duration` | Certificate validity duration (90 days) | `string` | `2160h` | +| `clusterGateway.tls.enabled` | Enable TLS | `boolean` | `true` | +| `clusterGateway.tls.issuerRef.kind` | Issuer kind | `string` | `Issuer` | +| `clusterGateway.tls.issuerRef.name` | Issuer name | `string` | `cluster-gateway-selfsigned-issuer` | +| `clusterGateway.tls.renewBefore` | Certificate renewal threshold (15 days before expiry) | `string` | `360h` | +| `clusterGateway.tls.secretName` | TLS secret name | `string` | `cluster-gateway-tls` | +| `clusterGateway.tls.skipClientCertVerify` | Deprecated: has no effect. Agent certificates are always verified per plane CR; use clusterGateway.internalMtls.enabled to control internal API verification. Will be removed in a future release. | `boolean` | `false` | +| `clusterGateway.tlsRoute.enabled` | Enable TLSRoute for cluster gateway | `boolean` | `false` | +| `clusterGateway.tlsRoute.hosts` | Hostnames for TLSRoute | `array` | `[]` | +| `clusterGateway.tolerations` | Tolerations | `array` | `[]` | + +## Controller Manager + +Controller Manager configuration - the main controller for OpenChoreo CRDs + +| Parameter | Description | Type | Default | +| :---------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | :------------- | :------------------------------------------------------------------------ | +| `controllerManager.affinity` | Affinity rules for pod scheduling | `object` | `{}` | +| `controllerManager.autoscaling.behavior.scaleDown.policies` | Scale-down policies | `array` | | +| `controllerManager.autoscaling.behavior.scaleDown.stabilizationWindowSeconds` | Stabilization window in seconds before scaling down | `integer` | `300` | +| `controllerManager.autoscaling.behavior.scaleUp.policies` | Scale-up policies | `array` | | +| `controllerManager.autoscaling.behavior.scaleUp.selectPolicy` | Policy selection strategy | `string` | `Max` | +| `controllerManager.autoscaling.behavior.scaleUp.stabilizationWindowSeconds` | Stabilization window in seconds before scaling up | `integer` | `0` | +| `controllerManager.autoscaling.enabled` | Enable Horizontal Pod Autoscaler | `boolean` | `false` | +| `controllerManager.autoscaling.maxReplicas` | Maximum number of replicas | `integer` | `3` | +| `controllerManager.autoscaling.minReplicas` | Minimum number of replicas | `integer` | `1` | +| `controllerManager.autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage for scaling | `integer` | `70` | +| `controllerManager.autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization percentage for scaling | `integer` | `80` | +| `controllerManager.clusterGateway.tls.caPath` | Path to the CA certificate file | `string` | `/etc/cluster-gateway/ca.crt` | +| `controllerManager.clusterGateway.tls.caSecret` | Name of the secret containing the CA certificate | `string` | `cluster-gateway-ca` | +| `controllerManager.clusterGateway.tls.clientCertPath` | Path to the client certificate used for mTLS to the cluster gateway internal API | `string` | `/etc/cluster-gateway-client/tls.crt` | +| `controllerManager.clusterGateway.tls.clientKeyPath` | Path to the client private key used for mTLS to the cluster gateway internal API | `string` | `/etc/cluster-gateway-client/tls.key` | +| `controllerManager.clusterGateway.tls.clientSecret` | Name of the secret containing the controller-manager client certificate for the cluster gateway internal API | `string` | `controller-manager-cluster-gateway-client-tls` | +| `controllerManager.clusterGateway.url` | Cluster gateway service URL | `string` | `https://cluster-gateway.openchoreo-control-plane.svc.cluster.local:8444` | +| `controllerManager.containerSecurityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `controllerManager.containerSecurityContext.appArmorProfile.type` | AppArmor profile type | `string` | `Unconfined` | +| `controllerManager.containerSecurityContext.capabilities.drop` | Capabilities to drop | `array` | | +| `controllerManager.containerSecurityContext.readOnlyRootFilesystem` | Mount root filesystem as read-only | `boolean` | `false` | +| `controllerManager.containerSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `controllerManager.image.pullPolicy` | Image pull policy | `string` | `Always` | +| `controllerManager.image.repository` | Docker image repository | `string` | `ghcr.io/openchoreo/controller` | +| `controllerManager.image.tag` | Image tag. If empty, uses Chart.AppVersion | `string` | | +| `controllerManager.manager.args` | Command-line arguments for the controller-manager | `array` | | +| `controllerManager.manager.env.enableWebhooks` | Enable admission webhooks | `string` | `true` | +| `controllerManager.metrics.enabled` | Enable Prometheus metrics endpoint | `boolean` | `true` | +| `controllerManager.metrics.serviceMonitor.enabled` | Create a ServiceMonitor resource for Prometheus Operator | `boolean` | `false` | +| `controllerManager.metrics.serviceMonitor.interval` | Scrape interval | `string` | `30s` | +| `controllerManager.metrics.serviceMonitor.labels.prometheus` | | `string` | `kube-prometheus` | +| `controllerManager.metrics.serviceMonitor.namespace` | Namespace where ServiceMonitor should be created | `string` | `monitoring` | +| `controllerManager.metrics.serviceMonitor.relabelings` | Metric relabeling rules | `array` | `[]` | +| `controllerManager.metrics.serviceMonitor.scrapeTimeout` | Scrape timeout | `string` | `10s` | +| `controllerManager.name` | Name of the controller-manager deployment | `string` | `controller-manager` | +| `controllerManager.networkPolicy.egress` | Egress rules for the NetworkPolicy | `array` | `[]` | +| `controllerManager.networkPolicy.enabled` | Enable NetworkPolicy | `boolean` | `false` | +| `controllerManager.networkPolicy.ingress` | Ingress rules for the NetworkPolicy | `array` | `[]` | +| `controllerManager.nodeSelector` | Node selector for pod scheduling | `object` | `{}` | +| `controllerManager.podDisruptionBudget.enabled` | Enable PodDisruptionBudget | `boolean` | `false` | +| `controllerManager.podDisruptionBudget.minAvailable` | Minimum number of pods that must be available | `integer` | `1` | +| `controllerManager.podSecurityContext.fsGroup` | Filesystem group for volumes | `integer` | `1000` | +| `controllerManager.podSecurityContext.runAsGroup` | Group ID to run the container as | `integer` | `1000` | +| `controllerManager.podSecurityContext.runAsNonRoot` | Run container as non-root user | `boolean` | `true` | +| `controllerManager.podSecurityContext.runAsUser` | User ID to run the container as | `integer` | `1000` | +| `controllerManager.podSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `controllerManager.priorityClass.create` | Create a priority class for the controller-manager | `boolean` | `false` | +| `controllerManager.priorityClass.name` | Priority class name | `string` | `openchoreo-controller-manager` | +| `controllerManager.priorityClass.value` | Priority class value (higher = more priority) | `integer` | `1000000` | +| `controllerManager.replicas` | Number of controller-manager replicas | `integer` | `1` | +| `controllerManager.resources.limits.cpu` | CPU limit | `string` | `1000m` | +| `controllerManager.resources.limits.memory` | Memory limit | `string` | `1Gi` | +| `controllerManager.resources.requests.cpu` | CPU request | `string` | `200m` | +| `controllerManager.resources.requests.memory` | Memory request | `string` | `256Mi` | +| `controllerManager.service.nodePort` | NodePort (only used if service.type is NodePort) | `integer,null` | `null` | +| `controllerManager.service.port` | Service port | `integer` | `8080` | +| `controllerManager.service.type` | Service type | `string` | `ClusterIP` | +| `controllerManager.serviceAccount.annotations` | Annotations to add to the service account | `object` | `{}` | +| `controllerManager.serviceAccount.create` | Create a service account for the controller-manager | `boolean` | `true` | +| `controllerManager.tolerations` | Tolerations for pod scheduling | `array` | `[]` | +| `controllerManager.topologySpreadConstraints` | Topology spread constraints for pod distribution across zones and nodes | `array` | | + +## Fullname Override + +Override the full name of the chart release + +| Parameter | Description | Type | Default | +| :----------------- | :------------------------------------------ | :------- | :----------- | +| `fullnameOverride` | Override the full name of the chart release | `string` | `openchoreo` | + +## Gateway + +KGateway (Gateway API) configuration. kgateway is installed separately; these values configure the Gateway CR created by this chart. + +| Parameter | Description | Type | Default | +| :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------- | :--------------------- | +| `gateway.annotations` | Annotations added to the Gateway resource. Use this to configure cert-manager, external-dns, or other integrations. | `object` | `{}` | +| `gateway.enabled` | Enable Gateway CR creation | `boolean` | `true` | +| `gateway.httpPort` | HTTP listener port | `integer` | `80` | +| `gateway.httpsPort` | HTTPS listener port | `integer` | `443` | +| `gateway.infrastructure` | Gateway infrastructure configuration passed to the generated Service. Used to configure cloud provider load balancer settings via annotations. Example for AWS with Elastic IP: infrastructure: annotations: service.beta.kubernetes.io/aws-load-balancer-type: "external" service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing" service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "eipalloc-xxx" | `object` | | +| `gateway.tls.certificateRefs` | TLS certificate references for the HTTPS listener. Each entry references a Secret containing the TLS cert/key pair. | `array` | | +| `gateway.tls.enabled` | Enable HTTPS listener on the gateway. When false, only the HTTP listener is created. | `boolean` | `true` | +| `gateway.tls.hostname` | Hostname pattern for the HTTPS listener (SNI matching) | `string` | `*.openchoreo.invalid` | + +## Global + +Global values shared across all components + +| Parameter | Description | Type | Default | +| :-------------------- | :--------------------------------------------------- | :------- | :------ | +| `global.commonLabels` | Labels applied to all resources created by the chart | `object` | `{}` | + +## Kubernetes Cluster Domain + +Kubernetes cluster domain suffix + +| Parameter | Description | Type | Default | +| :------------------------ | :------------------------------- | :------- | :-------------- | +| `kubernetesClusterDomain` | Kubernetes cluster domain suffix | `string` | `cluster.local` | + +## Metrics Service + +Metrics service configuration + +| Parameter | Description | Type | Default | +| :--------------------- | :----------------------------------- | :------- | :---------- | +| `metricsService.ports` | Ports exposed by the metrics service | `array` | | +| `metricsService.type` | Service type | `string` | `ClusterIP` | + +## Openchoreo Api + +OpenChoreo API server configuration + +| Parameter | Description | Type | Default | +| :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :--------------------------------------------------------- | +| `openchoreoApi.affinity` | Affinity rules | `object` | `{}` | +| `openchoreoApi.autoscaling.behavior.scaleDown.policies` | Scale-down policies | `array` | | +| `openchoreoApi.autoscaling.behavior.scaleDown.stabilizationWindowSeconds` | Stabilization window in seconds | `integer` | `300` | +| `openchoreoApi.autoscaling.behavior.scaleUp.policies` | Scale-up policies | `array` | | +| `openchoreoApi.autoscaling.behavior.scaleUp.selectPolicy` | Policy selection strategy | `string` | `Max` | +| `openchoreoApi.autoscaling.behavior.scaleUp.stabilizationWindowSeconds` | Stabilization window in seconds | `integer` | `0` | +| `openchoreoApi.autoscaling.enabled` | Enable Horizontal Pod Autoscaler | `boolean` | `false` | +| `openchoreoApi.autoscaling.maxReplicas` | Maximum number of replicas | `integer` | `3` | +| `openchoreoApi.autoscaling.minReplicas` | Minimum number of replicas | `integer` | `1` | +| `openchoreoApi.autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage | `integer` | `70` | +| `openchoreoApi.autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization percentage | `integer` | `80` | +| `openchoreoApi.config.logging.add_source` | Include source file and line number in log entries | `boolean` | `false` | +| `openchoreoApi.config.logging.format` | Log output format: json, text | `string` | `json` | +| `openchoreoApi.config.logging.level` | Minimum log level: debug, info, warn, error | `string` | `info` | +| `openchoreoApi.config.mcp.enabled` | Enable the MCP server for AI-friendly tool interfaces | `boolean` | `true` | +| `openchoreoApi.config.mcp.toolsets` | List of enabled MCP toolsets. Each toolset exposes a group of related operations. Allowed toolsets: namespace, project, component, deployment, build, pe | `array` | `["namespace","project","component","deployment","build"]` | +| `openchoreoApi.config.security.authentication.jwt.clock_skew` | Allowed clock skew when validating token expiration times | `string` | `0s` | +| `openchoreoApi.config.security.authentication.jwt.jwks.refresh_interval` | How often to refresh the JWKS from the remote URL | `string` | `1h` | +| `openchoreoApi.config.security.authentication.jwt.jwks.skip_tls_verify` | Skip TLS certificate verification when fetching JWKS | `boolean` | `false` | +| `openchoreoApi.config.security.authorization.bootstrap.mappings` | Default role-to-entitlement mappings to create at installation | `array` | `[]` | +| `openchoreoApi.config.security.authorization.bootstrap.roles` | Default authorization roles to create at installation | `array` | `[]` | +| `openchoreoApi.config.security.authorization.cache.enabled` | Enable caching of authorization decisions | `boolean` | `false` | +| `openchoreoApi.config.security.authorization.cache.ttl` | How long to cache authorization decisions | `string` | `5m` | +| `openchoreoApi.config.security.authorization.resync_interval` | Interval for periodic full resync of authorization policies. Acts as a safety net to recover from missed events. Set to "0" to disable. | `string` | `10m` | +| `openchoreoApi.config.security.subjects.service_account.display_name` | | `string` | `Service Account` | +| `openchoreoApi.config.security.subjects.service_account.mechanisms.jwt.entitlement.claim` | | `string` | `sub` | +| `openchoreoApi.config.security.subjects.service_account.mechanisms.jwt.entitlement.display_name` | | `string` | `Client ID` | +| `openchoreoApi.config.security.subjects.service_account.priority` | | `integer` | `2` | +| `openchoreoApi.config.security.subjects.user.display_name` | | `string` | `User` | +| `openchoreoApi.config.security.subjects.user.mechanisms.jwt.entitlement.claim` | | `string` | `groups` | +| `openchoreoApi.config.security.subjects.user.mechanisms.jwt.entitlement.display_name` | | `string` | `User Group` | +| `openchoreoApi.config.security.subjects.user.priority` | | `integer` | `1` | +| `openchoreoApi.config.server.bind_address` | Address to bind the HTTP server to | `string` | `0.0.0.0` | +| `openchoreoApi.config.server.port` | Port to listen on for HTTP requests | `integer` | `8080` | +| `openchoreoApi.config.server.publicUrl` | Public URL for the API server | `string` | `http://api.openchoreo.invalid` | +| `openchoreoApi.config.server.timeouts.idle` | Maximum time to wait for the next request when keep-alives are enabled | `string` | `60s` | +| `openchoreoApi.config.server.timeouts.read` | Maximum duration for reading the entire request, including the body | `string` | `15s` | +| `openchoreoApi.config.server.timeouts.shutdown` | Maximum duration to wait for active connections to close during shutdown | `string` | `30s` | +| `openchoreoApi.config.server.timeouts.write` | Maximum duration before timing out writes of the response | `string` | `15s` | +| `openchoreoApi.config.server.tls.cert_file` | Path to the TLS certificate file | `string` | | +| `openchoreoApi.config.server.tls.enabled` | Enable TLS for the HTTP server | `boolean` | `false` | +| `openchoreoApi.config.server.tls.key_file` | Path to the TLS private key file | `string` | | +| `openchoreoApi.containerSecurityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `openchoreoApi.containerSecurityContext.appArmorProfile.type` | AppArmor profile type | `string` | `Unconfined` | +| `openchoreoApi.containerSecurityContext.capabilities.drop` | Capabilities to drop | `array` | | +| `openchoreoApi.containerSecurityContext.readOnlyRootFilesystem` | Read-only root filesystem | `boolean` | `false` | +| `openchoreoApi.containerSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `openchoreoApi.database.path` | Path to the SQLite database file | `string` | `/var/lib/openchoreo/data/controlplane.db` | +| `openchoreoApi.enabled` | Enable the OpenChoreo API server | `boolean` | `true` | +| `openchoreoApi.http.annotations` | HTTPRoute annotations | `object` | `{}` | +| `openchoreoApi.http.enabled` | Enable HTTPRoute | `boolean` | `true` | +| `openchoreoApi.http.hostnames` | HTTPRoute hostnames | `array` | `["api.openchoreo.invalid"]` | +| `openchoreoApi.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `openchoreoApi.image.repository` | Docker image repository | `string` | `ghcr.io/openchoreo/openchoreo-api` | +| `openchoreoApi.image.tag` | Image tag. If empty, uses Chart.AppVersion | `string` | | +| `openchoreoApi.metrics.enabled` | Enable Prometheus metrics | `boolean` | `true` | +| `openchoreoApi.metrics.serviceMonitor.enabled` | Create ServiceMonitor resource | `boolean` | `false` | +| `openchoreoApi.metrics.serviceMonitor.interval` | Scrape interval | `string` | `30s` | +| `openchoreoApi.metrics.serviceMonitor.labels.prometheus` | | `string` | `kube-prometheus` | +| `openchoreoApi.metrics.serviceMonitor.namespace` | Namespace for ServiceMonitor | `string` | `monitoring` | +| `openchoreoApi.metrics.serviceMonitor.relabelings` | Metric relabeling rules | `array` | `[]` | +| `openchoreoApi.metrics.serviceMonitor.scrapeTimeout` | Scrape timeout | `string` | `10s` | +| `openchoreoApi.name` | Static name for all openchoreo-api resources (Service, Deployment, ClusterRole, etc.) | `string` | `openchoreo-api` | +| `openchoreoApi.networkPolicy.egress` | Egress rules | `array` | `[]` | +| `openchoreoApi.networkPolicy.enabled` | Enable NetworkPolicy | `boolean` | `false` | +| `openchoreoApi.networkPolicy.ingress` | Ingress rules | `array` | `[]` | +| `openchoreoApi.nodeSelector` | Node selector | `object` | `{}` | +| `openchoreoApi.podDisruptionBudget.enabled` | Enable PodDisruptionBudget | `boolean` | `false` | +| `openchoreoApi.podDisruptionBudget.minAvailable` | Minimum available pods | `integer` | `1` | +| `openchoreoApi.podSecurityContext.fsGroup` | Filesystem group | `integer` | `1000` | +| `openchoreoApi.podSecurityContext.runAsGroup` | Group ID | `integer` | `1000` | +| `openchoreoApi.podSecurityContext.runAsNonRoot` | Run as non-root user | `boolean` | `true` | +| `openchoreoApi.podSecurityContext.runAsUser` | User ID | `integer` | `1000` | +| `openchoreoApi.podSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `openchoreoApi.priorityClass.create` | Create a priority class | `boolean` | `false` | +| `openchoreoApi.priorityClass.name` | Priority class name | `string` | `openchoreo-api` | +| `openchoreoApi.priorityClass.value` | Priority class value | `integer` | `900000` | +| `openchoreoApi.replicas` | Number of API server replicas | `integer` | `1` | +| `openchoreoApi.resources.limits.cpu` | CPU limit | `string` | `1000m` | +| `openchoreoApi.resources.limits.memory` | Memory limit | `string` | `1Gi` | +| `openchoreoApi.resources.requests.cpu` | CPU request | `string` | `200m` | +| `openchoreoApi.resources.requests.memory` | Memory request | `string` | `256Mi` | +| `openchoreoApi.service.nodePort` | NodePort (only used if service.type is NodePort) | `integer,null` | `null` | +| `openchoreoApi.service.port` | Service port | `integer` | `8080` | +| `openchoreoApi.service.type` | Service type | `string` | `ClusterIP` | +| `openchoreoApi.serviceAccount.annotations` | Annotations to add to the service account | `object` | `{}` | +| `openchoreoApi.serviceAccount.name` | Service account name (always created when openchoreoApi.enabled is true) | `string` | `openchoreo-api` | +| `openchoreoApi.tolerations` | Tolerations | `array` | `[]` | +| `openchoreoApi.topologySpreadConstraints` | Topology spread constraints | `array` | | + +## Security + +Common security configuration shared across all components + +| Parameter | Description | Type | Default | +| :-------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | :-------- | :--------------------------------------------------- | +| `security.authServerBaseUrl` | Base URL for the authorization server (used for OAuth metadata) | `string` | | +| `security.authz.enabled` | Enable authorization using Casbin. Policies are loaded from ClusterAuthzRole, AuthzRole, ClusterAuthzRoleBinding, and AuthzRoleBinding CRDs. | `boolean` | `true` | +| `security.enabled` | Global security toggle - when disabled, authentication is turned off for all components | `boolean` | `true` | +| `security.jwt.audience` | Expected audience claim in JWT tokens | `string` | | +| `security.oidc.authorizationUrl` | OIDC authorization endpoint URL | `string` | `http://thunder.openchoreo.invalid/oauth2/authorize` | +| `security.oidc.externalClients` | External client configurations for authentication | `array` | | +| `security.oidc.issuer` | OIDC provider issuer URL | `string` | `http://thunder.openchoreo.invalid` | +| `security.oidc.jwksUrl` | OIDC JWKS URL for token validation | `string` | `http://thunder.openchoreo.invalid/oauth2/jwks` | +| `security.oidc.tokenUrl` | OIDC token endpoint URL | `string` | `http://thunder.openchoreo.invalid/oauth2/token` | +| `security.oidc.wellKnownEndpoint` | OIDC well-known configuration endpoint URL | `string` | | + +## Wait Job + +Wait job configuration for Helm hooks + +| Parameter | Description | Type | Default | +| :-------------- | :---------------------------- | :------- | :----------------------------- | +| `waitJob.image` | Container image for wait jobs | `string` | `bitnamilegacy/kubectl:1.32.4` | + +## Webhook Service + +Webhook service configuration + +| Parameter | Description | Type | Default | +| :--------------------- | :----------------------------------- | :------- | :---------- | +| `webhookService.ports` | Ports exposed by the webhook service | `array` | | +| `webhookService.type` | Service type | `string` | `ClusterIP` | diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/helm/data-plane.mdx b/versioned_docs/version-v1.2.0-rc.2/reference/helm/data-plane.mdx new file mode 100644 index 00000000..0eb49ac2 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/helm/data-plane.mdx @@ -0,0 +1,147 @@ +--- +title: Data Plane +description: Helm chart values reference for openchoreo-data-plane. +sidebar_position: 2 +--- + +## Dependencies + +This chart depends on the following sub-charts. For full configuration options of each dependency, please refer to their official documentation. + +| Name | Version | Repository | Condition | +| :-------------------------------------------------------------------------- | :------ | :------------------------------------------------------------------------------------------------------- | :------------------------------ | +| [kube-prometheus-stack](https://prometheus-community.github.io/helm-charts) | 81.6.3 | [https://prometheus-community.github.io/helm-charts](https://prometheus-community.github.io/helm-charts) | `kube-prometheus-stack.enabled` | + +## Cluster Agent + +Cluster Agent configuration for WebSocket connection to control plane cluster gateway + +| Parameter | Description | Type | Default | +| :------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :------------------------------------------------------------------------- | +| `clusterAgent.affinity` | Affinity rules for pod scheduling | `object` | `{}` | +| `clusterAgent.heartbeatInterval` | Interval between heartbeat messages to control plane | `string` | `30s` | +| `clusterAgent.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `clusterAgent.image.repository` | Cluster agent image repository | `string` | `ghcr.io/openchoreo/cluster-agent` | +| `clusterAgent.image.tag` | Image tag. Empty uses Chart.AppVersion. | `string` | | +| `clusterAgent.logLevel` | Log level for cluster agent | `string` | `info` | +| `clusterAgent.name` | Name of the cluster agent deployment | `string` | `cluster-agent-dataplane` | +| `clusterAgent.nodeSelector` | Node selector for pod scheduling | `object` | `{}` | +| `clusterAgent.planeID` | Logical plane identifier shared across multiple CRs connecting to the same physical plane. Defaults to Helm release name if not specified. | `string` | `default` | +| `clusterAgent.planeType` | Type of plane this agent manages | `string` | `dataplane` | +| `clusterAgent.podAnnotations` | Annotations to add to cluster agent pods | `object` | `{}` | +| `clusterAgent.podDisruptionBudget.enabled` | Enable PodDisruptionBudget for cluster agent | `boolean` | `false` | +| `clusterAgent.podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable | `integer,null` | `null` | +| `clusterAgent.podDisruptionBudget.minAvailable` | Minimum number of pods that must be available | `integer` | `1` | +| `clusterAgent.podSecurityContext.fsGroup` | Group ID for volume mounts | `integer` | `1000` | +| `clusterAgent.podSecurityContext.runAsNonRoot` | Run container as non-root user | `boolean` | `true` | +| `clusterAgent.podSecurityContext.runAsUser` | User ID to run container as | `integer` | `1000` | +| `clusterAgent.priorityClass.create` | Create a PriorityClass for cluster agent | `boolean` | `false` | +| `clusterAgent.priorityClass.name` | PriorityClass name | `string` | `cluster-agent-dataplane` | +| `clusterAgent.priorityClass.value` | Priority value (higher = more important) | `integer` | `900000` | +| `clusterAgent.rbac.create` | Create RBAC resources (ClusterRole, ClusterRoleBinding) | `boolean` | `true` | +| `clusterAgent.reconnectDelay` | Delay before attempting reconnection after disconnect | `string` | `5s` | +| `clusterAgent.replicas` | Number of cluster agent replicas (typically 1 per data plane) | `integer` | `1` | +| `clusterAgent.resources.limits.cpu` | CPU limit for the agent | `string` | `100m` | +| `clusterAgent.resources.limits.memory` | Memory limit for the agent | `string` | `256Mi` | +| `clusterAgent.resources.requests.cpu` | CPU request for the agent | `string` | `50m` | +| `clusterAgent.resources.requests.memory` | Memory request for the agent | `string` | `128Mi` | +| `clusterAgent.securityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `clusterAgent.securityContext.capabilities.drop` | Capabilities to drop from container | `array` | `["ALL"]` | +| `clusterAgent.securityContext.readOnlyRootFilesystem` | Mount root filesystem as read-only | `boolean` | `true` | +| `clusterAgent.serverUrl` | WebSocket URL of the cluster gateway in control plane | `string` | `wss://cluster-gateway.openchoreo-control-plane.svc.cluster.local:8443/ws` | +| `clusterAgent.serviceAccount.annotations` | Annotations to add to the service account | `object` | `{}` | +| `clusterAgent.serviceAccount.create` | Create a service account for the cluster agent | `boolean` | `true` | +| `clusterAgent.serviceAccount.name` | Service account name | `string` | `cluster-agent-dataplane` | +| `clusterAgent.tls.caSecretName` | CA secret name for signing agent client certificates. If empty, self-signed certs will be generated (required for multi-cluster setup). | `string` | `cluster-gateway-ca` | +| `clusterAgent.tls.clientSecretName` | Secret name for client certificate (typically same as secretName) | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.duration` | Certificate validity duration | `string` | `2160h` | +| `clusterAgent.tls.enabled` | Enable TLS for agent-gateway communication | `boolean` | `true` | +| `clusterAgent.tls.generateCerts` | Generate client certificates locally using cert-manager with a self-signed CA | `boolean` | `true` | +| `clusterAgent.tls.renewBefore` | Time before expiry to renew certificate | `string` | `360h` | +| `clusterAgent.tls.secretName` | Secret name for client certificate and key | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.serverCAConfigMap` | ConfigMap name containing server CA certificate for verifying gateway | `string` | `cluster-gateway-ca` | +| `clusterAgent.tolerations` | Tolerations for pod scheduling | `array` | `[]` | + +## Gateway + +Kubernetes Gateway API configuration. Creates a Gateway CR for HTTP/HTTPS traffic routing. + +| Parameter | Description | Type | Default | +| :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | :-------- | :--------------------------------------------------------- | +| `gateway.annotations` | Annotations added to the Gateway resource. Use this to configure cert-manager, external-dns, or other integrations. | `object` | `{}` | +| `gateway.enabled` | Enable Gateway CR creation | `boolean` | `true` | +| `gateway.gatewayClassName` | GatewayClass name to reference in the Gateway CR | `string` | `kgateway` | +| `gateway.httpPort` | Port for the HTTP listener on the gateway | `integer` | `80` | +| `gateway.httpsPort` | Port for the HTTPS listener on the gateway | `integer` | `443` | +| `gateway.infrastructure` | Gateway infrastructure configuration passed to the generated Service. Used to configure cloud provider load balancer settings via annotations. | `object` | `{"labels":{"openchoreo.dev/system-component":"gateway"}}` | +| `gateway.tls.certificateRefs` | TLS certificate references for the HTTPS listener. Each entry references a Secret containing the TLS cert/key pair. | `array` | | +| `gateway.tls.enabled` | Enable HTTPS listener on the gateway. When false, only the HTTP listener is created. | `boolean` | `true` | +| `gateway.tls.hostname` | Hostname pattern for the HTTPS listener (SNI matching) | `string` | `*.openchoreoapis.invalid` | + +## Global + +Global values shared across all components in the data plane + +| Parameter | Description | Type | Default | +| :-------------------- | :------------------------------------------------------------ | :------- | :------ | +| `global.commonLabels` | Common labels applied to all resources deployed by this chart | `object` | `{}` | + +## Kube Prometheus Stack + +For full configuration options, please refer to the [official chart documentation](https://prometheus-community.github.io/helm-charts). + +Prometheus stack configuration (kube-prometheus-stack sub-chart). Provides metrics collection for workload observability. + +| Parameter | Description | Type | Default | +| :------------------------------------------------------------------- | :----------------------------------------------------------------------------------- | :-------- | :------------------------- | +| `kube-prometheus-stack.alertmanager.enabled` | Enable Alertmanager for alert management (not used by OpenChoreo) | `boolean` | `false` | +| `kube-prometheus-stack.cleanPrometheusOperatorObjectNames` | Produce cleaner resource names without redundant prefixes | `boolean` | `true` | +| `kube-prometheus-stack.coreDns.enabled` | Enable CoreDNS metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.crds.enabled` | Install Prometheus Operator CRDs (ServiceMonitor, PodMonitor, etc.) | `boolean` | `true` | +| `kube-prometheus-stack.defaultRules.create` | Create default alerting rules (disabled - OpenChoreo uses custom rules) | `boolean` | `false` | +| `kube-prometheus-stack.enabled` | Enable the Prometheus monitoring stack for metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.fullnameOverride` | Override the full name of Prometheus stack resources | `string` | `openchoreo-observability` | +| `kube-prometheus-stack.grafana.enabled` | Enable Grafana dashboards (not used by OpenChoreo - use observability plane instead) | `boolean` | `false` | +| `kube-prometheus-stack.kube-state-metrics.collectors` | Kubernetes resource types to collect metrics from | `array` | `["pods"]` | +| `kube-prometheus-stack.kube-state-metrics.fullnameOverride` | Override the full name of kube-state-metrics resources | `string` | `kube-state-metrics` | +| `kube-prometheus-stack.kube-state-metrics.metricAllowlist` | Specific metrics to collect (allowlist filter) | `array` | | +| `kube-prometheus-stack.kube-state-metrics.metricLabelsAllowlist` | Pod labels to include in metrics for filtering by OpenChoreo resources | `array` | | +| `kube-prometheus-stack.kubeApiServer.enabled` | Enable API server metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.kubeControllerManager.enabled` | Enable controller manager metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.kubeEtcd.enabled` | Enable etcd metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.kubeProxy.enabled` | Enable kube-proxy metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.kubeScheduler.enabled` | Enable scheduler metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.nodeExporter.enabled` | Enable node-level metrics collection | `boolean` | `false` | +| `kube-prometheus-stack.prometheus.agentMode` | Run Prometheus in agent mode for lightweight remote-write only operation | `boolean` | `true` | +| `kube-prometheus-stack.prometheus.enabled` | Deploy a Prometheus instance (requires Prometheus Operator) | `boolean` | `true` | +| `kube-prometheus-stack.prometheus.prometheusSpec.remoteWrite` | Remote write endpoints for forwarding metrics to external storage | `array` | | +| `kube-prometheus-stack.prometheusOperator.enabled` | Enable Prometheus Operator for managing Prometheus instances | `boolean` | `true` | +| `kube-prometheus-stack.prometheusOperator.fullnameOverride` | Override the full name of Prometheus Operator resources | `string` | `prometheus-operator` | +| `kube-prometheus-stack.prometheusOperator.resources.limits.cpu` | CPU limit for Prometheus Operator | `string` | `40m` | +| `kube-prometheus-stack.prometheusOperator.resources.limits.memory` | Memory limit for Prometheus Operator | `string` | `50Mi` | +| `kube-prometheus-stack.prometheusOperator.resources.requests.cpu` | CPU request for Prometheus Operator | `string` | `20m` | +| `kube-prometheus-stack.prometheusOperator.resources.requests.memory` | Memory request for Prometheus Operator | `string` | `30Mi` | + +## Kubernetes Cluster Domain + +Kubernetes cluster DNS domain used for service discovery and certificate generation + +| Parameter | Description | Type | Default | +| :------------------------ | :---------------------------------------------------------------------------------- | :------- | :-------------- | +| `kubernetesClusterDomain` | Kubernetes cluster DNS domain used for service discovery and certificate generation | `string` | `cluster.local` | + +## Networking + +Network configuration for the data plane + +| Parameter | Description | Type | Default | +| :------------------- | :---------------------------------------------------------------------- | :-------- | :------ | +| `networking.enabled` | Enable networking features (network policies, service mesh integration) | `boolean` | `true` | + +## Security + +Security configuration for the data plane + +| Parameter | Description | Type | Default | +| :----------------- | :---------------------------------------------------------------- | :-------- | :------ | +| `security.enabled` | Enable security features (certificate issuers, TLS configuration) | `boolean` | `true` | diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/helm/observability-plane.mdx b/versioned_docs/version-v1.2.0-rc.2/reference/helm/observability-plane.mdx new file mode 100644 index 00000000..46de6393 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/helm/observability-plane.mdx @@ -0,0 +1,232 @@ +--- +title: Observability Plane +description: Helm chart values reference for openchoreo-observability-plane. +sidebar_position: 4 +--- + +## Cluster Agent + +Cluster Agent configuration for WebSocket-based communication with the control plane's cluster gateway + +| Parameter | Description | Type | Default | +| :------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :------------------------------------------------------------------------- | +| `clusterAgent.affinity` | Affinity rules for pod scheduling | `object` | `{}` | +| `clusterAgent.heartbeatInterval` | Interval between heartbeat messages to the control plane | `string` | `30s` | +| `clusterAgent.image.pullPolicy` | Image pull policy for the cluster agent | `string` | `IfNotPresent` | +| `clusterAgent.image.repository` | Container image repository for the cluster agent | `string` | `ghcr.io/openchoreo/cluster-agent` | +| `clusterAgent.image.tag` | Container image tag (defaults to Chart.AppVersion if empty) | `string` | | +| `clusterAgent.logLevel` | Log level for the cluster agent | `string` | `info` | +| `clusterAgent.name` | Name of the cluster agent deployment and associated resources | `string` | `cluster-agent-observabilityplane` | +| `clusterAgent.nodeSelector` | Node selector for pod scheduling | `object` | `{}` | +| `clusterAgent.planeID` | Logical plane identifier for multi-tenancy. Multiple CRs with the same planeID share one agent. Defaults to Helm release name if not specified. | `string` | `default` | +| `clusterAgent.planeType` | Type of plane this agent serves | `string` | `observabilityplane` | +| `clusterAgent.podAnnotations` | Annotations to add to cluster agent pods | `object` | `{}` | +| `clusterAgent.podDisruptionBudget.enabled` | Enable PodDisruptionBudget for cluster agent | `boolean` | `false` | +| `clusterAgent.podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable | `integer,null` | `null` | +| `clusterAgent.podDisruptionBudget.minAvailable` | Minimum number of pods that must be available | `integer` | `1` | +| `clusterAgent.podSecurityContext.fsGroup` | Filesystem group ID | `integer` | `1000` | +| `clusterAgent.podSecurityContext.runAsNonRoot` | Run as non-root user | `boolean` | `true` | +| `clusterAgent.podSecurityContext.runAsUser` | User ID to run as | `integer` | `1000` | +| `clusterAgent.priorityClass.create` | Create a priority class | `boolean` | `false` | +| `clusterAgent.priorityClass.name` | Name of the priority class | `string` | `cluster-agent-observabilityplane` | +| `clusterAgent.priorityClass.value` | Priority value | `integer` | `900000` | +| `clusterAgent.rbac.create` | Create ClusterRole and ClusterRoleBinding for the agent | `boolean` | `true` | +| `clusterAgent.reconnectDelay` | Delay before reconnecting after connection loss | `string` | `5s` | +| `clusterAgent.replicas` | Number of cluster agent pod replicas | `integer` | `1` | +| `clusterAgent.resources.limits.cpu` | CPU limit | `string` | `100m` | +| `clusterAgent.resources.limits.memory` | Memory limit | `string` | `256Mi` | +| `clusterAgent.resources.requests.cpu` | CPU request | `string` | `50m` | +| `clusterAgent.resources.requests.memory` | Memory request | `string` | `128Mi` | +| `clusterAgent.securityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `boolean` | `false` | +| `clusterAgent.securityContext.capabilities.drop` | Capabilities to drop | `array` | | +| `clusterAgent.securityContext.readOnlyRootFilesystem` | Mount root filesystem as read-only | `boolean` | `true` | +| `clusterAgent.serverCANamespace` | Namespace where cluster-gateway CA ConfigMap exists | `string` | `openchoreo-control-plane` | +| `clusterAgent.serverUrl` | WebSocket URL of the cluster gateway in the control plane | `string` | `wss://cluster-gateway.openchoreo-control-plane.svc.cluster.local:8443/ws` | +| `clusterAgent.serviceAccount.annotations` | Annotations to add to the service account | `object` | `{}` | +| `clusterAgent.serviceAccount.create` | Create a dedicated service account | `boolean` | `true` | +| `clusterAgent.serviceAccount.name` | Name of the service account | `string` | `cluster-agent-observabilityplane` | +| `clusterAgent.tls.caSecretName` | CA secret name for signing agent client certificates. If empty, self-signed certs will be generated (required for multi-cluster setup). | `string` | `cluster-gateway-ca` | +| `clusterAgent.tls.caSecretNamespace` | Namespace where the CA secret exists. If empty, self-signed certs will be generated (required for multi-cluster setup). | `string` | `openchoreo-control-plane` | +| `clusterAgent.tls.caValue` | Inline CA certificate in PEM format (for multi-cluster, takes precedence) | `string` | | +| `clusterAgent.tls.clientSecretName` | Name of the client certificate Secret | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.duration` | Certificate validity duration (e.g., 2160h = 90 days) | `string` | `2160h` | +| `clusterAgent.tls.enabled` | Enable TLS for cluster agent communication | `boolean` | `true` | +| `clusterAgent.tls.generateCerts` | Generate client certificates locally using cert-manager with a self-signed CA | `boolean` | `true` | +| `clusterAgent.tls.renewBefore` | Time before expiry to renew certificate (e.g., 360h = 15 days) | `string` | `360h` | +| `clusterAgent.tls.secretName` | Name of the Secret containing client certificate and key | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.serverCAConfigMap` | Name of the ConfigMap containing server CA certificate | `string` | `cluster-gateway-ca` | +| `clusterAgent.tls.serverCAValue` | Inline server CA certificate in PEM format (for multi-cluster setups) | `string` | | +| `clusterAgent.tolerations` | Tolerations for pod scheduling | `array` | `[]` | + +## Controller Manager + +Configuration for the observability plane controller manager that reconciles ObservabilityAlertRules and other CRDs + +| Parameter | Description | Type | Default | +| :-------------------------------------------------------------------- | :---------------------------------------------------------------------- | :-------- | :------------------------------------------------------------------------ | +| `controllerManager.affinity` | Affinity rules for pod scheduling | `object` | `{}` | +| `controllerManager.clusterGateway.enabled` | Enable cluster gateway integration for multi-cluster setups | `boolean` | `false` | +| `controllerManager.clusterGateway.tls.caConfigMap` | Name of the ConfigMap containing the gateway CA certificate | `string` | `cluster-gateway-ca` | +| `controllerManager.clusterGateway.tls.caPath` | Path to the CA certificate file for gateway verification | `string` | `/etc/cluster-gateway/ca.crt` | +| `controllerManager.clusterGateway.url` | URL of the cluster gateway service in the control plane | `string` | `https://cluster-gateway.openchoreo-control-plane.svc.cluster.local:8443` | +| `controllerManager.containerSecurityContext.allowPrivilegeEscalation` | Prevent privilege escalation within the container | `boolean` | `false` | +| `controllerManager.containerSecurityContext.capabilities.drop` | Capabilities to drop from the container | `array` | `["ALL"]` | +| `controllerManager.containerSecurityContext.readOnlyRootFilesystem` | Mount root filesystem as read-only | `boolean` | `false` | +| `controllerManager.containerSecurityContext.seccompProfile.type` | Seccomp profile type | `string` | `RuntimeDefault` | +| `controllerManager.deploymentPlane` | Identifier for this deployment plane type | `string` | `observabilityplane` | +| `controllerManager.enabled` | Enable or disable the controller manager deployment | `boolean` | `true` | +| `controllerManager.image.pullPolicy` | Image pull policy for the controller manager container | `string` | `IfNotPresent` | +| `controllerManager.image.repository` | Container image repository for the controller manager | `string` | `ghcr.io/openchoreo/controller` | +| `controllerManager.image.tag` | Container image tag (defaults to Chart.AppVersion if empty) | `string` | | +| `controllerManager.manager.args` | Command line arguments passed to the controller manager | `array` | | +| `controllerManager.manager.env.enableWebhooks` | Enable or disable admission webhooks | `string` | `false` | +| `controllerManager.name` | Name of the controller manager deployment and associated resources | `string` | `controller-manager` | +| `controllerManager.nodeSelector` | Node selector for pod scheduling constraints | `object` | `{}` | +| `controllerManager.podSecurityContext.fsGroup` | Group ID for filesystem access | `integer` | `1000` | +| `controllerManager.podSecurityContext.runAsGroup` | Group ID to run the container process | `integer` | `1000` | +| `controllerManager.podSecurityContext.runAsNonRoot` | Require the container to run as a non-root user | `boolean` | `true` | +| `controllerManager.podSecurityContext.runAsUser` | User ID to run the container process | `integer` | `1000` | +| `controllerManager.priorityClass.create` | Create a priority class for the controller manager | `boolean` | `false` | +| `controllerManager.priorityClass.name` | Name of the priority class | `string` | `observabilityplane-controller-manager` | +| `controllerManager.priorityClass.value` | Priority value (higher values indicate higher priority) | `integer` | `900000` | +| `controllerManager.replicas` | Number of controller manager pod replicas | `integer` | `1` | +| `controllerManager.resources.limits.cpu` | CPU limit for the controller manager | `string` | `500m` | +| `controllerManager.resources.limits.memory` | Memory limit for the controller manager | `string` | `512Mi` | +| `controllerManager.resources.requests.cpu` | CPU request for the controller manager | `string` | `100m` | +| `controllerManager.resources.requests.memory` | Memory request for the controller manager | `string` | `256Mi` | +| `controllerManager.serviceAccount.annotations` | Annotations to add to the service account | `object` | `{}` | +| `controllerManager.serviceAccount.create` | Create a dedicated service account for the controller manager | `boolean` | `true` | +| `controllerManager.tolerations` | Tolerations for pod scheduling on tainted nodes | `array` | `[]` | +| `controllerManager.topologySpreadConstraints` | Topology spread constraints for pod distribution across failure domains | `array` | `[]` | + +## Gateway + +Gateway resource configuration for observability plane routing + +| Parameter | Description | Type | Default | +| :-------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------- | :--------------------- | +| `gateway.annotations` | Annotations added to the Gateway resource. Use this to configure cert-manager, external-dns, or other integrations. | `object` | `{}` | +| `gateway.enabled` | Enable Gateway CR creation | `boolean` | `true` | +| `gateway.httpPort` | HTTP listener port | `integer` | `80` | +| `gateway.httpsPort` | HTTPS listener port | `integer` | `443` | +| `gateway.infrastructure` | Gateway infrastructure configuration passed to the generated Service. Used to configure cloud provider load balancer settings via annotations. Example for AWS with Elastic IP: infrastructure: annotations: service.beta.kubernetes.io/aws-load-balancer-type: "external" | `object` | | +| `gateway.tls.certificateRefs` | TLS certificate references for the HTTPS listener. Each entry references a Secret containing the TLS cert/key pair. | `array` | | +| `gateway.tls.enabled` | Enable HTTPS listener on the gateway. When false, only the HTTP listener is created. | `boolean` | `true` | +| `gateway.tls.hostname` | Hostname pattern for the HTTPS listener (SNI matching) | `string` | `*.openchoreo.invalid` | +| `gateway.tlsPassthrough.enabled` | Enable TLS passthrough listener (used for OpenSearch direct access) | `boolean` | `false` | +| `gateway.tlsPassthrough.hostname` | Hostname for TLS passthrough listener | `string` | | +| `gateway.tlsPassthrough.port` | Port for TLS passthrough listener | `integer` | `11443` | + +## Global + +Global values shared across all components in the observability plane + +| Parameter | Description | Type | Default | +| :------------------------ | :----------------------------------------------------------- | :------- | :-------------- | +| `global.commonLabels` | Common labels applied to all resources created by this chart | `object` | `{}` | +| `global.installationMode` | Installation mode of OpenChoreo | `string` | `singleCluster` | + +## Kubernetes Cluster Domain + +Kubernetes cluster domain used for service discovery DNS resolution + +| Parameter | Description | Type | Default | +| :------------------------ | :------------------------------------------------------------------ | :------- | :-------------- | +| `kubernetesClusterDomain` | Kubernetes cluster domain used for service discovery DNS resolution | `string` | `cluster.local` | + +## Observer + +OpenChoreo Observer service configuration - REST API that abstracts OpenSearch for logging, metrics, and tracing + +| Parameter | Description | Type | Default | +| :------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------- | :------------------------------------------- | +| `observer.alertStoreBackend` | Alert entry storage backend for fired alerts | `string` | `sqlite` | +| `observer.alertStoreSqliteSize` | PVC size for SQLite alert entry storage | `string` | `128Mi` | +| `observer.authzTlsInsecureSkipVerify` | Skip TLS certificate verification when calling the control plane authz service (use for self-signed certs) | `boolean` | `false` | +| `observer.controlPlaneApiUrl` | Control plane API base URL used by observer | `string` | `http://api.openchoreo.localhost:8080` | +| `observer.cors.allowedOrigins` | List of allowed origins for CORS requests. Empty list disables CORS. | `array` | | +| `observer.extraEnvs` | Extra environment variables for the Observer container | `array` | | +| `observer.http.enabled` | Enable HTTPRoute | `boolean` | `true` | +| `observer.http.hostnames` | HTTPRoute hostnames | `array` | | +| `observer.image.pullPolicy` | Image pull policy for the Observer container | `string` | `IfNotPresent` | +| `observer.image.repository` | Container image repository for the Observer | `string` | `ghcr.io/openchoreo/observer` | +| `observer.image.tag` | Container image tag (defaults to Chart.AppVersion if empty) | `string` | | +| `observer.internalService.port` | Service port for the Observer internal API | `integer` | `8081` | +| `observer.logLevel` | Log level for the Observer service | `string` | `info` | +| `observer.logsAdapter.timeout` | Timeout for logs adapter requests | `string` | `30s` | +| `observer.logsAdapter.url` | URL of the logs adapter service | `string` | `http://logs-adapter:9098` | +| `observer.oauthClientId` | OAuth2 client ID used by the Observer when calling the control plane API | `string` | `openchoreo-observer-resource-reader-client` | +| `observer.replicas` | Number of Observer pod replicas | `integer` | `1` | +| `observer.resources.limits.cpu` | CPU limit for the Observer | `string` | `200m` | +| `observer.resources.limits.memory` | Memory limit for the Observer | `string` | `200Mi` | +| `observer.resources.requests.cpu` | CPU request for the Observer | `string` | `100m` | +| `observer.resources.requests.memory` | Memory request for the Observer | `string` | `128Mi` | +| `observer.secretName` | Name of an existing Secret injected via envFrom into the Observer container. Required keys - UID_RESOLVER_OAUTH_CLIENT_SECRET; ALERT_STORE_DSN is also required when alertStoreBackend=postgresql (Observer fails to start otherwise) and ignored for sqlite (a default DSN is used). | `string` | | +| `observer.security.subjectTypes` | Subject type configurations for JWT subject resolution | `array` | | +| `observer.service.port` | Service port for the Observer API | `integer` | `8080` | +| `observer.service.type` | Kubernetes service type | `string` | `ClusterIP` | +| `observer.tracingAdapter.timeout` | Timeout for tracing adapter requests | `string` | `30s` | +| `observer.tracingAdapter.url` | URL of the tracing adapter service | `string` | `http://tracing-adapter:9100` | + +:::note +The Observer includes a **uid-resolver** component that uses the OAuth2 `client_credentials` grant to call the control plane API for component/project/environment identity resolution. +The relevant values are `observer.oauthClientId`, the `UID_RESOLVER_OAUTH_CLIENT_SECRET` key in `observer.secretName` secret, and `security.oidc.tokenUrl`. +When using an external identity provider, refer to [Observer External IDP Configuration](../../platform-engineer-guide/observability-alerting.mdx#observer-external-idp-configuration) for setup steps. +::: + +## Rca + +AI-powered Root Cause Analysis agent configuration + +| Parameter | Description | Type | Default | +| :------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------- | :------------------------------------- | +| `rca.authz.timeoutSeconds` | Authorization request timeout in seconds | `integer` | `30` | +| `rca.cors.allowedOrigins` | List of allowed origins for CORS requests. Empty list disables CORS. | `array` | | +| `rca.enabled` | Enable SRE Agent deployment | `boolean` | `false` | +| `rca.extraEnvs` | Extra environment variables for the SRE Agent container | `array` | | +| `rca.http.enabled` | Enable HTTPRoute | `boolean` | `true` | +| `rca.http.hostnames` | HTTPRoute hostnames | `array` | | +| `rca.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `rca.image.repository` | Container image repository | `string` | `ghcr.io/openchoreo/ai-rca-agent` | +| `rca.image.tag` | Container image tag (defaults to Chart.AppVersion if empty) | `string` | | +| `rca.llm.modelName` | LLM model name (e.g., gpt-5.2) | `string` | | +| `rca.logLevel` | Log level for the SRE Agent | `string` | `INFO` | +| `rca.name` | Name of the SRE Agent deployment | `string` | `ai-rca-agent` | +| `rca.oauth.clientId` | OAuth2 client ID registered with the IDP | `string` | `openchoreo-rca-agent` | +| `rca.observerApiUrl` | Observer API base URL | `string` | `http://observer:8080` | +| `rca.openchoreoApiUrl` | OpenChoreo API base URL used by the SRE Agent | `string` | `http://api.openchoreo.localhost:8080` | +| `rca.remedAgent` | Enable remediation agent | `boolean` | `true` | +| `rca.replicas` | Number of SRE Agent replicas | `integer` | `1` | +| `rca.reportBackend` | Report storage backend type | `string` | `sqlite` | +| `rca.resources.limits.cpu` | CPU limit | `string` | `250m` | +| `rca.resources.limits.memory` | Memory limit | `string` | `1536Mi` | +| `rca.resources.requests.cpu` | CPU request | `string` | `100m` | +| `rca.resources.requests.memory` | Memory request | `string` | `1024Mi` | +| `rca.secretName` | Name of an existing Secret injected via envFrom into the SRE Agent container. Required keys - RCA_LLM_API_KEY, OAUTH_CLIENT_SECRET. Optional keys - SQL_BACKEND_URI (when reportBackend is postgresql). | `string` | `rca-agent-secret` | +| `rca.service.port` | Service port | `integer` | `8080` | +| `rca.service.type` | Service type | `string` | `ClusterIP` | +| `rca.sqliteStorageSize` | PVC storage size for SQLite (only used when reportBackend is sqlite) | `string` | `128Mi` | + +## Security + +Common security configuration shared across all components + +| Parameter | Description | Type | Default | +| :----------------------------------------------- | :-------------------------------------------------------------------------------------- | :-------- | :------ | +| `security.enabled` | Global security toggle - when disabled, authentication is turned off for all components | `boolean` | `true` | +| `security.jwt.audience` | Expected audience claim in JWT tokens | `string` | | +| `security.oidc.authServerBaseUrl` | Base URL for the authorization server (used for OAuth metadata) | `string` | | +| `security.oidc.issuer` | OIDC issuer URL | `string` | | +| `security.oidc.jwksUrl` | JWKS URL for token verification | `string` | | +| `security.oidc.jwksUrlTlsInsecureSkipVerify` | Skip TLS verification for JWKS URL | `string` | `false` | +| `security.oidc.tokenUrl` | OIDC token endpoint URL | `string` | | +| `security.oidc.uidResolverTlsInsecureSkipVerify` | Skip TLS verification for the UID resolver OAuth token endpoint (for self-signed certs) | `string` | `false` | + +## Tls + +Global TLS certificate configuration using cert-manager + +| Parameter | Description | Type | Default | +| :------------- | :--------------------------------------------------------------------------- | :-------- | :------ | +| `tls.dnsNames` | DNS names for generated wildcard certificate. Required when tls.enabled=true | `array` | `[]` | +| `tls.enabled` | Enable TLS certificate generation for the observability plane | `boolean` | `false` | diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/helm/workflow-plane.mdx b/versioned_docs/version-v1.2.0-rc.2/reference/helm/workflow-plane.mdx new file mode 100644 index 00000000..c494b24d --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/helm/workflow-plane.mdx @@ -0,0 +1,97 @@ +--- +title: Workflow Plane +description: Helm chart values reference for openchoreo-workflow-plane. +sidebar_position: 3 +--- + +## Dependencies + +This chart depends on the following sub-charts. For full configuration options of each dependency, please refer to their official documentation. + +| Name | Version | Repository | Condition | +| :----------------------------------------------------- | :------ | :--------------------------------------------------------------------------- | :-------- | +| [argo-workflows](https://argoproj.github.io/argo-helm) | 0.45.2 | [https://argoproj.github.io/argo-helm](https://argoproj.github.io/argo-helm) | - | + +## Argo Workflows + +For full configuration options, please refer to the [official chart documentation](https://argoproj.github.io/argo-helm). + +Argo Workflows sub-chart configuration. See https://github.com/argoproj/argo-helm/tree/main/charts/argo-workflows for all options. + +| Parameter | Description | Type | Default | +| :---------------------------------------------------- | :--------------------------------------------------- | :-------- | :------ | +| `argo-workflows.controller.resources.limits.cpu` | CPU limit for the controller | `string` | `50m` | +| `argo-workflows.controller.resources.limits.memory` | Memory limit for the controller | `string` | `64Mi` | +| `argo-workflows.controller.resources.requests.cpu` | CPU request for the controller | `string` | `25m` | +| `argo-workflows.controller.resources.requests.memory` | Memory request for the controller | `string` | `32Mi` | +| `argo-workflows.crds.keep` | Keep CRDs on chart uninstall | `boolean` | `false` | +| `argo-workflows.fullnameOverride` | Override the full name of Argo Workflows resources | `string` | `argo` | +| `argo-workflows.server.enabled` | Enable the Argo Workflows server UI | `boolean` | `false` | +| `argo-workflows.workflow.serviceAccount.create` | Create service account for workflows | `boolean` | `true` | +| `argo-workflows.workflowNamespaces` | Namespaces where Argo Workflows can submit workflows | `array` | | + +## Cluster Agent + +Cluster Agent configuration for agent-based communication with control plane + +| Parameter | Description | Type | Default | +| :------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :------------------------------------------------------------------------- | +| `clusterAgent.affinity` | Affinity rules for cluster agent pods | `object` | | +| `clusterAgent.heartbeatInterval` | Heartbeat interval for control plane connection | `string` | `30s` | +| `clusterAgent.image.pullPolicy` | Image pull policy | `string` | `IfNotPresent` | +| `clusterAgent.image.repository` | Image repository for cluster agent | `string` | `ghcr.io/openchoreo/cluster-agent` | +| `clusterAgent.image.tag` | Image tag. If empty, uses Chart.AppVersion. | `string` | | +| `clusterAgent.logLevel` | Log level for cluster agent | `string` | `info` | +| `clusterAgent.name` | Name of the cluster agent deployment | `string` | `cluster-agent-workflowplane` | +| `clusterAgent.nodeSelector` | Node selector for cluster agent pods | `object` | | +| `clusterAgent.planeID` | Logical plane identifier. Shared across multiple CRs connecting to the same physical plane for multi-tenancy. | `string` | `default` | +| `clusterAgent.planeType` | Type of plane | `string` | `workflowplane` | +| `clusterAgent.podAnnotations` | Annotations to add to cluster agent pods | `object` | | +| `clusterAgent.podDisruptionBudget.enabled` | Enable PodDisruptionBudget for cluster agent | `boolean` | `false` | +| `clusterAgent.podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable | `integer,null` | `null` | +| `clusterAgent.podDisruptionBudget.minAvailable` | Minimum number of pods that must be available | `integer` | `1` | +| `clusterAgent.podSecurityContext.fsGroup` | | `integer` | `1000` | +| `clusterAgent.podSecurityContext.runAsNonRoot` | | `boolean` | `true` | +| `clusterAgent.podSecurityContext.runAsUser` | | `integer` | `1000` | +| `clusterAgent.priorityClass.create` | Create priority class | `boolean` | `false` | +| `clusterAgent.priorityClass.name` | Priority class name | `string` | `cluster-agent-workflowplane` | +| `clusterAgent.priorityClass.value` | Priority value | `integer` | `900000` | +| `clusterAgent.rbac.create` | Create RBAC resources | `boolean` | `true` | +| `clusterAgent.reconnectDelay` | Delay before reconnecting on disconnection | `string` | `5s` | +| `clusterAgent.replicas` | Number of cluster agent replicas | `integer` | `1` | +| `clusterAgent.resources.limits.cpu` | | `string` | `100m` | +| `clusterAgent.resources.limits.memory` | | `string` | `256Mi` | +| `clusterAgent.resources.requests.cpu` | | `string` | `50m` | +| `clusterAgent.resources.requests.memory` | | `string` | `128Mi` | +| `clusterAgent.securityContext.allowPrivilegeEscalation` | | `boolean` | `false` | +| `clusterAgent.securityContext.capabilities.drop` | | `array` | | +| `clusterAgent.securityContext.readOnlyRootFilesystem` | | `boolean` | `true` | +| `clusterAgent.serverUrl` | WebSocket URL of the cluster gateway in control plane | `string` | `wss://cluster-gateway.openchoreo-control-plane.svc.cluster.local:8443/ws` | +| `clusterAgent.serviceAccount.annotations` | Annotations to add to the service account | `object` | | +| `clusterAgent.serviceAccount.create` | Create service account | `boolean` | `true` | +| `clusterAgent.serviceAccount.name` | Service account name | `string` | `cluster-agent-workflowplane` | +| `clusterAgent.tls.caSecretName` | CA secret name for signing agent client certificates. If empty, self-signed certs will be generated (required for multi-cluster setup). | `string` | `cluster-gateway-ca` | +| `clusterAgent.tls.clientSecretName` | Client certificate secret name | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.duration` | Certificate duration | `string` | `2160h` | +| `clusterAgent.tls.enabled` | Enable TLS for agent communication | `boolean` | `true` | +| `clusterAgent.tls.generateCerts` | Generate client certificates locally using cert-manager with a self-signed CA | `boolean` | `true` | +| `clusterAgent.tls.renewBefore` | Certificate renewal window | `string` | `360h` | +| `clusterAgent.tls.secretName` | Secret containing client certificate and key | `string` | `cluster-agent-tls` | +| `clusterAgent.tls.serverCAConfigMap` | ConfigMap containing server CA certificate for verifying gateway | `string` | `cluster-gateway-ca` | +| `clusterAgent.tolerations` | Tolerations for cluster agent pods | `array` | | + +## Global + +Global configuration values shared across all components + +| Parameter | Description | Type | Default | +| :-------------------- | :------------------------------------- | :------- | :------ | +| `global.commonLabels` | Common labels to add to every resource | `object` | | + +## Wait Job + +Wait job configuration for post-install hooks + +| Parameter | Description | Type | Default | +| :-------------- | :-------------------------------------------------------- | :------- | :----------------------------- | +| `waitJob.image` | Container image used for wait jobs (must contain kubectl) | `string` | `bitnamilegacy/kubectl:1.32.4` | diff --git a/versioned_docs/version-v1.2.0-rc.2/reference/mcp-servers.mdx b/versioned_docs/version-v1.2.0-rc.2/reference/mcp-servers.mdx new file mode 100644 index 00000000..a077a5fa --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/reference/mcp-servers.mdx @@ -0,0 +1,473 @@ +--- +title: MCP Servers +description: MCP servers enabling AI assistants to manage resources and query observability data +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# MCP Servers + +OpenChoreo provides Model Context Protocol (MCP) servers that enable AI assistants to interact with your OpenChoreo platform. + +## Overview + +OpenChoreo provides two MCP servers: + +1. **Control Plane MCP Server** - Provides tools for managing OpenChoreo resources (namespaces, projects, components, builds, deployments, infrastructure) +2. **Observability Plane MCP Server** - Provides tools for accessing observability data (logs, metrics, traces, alerts, incidents) + +Each MCP server is independently accessible and requires separate configuration. + +### Using Both MCP Servers Together + +:::tip Recommended Configuration +For the best experience, configure **both** the Control Plane and Observability Plane MCP servers together. Observability tools accept resource names (namespace, project, component, environment) as parameters — use the Control Plane MCP server to list and discover these names, then pass them directly to Observability tools. + +**Example workflow:** + +1. Use Control Plane MCP (`list_namespaces`, `list_projects`, `list_components`, `list_environments`) to discover resource names +2. Use those names with Observability Plane MCP tools (`query_component_logs`, `query_traces`, `query_http_metrics`, `query_alerts`) to fetch observability data + ::: + +## Available Tools + +### Control Plane MCP Server + +The Control Plane MCP server is organized into seven toolsets. + +Note: The cluster-prefixed tools have been deprecated since v1.1 and, as of v1.2.0, are hidden from `tools/list` by default (see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools)). + +:::info Tools in multiple toolsets +Some read-only tools (marked with †) appear in both the default developer toolsets and the PE toolset. This allows platform engineers to use the PE toolset alongside Namespace and Project toolsets without needing to enable all developer toolsets. +::: + +#### Deprecated cluster-prefixed tools + +:::warning Deprecation notice +The `*_cluster_*` tools (cluster-scoped component types, traits, workflows, and planes) are **deprecated**. Each one has been collapsed into its namespace-scoped counterpart, which now accepts a `scope: "namespace" | "cluster"` argument (defaults to `"namespace"`). For example, `get_cluster_component_type` is replaced by `get_component_type` called with `scope: "cluster"`. + +**Rollout timeline:** + +| Release | `tools/list` behavior | Callable? | +| -------------------- | --------------------------------------------------------------------------------- | --------- | +| **v1.1.x** | Aliases **listed by default**, each marked deprecated in its description. | Yes | +| **current (v1.2.0)** | Aliases **hidden by default**; set `?includeDeprecatedTools=true` to opt back in. | Yes | +| **v1.3.0** | Aliases **removed**; the `includeDeprecatedTools` flag is also removed. | No | + +Every invocation of a deprecated alias returns a deprecation warning pointing to the replacement, so clients that ignore `tools/list` metadata still get a migration signal at call time. + +If your integration depends on the legacy `*_cluster_*` names, migrate to the canonical tool with `scope: "cluster"` — as of v1.2.0, discovery-driven clients that read `tools/list` no longer see the aliases unless you append `?includeDeprecatedTools=true` to the MCP server URL (see [Per-Session Tool Filtering](#per-session-tool-filtering)). +::: + +
+Namespace Toolset + +- `list_namespaces` — List all namespaces (top-level containers for organizing projects, components, and resources) +- `create_namespace` — Create a new namespace +- `list_secret_references` ‡ — List all secret references (credentials and sensitive configuration) for a namespace +- `get_secret_reference` ‡ — Get a single secret reference's full spec (template, data sources, refresh interval, target plane). For sync status, query `get_resource_events` against the rendered ExternalSecret on the data plane + +‡ Also registered on the PE toolset. Authoring secret references (`create_`, `update_`, `delete_secret_reference`) is PE-only — see the PE toolset below. + +
+ +
+Project Toolset + +- `list_projects` — List all projects in a namespace (logical groupings of related components sharing deployment pipelines) +- `create_project` — Create a new project in a namespace +- `update_project` — Partially update a project (`display_name`, `description`, `deployment_pipeline`); only provided fields change +- `delete_project` — Delete a project; cascades via finalizer to remove all components, workloads, releases, and bindings owned by the project + +
+ +
+Component Toolset + +**Component Management** + +- `create_component` — Create a new component in a project +- `list_components` — List all components in a project (deployable units with independent build and deployment lifecycles) +- `get_component` — Get detailed component info including configuration, deployment status, and builds +- `patch_component` — Partially update a component's configuration (display_name, description, autoDeploy, parameters, traits, workflow); pass an empty array for traits to clear all traits +- `delete_component` — Delete a component; cascades via finalizer to its workloads, releases, and release bindings +- `get_component_schema` — Get the JSON schema for a component's configuration options + +**Workload Management** + +- `list_workloads` — List workloads for a component (names, images, endpoint names) +- `get_workload` — Get detailed workload info; returns the full Spec (round-trip-safe with `update_workload`) +- `create_workload` — Create a new workload for a component (runtime spec: containers, resources, env vars) +- `update_workload` — Update an existing workload's specification (container config, env vars, port mappings, resource limits) +- `delete_workload` — Delete a workload; for reversible removal of just the deployment, use `update_release_binding` with `release_state: Undeploy` +- `get_workload_schema` — Get the JSON schema for the workload specification + +**Platform Standards — Read-Only, Namespace-Scoped** + +- `list_component_types` † — List available component types in a namespace (WebApplication, Service, ScheduledTask, etc.) +- `get_component_type` † — Get the full definition of a component type including its complete spec +- `get_component_type_schema` † — Get the parameter schema for a component type +- `list_traits` † — List available traits in a namespace (autoscaling, ingress, service mesh, etc.) +- `get_trait` † — Get the full definition of a trait including its complete spec +- `get_trait_schema` † — Get the parameter schema for a trait + +**Platform Standards — Read-Only, Cluster-Scoped** _(deprecated — use the namespace-scoped tool with `scope: "cluster"`; see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools))_ + +- `list_cluster_component_types` † — List cluster-scoped component types shared across namespaces +- `get_cluster_component_type` † — Get the full definition of a cluster-scoped component type +- `get_cluster_component_type_schema` † — Get the schema for a cluster-scoped component type +- `list_cluster_traits` † — List cluster-scoped traits shared across namespaces +- `get_cluster_trait` † — Get the full definition of a cluster-scoped trait +- `get_cluster_trait_schema` † — Get the schema for a cluster-scoped trait + +
+ +
+Resource Toolset + +The Resource toolset mirrors the Component toolset for managed infrastructure: developers create Resources that reference platform-engineer-published ResourceTypes, and workloads consume the declared outputs via `dependencies.resources[]`. ResourceType writes, ResourceRelease management, and ResourceReleaseBinding CRUD live in the PE and Deployment toolsets respectively. + +**Resource Management** + +- `list_resources` — List all Resources in a project (managed-infrastructure dependencies like databases, queues, caches, object stores) +- `get_resource` — Get a Resource's full spec including parameters, referenced (Cluster)ResourceType, latest cut release, and conditions +- `create_resource` — Create a new Resource referencing a ResourceType or ClusterResourceType; the controller cuts the first ResourceRelease automatically +- `update_resource` — Update a Resource's parameters (full replacement). `spec.owner` and `spec.type` are immutable +- `delete_resource` — Delete a Resource; the two-phase finalizer blocks until all ResourceReleaseBindings are removed, then GCs owned ResourceReleases + +**Platform Standards — Read-Only, Namespace-Scoped** + +- `list_resource_types` † — List available ResourceTypes in a namespace (Postgres, Valkey, NATS, S3 buckets, Crossplane claims, etc.). Pass `scope: "cluster"` for ClusterResourceTypes +- `get_resource_type` † — Get the full definition of a ResourceType including parameter schema, environmentConfigs schema, outputs, and rendered resources. Pass `scope: "cluster"` for a ClusterResourceType +- `get_resource_type_schema` † — Get the parameter schema for a ResourceType. Pass `scope: "cluster"` for a ClusterResourceType + +
+ +
+Deployment Toolset + +**Components** + +- `create_release_binding` — Create a new release binding to deploy a component to a specific environment +- `list_release_bindings` — List release bindings associating releases with environments for a component +- `get_release_binding` — Get detailed info for a specific release binding including state, overrides, and endpoints +- `update_release_binding` — Update a release binding's configuration (release, release_state, overrides, traits, workload settings); set `release_state: Active` to deploy or `Undeploy` to remove from the data plane while keeping the binding +- `delete_release_binding` — Delete a release binding entirely; for reversible removal that keeps the binding, use `update_release_binding` with `release_state: Undeploy` instead +- `delete_component_release` — Delete a component release (immutable; useful for pruning old releases) + +**Resources** + +- `create_resource_release_binding` — Create a new ResourceReleaseBinding to deploy a Resource to a specific environment +- `list_resource_release_bindings` — List ResourceReleaseBindings in a namespace; optionally filter by project, resource, or environment +- `get_resource_release_binding` — Get detailed info for a ResourceReleaseBinding including the pinned ResourceRelease, retention policy, environment overrides, and resolved outputs +- `update_resource_release_binding` — Update a ResourceReleaseBinding's configuration (`resource_release`, `retain_policy`, `resource_type_environment_configs`); promotion is performed by setting `resource_release` to a new ResourceRelease name +- `delete_resource_release_binding` — Delete a ResourceReleaseBinding; if effective `retainPolicy` is `Retain`, the finalizer holds and the data-plane state persists until the policy is flipped to `Delete` +- `delete_resource_release` — Delete a ResourceRelease snapshot (immutable; useful for pruning old releases) + +**Pipelines & Environments** + +- `list_deployment_pipelines` — List all deployment pipelines defining environment promotion order in a namespace +- `get_deployment_pipeline` — Get detailed deployment pipeline info including stages, promotion order, and environments +- `list_environments` † — List all environments (deployment targets like dev, staging, production) in a namespace + +
+ +
+Build Toolset + +- `trigger_workflow_run` — Trigger a workflow run for a component using the component's configured workflow and parameters +- `create_workflow_run` — Create a new workflow run by specifying a workflow name and optional parameters +- `list_workflow_runs` — List workflow run executions in a namespace; optionally filter by project and component +- `get_workflow_run` — Get detailed info for a workflow run including status, tasks, and timestamps +- `get_workflow_run_status` — Get the live status of a workflow run (phase, task progress) +- `get_workflow_run_logs` — Stream live logs for a workflow run (live-only — does not return archived logs for completed runs); optional `task` filter +- `get_workflow_run_events` — Get Kubernetes events for a workflow run (scheduling, pod-startup failures); optional `task` filter +- `list_workflows` † — List all workflow templates in a namespace (CI/CD pipelines executed on the workflow plane) +- `get_workflow` † — Get the full definition of a workflow including its complete spec +- `get_workflow_schema` † — Get the parameter schema for a workflow template + +_Deprecated — use the namespace-scoped tool with `scope: "cluster"` instead; see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools):_ + +- `list_cluster_workflows` — List cluster-scoped workflow definitions shared across namespaces +- `get_cluster_workflow` — Get the full definition of a cluster-scoped workflow +- `get_cluster_workflow_schema` — Get the schema for a cluster-scoped workflow + +
+ +
+Platform Engineering (PE) Toolset + +:::note +The PE toolset is enabled by default. These tools are intended for platform administrators who manage infrastructure, environments, platform standards, and deployment pipelines. If you need to disable the PE toolset, see [Configuring MCP Toolsets](#configuring-mcp-toolsets). +::: + +**Environment Management** + +- `list_environments` † — List all environments in a namespace +- `create_environment` — Create a new environment in a namespace +- `update_environment` — Update an existing environment (display name, description, production flag) +- `delete_environment` — Delete an environment from a namespace + +**Deployment Pipeline Management** + +- `create_deployment_pipeline` — Create a new deployment pipeline defining environment promotion order +- `update_deployment_pipeline` — Update promotion paths and approval requirements +- `delete_deployment_pipeline` — Delete a deployment pipeline from a namespace + +**Component Releases** + +- `list_component_releases` — List all releases (immutable snapshots at a specific build) for a component +- `create_component_release` — Create a new release from the latest build of a component +- `get_component_release` — Get detailed release info including build information, image tags, and deployment status +- `get_component_release_schema` — Get the JSON schema for a component release's configuration options + +**Resource Releases** + +- `list_resource_releases` — List all ResourceReleases (immutable snapshots of `Resource.spec` + `(Cluster)ResourceType.spec`) for a Resource +- `create_resource_release` — Manually cut a ResourceRelease from the current Resource and ResourceType state. Typically not needed in steady state—the Resource controller cuts releases automatically on hash change +- `get_resource_release` — Get the full snapshot including the frozen (Cluster)ResourceType spec and the Resource parameters captured at release time + +**Infrastructure — Namespace-Scoped Planes** + +- `list_dataplanes` — List all data planes (clusters where workloads execute) in a namespace +- `get_dataplane` — Get detailed data plane info including cluster details, capacity, and health +- `list_workflowplanes` — List all workflow planes (dedicated build infrastructure) in a namespace +- `get_workflowplane` — Get detailed workflow plane info including cluster details and health status +- `list_observability_planes` — List all observability planes providing monitoring, logging, and tracing in a namespace +- `get_observability_plane` — Get detailed observability plane info including observer URL and health status + +**Infrastructure — Cluster-Scoped Planes** _(deprecated — use the namespace-scoped tool with `scope: "cluster"`; see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools))_ + +- `list_cluster_dataplanes` — List all cluster-scoped data planes +- `get_cluster_dataplane` — Get detailed info for a cluster-scoped data plane +- `list_cluster_workflowplanes` — List all cluster-scoped workflow planes +- `get_cluster_workflowplane` — Get detailed info for a cluster-scoped workflow plane +- `list_cluster_observability_planes` — List all cluster-scoped observability planes +- `get_cluster_observability_plane` — Get detailed info for a cluster-scoped observability plane + +**Platform Standards — Read, Namespace-Scoped** + +- `list_component_types` † — List available component types in a namespace +- `get_component_type` — Get the full definition of a component type including its complete spec +- `get_component_type_schema` † — Get the parameter schema for a component type +- `list_traits` † — List available traits in a namespace +- `get_trait` — Get the full definition of a trait including its complete spec +- `get_trait_schema` † — Get the parameter schema for a trait +- `list_resource_types` † — List available ResourceTypes in a namespace. Pass `scope: "cluster"` for ClusterResourceTypes +- `get_resource_type` † — Get the full definition of a ResourceType including outputs and resource manifests. Pass `scope: "cluster"` for a ClusterResourceType +- `get_resource_type_schema` † — Get the parameter schema for a ResourceType. Pass `scope: "cluster"` for a ClusterResourceType +- `list_workflows` † — List all workflow templates in a namespace +- `get_workflow` — Get the full definition of a workflow including its complete spec +- `get_workflow_schema` † — Get the parameter schema for a workflow template + +**Platform Standards — Creation Schemas** + +- `get_component_type_creation_schema` — Get the spec schema for creating a component type +- `get_cluster_component_type_creation_schema` _(deprecated — use `get_component_type_creation_schema` with `scope: "cluster"`)_ — Get the spec schema for creating a cluster-scoped component type +- `get_trait_creation_schema` — Get the spec schema for creating a trait +- `get_cluster_trait_creation_schema` _(deprecated — use `get_trait_creation_schema` with `scope: "cluster"`)_ — Get the spec schema for creating a cluster-scoped trait +- `get_resource_type_creation_schema` — Get the spec schema for creating a ResourceType. Pass `scope: "cluster"` for a ClusterResourceType +- `get_workflow_creation_schema` — Get the spec schema for creating a workflow +- `get_cluster_workflow_creation_schema` _(deprecated — use `get_workflow_creation_schema` with `scope: "cluster"`)_ — Get the spec schema for creating a cluster-scoped workflow + +**Platform Standards — Write, Namespace-Scoped** + +- `create_component_type` — Create a new component type in a namespace +- `update_component_type` — Update an existing component type (full replacement) +- `delete_component_type` — Delete a component type from a namespace +- `create_trait` — Create a new trait in a namespace +- `update_trait` — Update an existing trait (full replacement) +- `delete_trait` — Delete a trait from a namespace +- `create_resource_type` — Create a new ResourceType. Pass `scope: "cluster"` to create a ClusterResourceType +- `update_resource_type` — Update an existing ResourceType (full replacement). Pass `scope: "cluster"` for a ClusterResourceType +- `delete_resource_type` — Delete a ResourceType. Pass `scope: "cluster"` to delete a ClusterResourceType +- `create_workflow` — Create a new workflow in a namespace +- `update_workflow` — Update an existing workflow (full replacement) +- `delete_workflow` — Delete a workflow from a namespace + +**Platform Standards — Read, Cluster-Scoped** _(deprecated — use the namespace-scoped tool with `scope: "cluster"`; see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools))_ + +- `list_cluster_component_types` † — List cluster-scoped component types +- `get_cluster_component_type` † — Get the full definition of a cluster-scoped component type +- `get_cluster_component_type_schema` † — Get the schema for a cluster-scoped component type +- `list_cluster_traits` † — List cluster-scoped traits +- `get_cluster_trait` † — Get the full definition of a cluster-scoped trait +- `get_cluster_trait_schema` † — Get the schema for a cluster-scoped trait +- `list_cluster_workflows` † — List cluster-scoped workflow definitions +- `get_cluster_workflow` † — Get the full definition of a cluster-scoped workflow +- `get_cluster_workflow_schema` † — Get the schema for a cluster-scoped workflow + +**Platform Standards — Write, Cluster-Scoped** _(deprecated — use the namespace-scoped tool with `scope: "cluster"`; see [Deprecated cluster-prefixed tools](#deprecated-cluster-prefixed-tools))_ + +- `create_cluster_component_type` — Create a new cluster-scoped component type +- `update_cluster_component_type` — Update an existing cluster-scoped component type (full replacement) +- `delete_cluster_component_type` — Delete a cluster-scoped component type +- `create_cluster_trait` — Create a new cluster-scoped trait +- `update_cluster_trait` — Update an existing cluster-scoped trait (full replacement) +- `delete_cluster_trait` — Delete a cluster-scoped trait +- `create_cluster_workflow` — Create a new cluster-scoped workflow +- `update_cluster_workflow` — Update an existing cluster-scoped workflow (full replacement) +- `delete_cluster_workflow` — Delete a cluster-scoped workflow + +**Authorization — Roles** + +- `list_authz_roles` — List authz roles in a namespace +- `get_authz_role` — Get the full definition of an authz role +- `get_authz_role_creation_schema` — Get the spec schema for creating an authz role +- `create_authz_role` — Create a new authz role +- `update_authz_role` — Update an existing authz role (full replacement) +- `delete_authz_role` — Delete an authz role + +**Authorization — Role Bindings** + +- `list_authz_role_bindings` — List authz role bindings in a namespace +- `get_authz_role_binding` — Get the full definition of an authz role binding +- `get_authz_role_binding_creation_schema` — Get the spec schema for creating an authz role binding +- `create_authz_role_binding` — Create a new authz role binding +- `update_authz_role_binding` — Update an existing authz role binding (full replacement) +- `delete_authz_role_binding` — Delete an authz role binding + +**Secret References** + +- `list_secret_references` ‡ — List all secret references (credentials and sensitive configuration) for a namespace +- `get_secret_reference` ‡ — Get a single secret reference's full spec (template, data sources, refresh interval, target plane). For sync status, query `get_resource_events` against the rendered ExternalSecret on the data plane +- `create_secret_reference` — Create a new secret reference; spec must include `template` (Kubernetes Secret type) and `data[]` (mapping of secret keys to external store references) +- `update_secret_reference` — Update an existing secret reference; annotations are merged, spec is replaced wholesale when provided +- `delete_secret_reference` — Delete a secret reference (the underlying Kubernetes Secret is removed by the controller) + +‡ Also registered on the Namespace toolset so developers can list and inspect secret references without enabling PE. + +**Diagnostics** + +- `get_resource_tree` — Get the rendered resource tree for a release binding +- `get_resource_events` — Get Kubernetes events for a specific resource in a deployment (scheduling, startup issues) +- `get_resource_logs` — Get container logs from a specific pod in a deployment (application errors, runtime issues) +- `evaluate_authz` — Evaluate one or more authz requests and return allow/deny plus the matching binding chain on a deny +- `list_authz_actions` — List the catalog of authz action names and the lowest applicable scope for each + +
+ +### Observability Plane MCP Server + +The Observability Plane MCP server provides tools covering logs, traces, metrics, alerts, and incidents: + +- `query_component_logs` — Query runtime application logs for components (services, APIs, workers, scheduled tasks); filter by project, component, environment, time range, log levels, and search phrases +- `query_workflow_logs` — Query CI/CD workflow run logs capturing build, test, and deployment pipeline execution details; filter by workflow run name and task name +- `query_http_metrics` — Query HTTP request and latency metrics; returns time-series data for request counts (total, successful, unsuccessful) and latency percentiles (p50, p90, p99) +- `query_resource_metrics` — Query CPU and memory resource usage metrics; returns time-series data for usage, requests, and limits — useful for capacity planning and detecting memory leaks +- `query_traces` — Query distributed traces; returns a list of traces with summary information including trace ID, span count, root span details, and duration +- `query_trace_spans` — Query all spans within a specific distributed trace by trace ID; returns span details with timing, parent span, and service information +- `get_span_details` — Get full details for a specific span including attributes, resource attributes, parent span ID, and timing details +- `query_alerts` — Query fired alerts in OpenChoreo; supports filtering by project, component, environment, and time range — useful for investigating recent alerts and their details +- `query_incidents` — Query incidents in OpenChoreo; supports filtering by project, component, environment, and time range — useful for tracking incident lifecycle and response status; all incidents have an accompanying alert but not the other way around + +## Configuring MCP Toolsets + +The Control Plane MCP server exposes seven toolsets: `namespace`, `project`, `component`, `resource`, `deployment`, `build`, and `pe`. All seven are enabled by default. You can control which toolsets are active by passing a JSON array to `openchoreoApi.config.mcp.toolsets` via `helm upgrade`. + +**Syntax:** + + + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set-json 'openchoreoApi.config.mcp.toolsets=["","",...]'`} + + +### Common Configurations + +**Developer toolsets:** + + + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set-json 'openchoreoApi.config.mcp.toolsets=["namespace","project","component","resource","deployment","build"]'`} + + +**Platform Engineer toolset:** + + + {`helm upgrade openchoreo-control-plane ${versions.helmSource}/openchoreo-control-plane \\ + --version ${versions.helmChart} \\ + --namespace openchoreo-control-plane \\ + --reuse-values \\ + --set-json 'openchoreoApi.config.mcp.toolsets=["namespace","project","pe"]'`} + + +:::tip +The `namespace` and `project` toolsets are useful companions for the PE toolset — they let platform engineers discover resources without enabling all developer toolsets. +::: + +## Per-Session Tool Filtering + +By default, the Control Plane MCP server filters `tools/list` and `tools/call` results by the authenticated user's permissions. Tools the user lacks permission for are hidden, and unauthorized calls are rejected. MCP clients can additionally narrow what a session sees, opt out of authorization-based filtering, or opt back into the deprecated cluster-prefixed aliases, by passing optional query parameters when establishing the session. + +| Query Parameter | Required | Default | Description | +| ------------------------ | -------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `toolsets` | `false` | All configured toolsets | Comma-separated list of toolsets to expose via `tools/list` for the session (e.g. `namespace,component,pe`). Unknown toolset names are silently ignored. | +| `filterByAuthz` | `false` | `true` | When `true`, hides tools the user cannot call and rejects unauthorized invocations. Set to `false` to disable MCP-layer authorization filtering. | +| `includeDeprecatedTools` | `false` | `false` (was `true` before v1.2.0) | Controls whether `tools/list` includes the deprecated cluster-prefixed aliases. The aliases remain callable regardless of this flag — it only controls listing. The flag and aliases are both removed in v1.3.0. | + +**Example** (as of v1.2.0 the deprecated aliases are hidden by default; append `includeDeprecatedTools=true` to opt back in): + +``` +http://api.openchoreo.localhost:8080/mcp?toolsets=namespace,component,pe&filterByAuthz=false&includeDeprecatedTools=true +``` + +:::note +These query parameters are HTTP-only and read once when the session is established. The `toolsets` parameter only filters `tools/list` results; it does not gate `tools/call`. The control plane API enforces authorization independently of `filterByAuthz`, so disabling MCP-layer filtering does not grant additional access. It just exposes tools the user cannot successfully invoke. +::: + +:::note Authorization of scope-collapsed tools +A scope-collapsed tool (one that accepts a `scope` argument) requires a distinct permission per scope — one for `scope: "namespace"` and one for `scope: "cluster"`. It appears in `tools/list` as long as the user holds the permission for **at least one** scope; a `tools/call` invocation is then authorized against the permission for the scope actually requested. So a user with only namespace-level permissions still sees the tool, but a call with `scope: "cluster"` is rejected unless they also hold the cluster-level permission. +::: + +## Finding MCP Server URLs + +MCP server URLs follow a simple pattern based on the respective service's hostname: + +- **Control Plane MCP Server**: `/mcp` +- **Observability Plane MCP Server**: `/mcp` + +### Example: Local k3d Setup + +If you followed the [local setup](../getting-started/try-it-out/on-k3d-locally.mdx) guide, your MCP server URLs will be: + +**Single Cluster Installation:** + +- **Control Plane MCP Server**: `http://api.openchoreo.localhost:8080/mcp` +- **Observability Plane MCP Server**: `http://observer.openchoreo.localhost:11080/mcp` + +**Multi-Cluster Installation:** + +- **Control Plane MCP Server**: `http://api.openchoreo.localhost:8080/mcp` +- **Observability Plane MCP Server**: `http://observer.observability.openchoreo.localhost:11087/mcp` + +:::note +The k3d local setup examples show different ports and hostnames: + +- Control plane services use port 8080 +- Observability plane uses port 11080 (single cluster) or 11087 (multi-cluster) +- Multi-cluster deployments use distinct subdomain patterns for namespace isolation + ::: + +## Default OAuth Applications + +OpenChoreo ships with pre-created OAuth applications in the default ThunderID identity provider for quick-start configuration: + +| Application | Client ID | Grant Type | Use Case | +| -------------------------- | -------------------- | ------------------------- | ------------------------------------------------------------------------------------- | +| **Browser-Based (Public)** | `user_mcp_client` | Authorization Code + PKCE | Interactive use with AI agents that support browser-based OAuth (Claude Code, Cursor) | +| **Service (Confidential)** | `service_mcp_client` | Client Credentials | Programmatic access, any AI agent via bearer token | + +These default applications eliminate the need to manually create OAuth apps for common setups. + +## Next Steps + +To configure your AI assistant to connect to OpenChoreo MCP servers, follow the [AI Configuration Guide](../ai/mcp-servers.mdx) to set up authentication and connect your AI agent. diff --git a/versioned_docs/version-v1.2.0-rc.2/releases/release-and-support-process.md b/versioned_docs/version-v1.2.0-rc.2/releases/release-and-support-process.md new file mode 100644 index 00000000..c24f63e8 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/releases/release-and-support-process.md @@ -0,0 +1,54 @@ +--- +title: Release and Support Process +--- + +# Overview + +OpenChoreo uses an open, community-first release model. Version numbers are expressed using the `x.y.z` format, where `x` represents the major version, `y` the minor version, and `z` the patch version, in accordance with [semantic versioning](https://semver.org/) terminology. + +We publish minor releases on a regular basis and maintain community support for the most recent **three** minor release lines. Patch releases are published on a cadence-based schedule for supported release lines, with additional out-of-band patch releases when required for critical issues. + +This page describes release cadence, supported versions, planned future releases, patching policy, maintenance mode, and end-of-life expectations for community-supported versions. + +# Release Status Definitions + +| Status | Meaning | +| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Actively Supported | The release line is eligible for regular patch releases. Applicable fixes may be backported based on severity, risk, and feasibility. | +| Maintenance Mode | The release line is nearing end of life. Patch releases may still be published, but only for a narrow set of issues such as critical security vulnerabilities, dependency or base-image updates, and critical core issues. | +| End of Life (EOL) | The release line is no longer supported. No further patch releases are planned. Users should upgrade to a newer supported minor release. | + +# Release Cadence + +OpenChoreo aims to publish new minor releases as and when needed during the early phase of the project. Release cadence will be more regular once the project enters the mature phase. Once a new minor release becomes generally available, community support continues for the latest three minor release lines. + +This "latest three minors" rule is the controlling rule for community support. When a new minor release is published, the oldest previously supported minor release line exits active support and moves to end-of-life according to the published schedule. The project will keep the EOL dates updated well in advance with future release planning. + +# Supported Minor Releases + +Community support is provided for the latest three minor release lines. Publish exact dates for each supported line so users can plan upgrades confidently. + +| Minor release | GA date | Latest patch | Status | Maintenance mode starts | End of life | +| :------------ | :---------- | :----------- | :----------------- | :---------------------- | :---------- | +| v1.1 | 2026-May-18 | v1.1.3 | Actively Supported | TBD | TBD | +| v1.0 | 2026-Mar-23 | v1.0.3 | Actively Supported | TBD | TBD | + +# Planned Future Minor Releases + +Planned dates are targets and may move based on release readiness. Any date changes should be reflected on this page and in release announcements. + +| Upcoming release | Target release date | Status | +| :--------------- | :------------------ | :---------- | +| v1.2 | 2026-July | In Progress | + +# Patch Releases + +Patch releases are intended to deliver targeted important bug fixes, including security fixes, for supported release lines. + +Patch releases are normally published on a **monthly** cadence. The earliest patch releases after a new minor release may happen faster. Additional out-of-band patch pre-releases (postfixed with `-hotfix.n`) may be published when required to address critical issues. Support for these pre-releases will end once the next patch release is released. + +Patch release timing may also be adjusted around major holiday periods, release readiness concerns, or urgent security needs. + +# Upgrade Guidance + +Users are encouraged to stay current with supported minor releases and to adopt the latest available patch release on their chosen supported minor line. To reduce upgrade risk, users should upgrade to the latest patch release of their current minor version before moving to the next minor version. diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/ai-overview-diagram.svg b/versioned_docs/version-v1.2.0-rc.2/resources/ai-overview-diagram.svg new file mode 100644 index 00000000..9064f042 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/ai-overview-diagram.svg @@ -0,0 +1,2 @@ +Control PlaneProvides access to a unifiedplatform context that spansdata and workflow planes -with access controlProvides access to unified logs,metrics, alerts and telemetry datawith access controlSRE/RCA AgentFinOps AgentArchitect AgentExternal Agents + SkillscollaboratesOpenChoreo CLI (occ)Built-in Platform AgentsMCPServerComing soonComing soonObservability Plane(s)MCPServer(OpenAPI)API(OpenAPI)(OpenAPI)API(OpenAPI)Data Plane(s)Workflow Plane(s) \ No newline at end of file diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/cell-runtime-with-portal-screenshot.png b/versioned_docs/version-v1.2.0-rc.2/resources/cell-runtime-with-portal-screenshot.png new file mode 100644 index 00000000..df7c0a6b Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/resources/cell-runtime-with-portal-screenshot.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/developer-api-overview.svg b/versioned_docs/version-v1.2.0-rc.2/resources/developer-api-overview.svg new file mode 100644 index 00000000..8790b025 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/developer-api-overview.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-architecture-components.svg b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-architecture-components.svg new file mode 100644 index 00000000..9aa428f3 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-architecture-components.svg @@ -0,0 +1,2025 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CLI + + + + + + + API + + + + + + + MCP + + + + + + + + + + + Data Plane(s) + + + + + + + Workflow Plane(s) + + + + + + + + + + + + + + + + + + + + + + + + + + + Control Plane + + + OpenChoreo + + + + + + + + + + + + + + Workflow Module + + + Observability Plane(s) + + + + + + A + + + Argo + Workflows + + + + + + + + + + + External CI Plugins + (Community) + + + + + + + + + GH Actions + Plugin + + + Jenkins + Plugin + + + + + + + OpenChoreo System Components + + + + + + + OpenChoreo System Components + + + + + + + + + + + API Gateway Modules + + + + + + + + + API Platform + + + + + + + + + + + + + + Elastic Module + + + + + + Scale to + Zero + + + + + + Isolated projects and environments for + workloads with ingress/egress controls + + + + + + + + + + + Guard Modules + + + + + + + + + + + + + + + Kubewarden + + + + + + + + + + + + + + + Observer API + + + + + + + Logging Modules + + + + + + + + + + + + + + + Metrics Module + + + + + + + Telemetry Module + + + + + + + Alert Module + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GitOps Module + + + + + + + + + + + + + + Authentication + + + Pluggable OAuth2/OIDC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Any OCI Container + Registry + + + Any ESO Compatible + Secret Store/Key Vault + + + + + + Secret management for + workflow and data planes + + + OR + + + + + + + Observer MCP + + + OpenChoreo System + Components + + + + + + + + + Cloud Native + Buildpacks + + + + + + + + + + + + + + + + + + + OTel Collector + + + + + + + + + + + AI Agent Modules + + + + + + + + + + + + + SRE Agent + + + + + + + + + + + + + FinOps Agent + + + + + + + + + + + + + Architect Agent + + + + + + + + + + Authorization & Access Control + + + OpenChoreo System + Components + + + + + + + + + + + + + OpenChoreo       Controllers + + + + + + + + + Any Git + Provider + + + + + + + + + + + + + + + + + + + + + + + + workflow + observability + + + runtime + observability + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wss + + + + + + + + wss + + + + + + + + wss,https + + + Platform and + application state + + + + + + Experience Plane + + + + + + + OpenChoreo API Server + + + + + + + + + UI + + + + + + + + + + + + + + + + + + Platform + Teams + + + Development + Teams + + + + + + + + + + + Planes, Namespaces, Authorization + Policies, Environments, Deployment + Pipelines, Workflows, Component Types, + Traits, ...and more + + + Platform API + + + Projects, Components, WorkflowRuns + + + Developer API + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-cell-runtime-view.png b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-cell-runtime-view.png new file mode 100644 index 00000000..917dc41a Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-cell-runtime-view.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-development-abstractions.png b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-development-abstractions.png new file mode 100644 index 00000000..ece20326 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-development-abstractions.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-diagram-v1-with-borders.png b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-diagram-v1-with-borders.png new file mode 100644 index 00000000..0c146bbb Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-diagram-v1-with-borders.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-platform-abstractions.png b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-platform-abstractions.png new file mode 100644 index 00000000..148268a0 Binary files /dev/null and b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo-platform-abstractions.png differ diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo_components.svg b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo_components.svg new file mode 100644 index 00000000..c5ae2aef --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/openchoreo_components.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/platform-topology-overview.svg b/versioned_docs/version-v1.2.0-rc.2/resources/platform-topology-overview.svg new file mode 100644 index 00000000..69b0e805 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/platform-topology-overview.svg @@ -0,0 +1,744 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/release-transformation-diagram.svg b/versioned_docs/version-v1.2.0-rc.2/resources/release-transformation-diagram.svg new file mode 100644 index 00000000..9808ae07 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/release-transformation-diagram.svg @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/what-are-openchoreo-planes.svg b/versioned_docs/version-v1.2.0-rc.2/resources/what-are-openchoreo-planes.svg new file mode 100644 index 00000000..9a43aa85 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/what-are-openchoreo-planes.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Control Plane + + + OpenChoreo + + + The central "Brain" of + the platform. + + Orchestrates other + planes based on + intent as declared in + APIs. + + + + + + + CLI + + + + + + + API + + + + + + + MCP + + + + + + + UI + + + + + + + Data Plane(s) + + + OpenChoreo + + + Runs application workloads. + + Logical environments, project & + tenant isolation, gateway topologies + and runtime/network security. + + + + + + + Workflow Plane(s) + + + OpenChoreo + + + + + + + Observability Plane(s) + + + OpenChoreo + + + Runs builds and CI workflows. + + Also runs general-purpose + automation workflows (eg. IaC). + + + Ingests and provides APIs for + distributed logs, metrics, traces + and alerts. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pushes + runtime + observability + data + + + Pushes + workflow + observability + data + + + orchestrates + + + + + + + + + The experience plane + + + + + + + + + + + + + + + + Modules + for tool + integrations + + + + + + Modules + for tool + integrations + + + + + + Modules + for tool + integrations + + diff --git a/versioned_docs/version-v1.2.0-rc.2/resources/what-is-openchoreo-overview.svg b/versioned_docs/version-v1.2.0-rc.2/resources/what-is-openchoreo-overview.svg new file mode 100644 index 00000000..c00a1ef9 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/resources/what-is-openchoreo-overview.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-v1.2.0-rc.2/tutorials/build-and-deploy-private.mdx b/versioned_docs/version-v1.2.0-rc.2/tutorials/build-and-deploy-private.mdx new file mode 100644 index 00000000..07a916d4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/tutorials/build-and-deploy-private.mdx @@ -0,0 +1,457 @@ +--- +title: Build from a Private Repository and Deploy via a Private Registry +description: Pull source code from a private Git repository, build and push the image to a private container registry, then deploy from that registry using OpenChoreo. +sidebar_position: 10 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Build from a Private Repository and Deploy via a Private Registry + +## Overview + +This tutorial covers a fully private end-to-end pipeline: your source code lives in a private Git repository, the container image is built inside OpenChoreo's Workflow Plane, pushed to a private container registry, and then pulled and deployed on the Data Plane. + +Each stage of the pipeline requires its own credentials: + +| Stage | Credential Required | +| -------------------------------- | --------------------------------------------- | +| Clone private Git repo | Git personal access token (PAT) | +| Push image to private registry | Registry push credentials | +| Pull image from private registry | Registry pull credentials (image pull secret) | + +This tutorial uses **GitHub** as the Git host and **Docker Hub** as the container registry. + +## Prerequisites + +Before you begin, ensure you have: + +- **OpenChoreo installed** in your Kubernetes cluster +- **kubectl** configured to access your cluster +- **A private GitHub repository** containing your application source code. +- **A private Docker Hub repository** to push and pull your built image +- **A Docker Hub personal access token** (or password) for both push (Workflow Plane) and pull (Data Plane) +- **A GitHub personal access token** with at least `repo` read access +- **External secret store** accessible from the Workflow Plane and Data Plane (each plane may have its own store, or they may share one — e.g., OpenBao for local dev, or Vault/AWS Secrets Manager for production) + +--- + +## Step 1 — Store Git Credentials + +Store your Git credentials in your secret backend so the Workflow Plane can clone the private repository. + +:::note +This example uses OpenBao, the default secret store in a local OpenChoreo development setup. For production, see [Secret Management](../platform-engineer-guide/secret-management.mdx). +::: + +Store a username and personal access token (PAT) under the key `secret/git/github-token`: + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/git/github-token \ + username="your-github-username" \ + token="your-personal-access-token" +' +``` + +Replace `your-github-username` and `your-personal-access-token` with your actual Git credentials. The token must have at least **read** access to the repository. + +--- + +## Step 2 — Create a SecretReference for the Git Repository + +Create a `SecretReference` custom resource that syncs your Git credentials from the secret store into the Workflow Plane namespace. + +```bash +kubectl apply -f - <\":{\"auth\":\"\"}}}" +' +``` + +Replace: + +- `` — your registry host (e.g., `https://index.docker.io/v1/` for Docker Hub, `ghcr.io` for GHCR) +- `` — the base64 string from the previous step + +**Example for Docker Hub:** + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/registry-push-secret \ + value="{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"ZGVtby11c2VyOmRlbW8tcGFzcw==\"}}}" +' +``` + +--- + +--- + +## Step 4 — Configure the Publish Step to Use Your Private Registry + +:::note Platform Engineer Setup +This step is a **one-time platform-level configuration** performed by a cluster admin. You do not need to repeat this for every application. +::: + +Replace the default `publish-image` ClusterWorkflowTemplate with one pointing to your private registry endpoint. Before applying, determine your `REGISTRY_ENDPOINT` value: + +| Registry | REGISTRY_ENDPOINT | +| ------------------------- | ------------------------------------------------------------- | +| Docker Hub | `docker.io/your-username` | +| Amazon ECR | `123456789.dkr.ecr.us-east-1.amazonaws.com/openchoreo-builds` | +| Google Artifact Registry | `us-central1-docker.pkg.dev/my-project/openchoreo-builds` | +| Azure Container Registry | `myregistry.azurecr.io` | +| GitHub Container Registry | `ghcr.io/my-org/openchoreo` | + +Then apply, replacing `your-registry-host/your-repo-path` with your value from the table above: + +```bash +kubectl apply -f - < /etc/containers/storage.conf + [storage] + driver = "overlay" + runroot = "/run/containers/storage" + graphroot = "/var/lib/containers/storage" + [storage.options.overlay] + mount_program = "/usr/bin/fuse-overlayfs" + CONF + + podman load -i /mnt/vol/app-image.tar + podman tag \$SRC_IMAGE \$REGISTRY_ENDPOINT/\$SRC_IMAGE + + if [ -f "\$AUTH_FILE" ]; then + podman push --tls-verify=true --authfile "\$AUTH_FILE" \$REGISTRY_ENDPOINT/\$SRC_IMAGE + else + podman push --tls-verify=true \$REGISTRY_ENDPOINT/\$SRC_IMAGE + fi + + echo -n "\$REGISTRY_ENDPOINT/\$SRC_IMAGE" > /tmp/image.txt + securityContext: + privileged: true + volumeMounts: + - mountPath: /mnt/vol + name: workspace + - mountPath: /etc/secrets/registry-push-secret + name: registry-push-secret + readOnly: true +EOF +``` + +--- + +## Step 5 — Store Registry Pull Credentials + +The Data Plane also needs credentials to **pull** the image from your private registry. Store them in OpenBao with the key `registry-credentials`: + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/registry-credentials \ + value="{\"auths\":{\"\":{\"auth\":\"\"}}}" +' +``` + +:::note +If your push and pull credentials are the same (e.g., same Docker Hub account), you can reuse the same base64 token. The separate keys (`registry-push-secret` and `registry-credentials`) exist because push credentials are used by the Workflow Plane and pull credentials are used by the Data Plane, which may be separate clusters. +::: + +--- + +## Step 6 — Configure Your ClusterComponentType to Pull from the Private Registry + +:::note Platform Engineer Setup +This is another **one-time platform-level change** performed by a cluster admin. Once configured, all components using this ClusterComponentType will automatically get the image pull secret injected — no per-component changes are needed. +::: + +Edit the `deployment/service` ClusterComponentType (or your custom type) to add two pieces: + +**1. An ExternalSecret** that syncs pull credentials into the workload namespace: + +```yaml +- id: registry-pull-secret + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: registry-pull-secret + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: registry-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + - secretKey: .dockerconfigjson + remoteRef: + key: registry-credentials + property: value +``` + +**2. `imagePullSecrets`** in the Deployment template so pods can authenticate when pulling: + +```yaml +- id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + template: + spec: + imagePullSecrets: + - name: registry-pull-secret + containers: + - name: main + image: ${workload.container.image} + # ... rest of container config +``` + +For the full ClusterComponentType configuration, see [Deploy from a Private Registry](./deploy-prebuilt-image.mdx#deploy-from-a-private-registry). + +--- + +## Step 7 — Create the Component + +Create the Component that points to your private Git repository: + +```bash +kubectl apply -f - < with the actual pod name) +kubectl logs -n workflows-default -f +``` + +The WorkflowRun goes through these stages: + +| Condition | Description | +| ------------------- | ------------------------------------------------- | +| `WorkflowRunning` | Argo Workflow is executing (clone → build → push) | +| `WorkflowSucceeded` | Image pushed to registry; Workload CR created | +| `WorkflowFailed` | Check step logs in the Workflow Plane | + +Wait for both `WorkflowCompleted: True` and `WorkflowSucceeded: True` before proceeding. + +--- + +## Step 9 — Verify the Deployment + +Once the WorkflowRun succeeds, OpenChoreo automatically creates a Workload CR with the pushed image reference and deploys it on the Data Plane. + +Check the component and workload: + +```bash +kubectl get component private-go-service +kubectl get workload -A | grep private-go-service +``` + +Check that pods are running: + +```bash +kubectl get pods -A | grep private-go-service +``` + +If pods are in `ImagePullBackOff`, verify that the pull secret is synced correctly: + +```bash +kubectl get externalsecret -A | grep registry-pull-secret +kubectl describe externalsecret registry-pull-secret -n +``` + +### Test Your Application + +Once the deployment is ready, test the service: + +```bash +curl http://development-default.openchoreoapis.localhost:19080/private-go-service-greeter-api/greeter/greet + +# Expected response: Hello, Stranger! +``` + +--- + +## Troubleshooting + +| Symptom | Likely Cause | Fix | +| ------------------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------- | +| WorkflowRun stuck in `Running` with `clone` step failing | Invalid Git credentials or secret not found | Check `SecretReference` status and verify credentials in secret store | +| WorkflowRun fails at `publish-image` step with "unauthorized" | Push credentials missing or wrong registry host | Re-verify `registry-push-secret` in OpenBao and the `REGISTRY_ENDPOINT` in the CWT | +| Pod in `ImagePullBackOff` after successful build | Pull secret not configured or synced | Verify `ExternalSecret` status and `imagePullSecrets` in ClusterComponentType | +| "x509: certificate signed by unknown authority" | Self-signed registry TLS cert | Set `--tls-verify=false` in the CWT or configure the CA cert | + +--- + +## Summary + +You have set up a fully private end-to-end pipeline in OpenChoreo: + +- Source code is cloned from a private Git repository using a `SecretReference` +- The image is built in the Workflow Plane and pushed to a private registry using a push secret +- The Data Plane pulls the image using an `ExternalSecret`-backed image pull secret and deploys it + +## Next Steps + +- [Set up Secret Management](../platform-engineer-guide/secret-management.mdx) for production-grade secret backends and automatic rotation +- [Container Registry Configuration](../platform-engineer-guide/container-registry-configuration.mdx) — Configure push credentials and registry providers in detail +- [Private Git Repositories](../developer-guide/workflows/ci/private-repository.md) — More on Git authentication methods (SSH, basic auth) +- [Workload Generation](../platform-engineer-guide/workflows/workload-generation.md) — How build outputs automatically become Workload CRs diff --git a/versioned_docs/version-v1.2.0-rc.2/tutorials/component-alerts-and-incidents.mdx b/versioned_docs/version-v1.2.0-rc.2/tutorials/component-alerts-and-incidents.mdx new file mode 100644 index 00000000..db43535a --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/tutorials/component-alerts-and-incidents.mdx @@ -0,0 +1,735 @@ +--- +title: Configure Component Alerts and Manage Incidents +description: Attach observability alert rules to components, configure email and webhook notifications, and test incident creation with controlled failure scenarios. +sidebar_position: 15 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Configure Component Alerts and Manage Incidents + +This tutorial shows how to monitor OpenChoreo components using Observability Alert Rules, route alert notifications to **email** and **webhooks**, and enable **incident creation** (including AI-powered root cause analysis), as well as **incident management**. + +To make testing easy, this tutorial includes **controlled failure scenarios** that deliberately misconfigure components to trigger alerts on demand. + +## Overview + +OpenChoreo’s component alert architecture follows a role-based workflow: + +- **Platform Engineers (one-time setup)** + - Deploy a trait/clustertrait to create `ObservabilityAlertRule` resources when attached to a component (OpenChoreo ships a default clustertrait named `observability-alert-rule`) + - Configure `ObservabilityAlertsNotificationChannel`s (email/webhook, per environment) +- **Developers (once per component)** + - Attach `observability-alert-rule` trait instances to components as needed + - The same alert rules then propagate as components are promoted across environments +- **Platform Engineers (per environment tuning)** + - Use `traitEnvironmentConfigs` in the `ReleaseBinding` CR to enable/disable alerts, select notification channels, and toggle incident creation and AI Root Cause Analysis + +## Prerequisites + +Before you begin, ensure you have: + +- A running OpenChoreo **control plane**, **data plane**, and **observability plane** +- `kubectl` configured to talk to the cluster where OpenChoreo is installed + +## Platform Engineer Workflow + +### Step 1: Deploy the Alert Rule Trait (One-Time Setup) + +OpenChoreo ships a default clustertrait named `observability-alert-rule` that exposes all the parameters from the ObservabilityAlertRule CR as either `parameters` or `environmentConfigs`. +Platform Engineers can create specialized traits and clustertraits to expose specific parameters from ObservabilityAlertRule CRs to developers. +For example: `observability-log-alert-rule`, `observability-metric-alert-rule`, `observability-incident-rule`, etc. + +If the default `observability-alert-rule` clustertrait is already installed in your cluster, you can skip this step. + +```bash +kubectl apply -f - <<'EOF' +--- +# Trait for Alert Rules +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: observability-alert-rule +spec: + parameters: + openAPIV3Schema: + type: object + properties: + description: + type: string + description: "A human-readable description of what this alert rule monitors and when it triggers." + severity: + type: string + enum: + - info + - warning + - critical + default: warning + description: "The severity level of alerts triggered by this rule. Determines alert priority and notification urgency." + source: + type: object + properties: + type: + type: string + enum: + - log + - metric + - budget + description: "The data source type for the alert rule." + query: + type: string + default: "" + description: "The query expression for log-based alerts. Required when source type is 'log'." + metric: + type: string + default: "" + description: "The predefined metric to monitor for metric-based alerts. Must be one of: cpu_usage, memory_usage. Required when source type is 'metric'." + required: + - type + condition: + type: object + properties: + window: + type: string + default: "5m" + description: "The time window over which data is aggregated before evaluating the alert condition (e.g. 5m, 10m, 30m, 1h)." + interval: + type: string + default: "1m" + description: "The frequency at which the alert rule is evaluated (e.g. 1m, 5m, 15m, 30m)." + operator: + type: string + enum: + - gt + - lt + - gte + - lte + - eq + default: gt + description: "The comparison operator used to evaluate the condition against the threshold (gt: greater than, lt: less than, gte: greater than or equal, lte: less than or equal, eq: equal)." + threshold: + type: integer + default: 10 + description: "The numeric threshold value used with the operator to determine when the alert triggers." + required: + - description + - source + - condition + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + enabled: + type: boolean + default: true + description: "Controls whether this alert rule is active. When disabled, the rule will not trigger alerts." + actions: + type: object + properties: + notifications: + type: object + properties: + channels: + type: array + items: + type: string + default: [] + description: "The notification channel identifiers where alerts should be delivered. Configured per environment by platform engineers. If not provided, defaults to the environment's default notification channel." + incident: + type: object + properties: + enabled: + type: boolean + default: false + description: "Enables incident creation when this alert fires. When enabled, a corresponding incident will be created in the incident management system." + triggerAiCostAnalysis: + type: boolean + default: false + description: "Enables AI-powered cost analysis when an incident is created for a budget alert. Provides automated cost breakdown and optimization recommendations. Requires incident.enabled to also be true and is only valid for budget source type." + triggerAiRca: + type: boolean + default: false + description: "Enables AI-powered root cause analysis when an incident is created. When enabled, provides automated reports of root causes for alert conditions. Requires incident.enabled to also be true." + + validations: + - rule: "${(has(environmentConfigs.actions) && has(environmentConfigs.actions.notifications) && environmentConfigs.actions.notifications.channels.size() > 0) || (has(environment.defaultNotificationChannel) && environment.defaultNotificationChannel != '')}" + message: "A notification channel is mandatory for alert rules (incident-only rules are not supported). Provide environmentConfigs.actions.notifications.channels or set environment.defaultNotificationChannel." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiRca == false || environmentConfigs.actions.incident.enabled == true}" + message: "incident.enabled must be true when triggerAiRca is true. AI-powered root cause analysis requires incident creation to be enabled." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiCostAnalysis == false || environmentConfigs.actions.incident.enabled == true}" + message: "incident.enabled must be true when triggerAiCostAnalysis is true. AI-powered cost analysis requires incident creation to be enabled." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiCostAnalysis == false || parameters.source.type == 'budget'}" + message: "triggerAiCostAnalysis can only be enabled for budget source type alerts." + + creates: + - targetPlane: observabilityplane + includeWhen: ${has(dataplane.observabilityPlaneRef)} + template: + apiVersion: openchoreo.dev/v1alpha1 + kind: ObservabilityAlertRule + metadata: + name: ${metadata.name}-${trait.instanceName} + namespace: ${metadata.namespace} + labels: + # Required for observability backends. Automatically populated by the controller. + openchoreo.dev/component-uid: ${metadata.componentUID} + openchoreo.dev/project-uid: ${metadata.projectUID} + openchoreo.dev/environment-uid: ${metadata.environmentUID} + spec: + name: ${trait.instanceName} + description: ${parameters.description} + severity: ${parameters.severity} + enabled: ${environmentConfigs.enabled} + source: + type: ${parameters.source.type} + query: ${parameters.source.query} + metric: ${parameters.source.metric} + condition: + window: ${parameters.condition.window} + interval: ${parameters.condition.interval} + operator: ${parameters.condition.operator} + threshold: ${parameters.condition.threshold} + actions: + notifications: + channels: >- + ${(has(environmentConfigs.actions) && has(environmentConfigs.actions.notifications) && environmentConfigs.actions.notifications.channels.size() > 0) + ? environmentConfigs.actions.notifications.channels + : [environment.defaultNotificationChannel]} + incident: + enabled: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && (environmentConfigs.actions.incident.enabled || environmentConfigs.actions.incident.triggerAiRca || environmentConfigs.actions.incident.triggerAiCostAnalysis)} + triggerAiCostAnalysis: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && environmentConfigs.actions.incident.enabled && environmentConfigs.actions.incident.triggerAiCostAnalysis} + triggerAiRca: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && environmentConfigs.actions.incident.enabled && environmentConfigs.actions.incident.triggerAiRca} +EOF + +kubectl get clustertrait observability-alert-rule +``` + +### Step 2: Configure Notification Channels (One-Time Setup per Environment) + +Platform Engineers can configure one or more notification channels per environment (email/webhook), then reference them across all alert rules in that environment. +The first notification channel created in an environment is marked as that environment’s **default** notification channel (used when an alert doesn’t explicitly select channels). + +#### Email Notification Channel Example + +If your organization uses SMTP email for notifications, you can create an email notification channel by applying the following YAML replacing the placeholder values with your own. +Otherwise, you can skip this step and use a webhook notification channel instead. + +```bash +kubectl apply -f - <<'EOF' +--- +# Example email Notification Channel for development environment +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: email-notification-channel-development + namespace: default +spec: + environment: development + type: email + emailConfig: + from: notifications@openchoreo.dev # Replace with your SMTP sender email address + to: + - openchoreo-devops-group@acme.com # Replace with your recipients' email addresses + smtp: + host: mail.acme.com # Replace with your SMTP host + port: 587 # Replace with your SMTP port + auth: + username: + secretKeyRef: + name: email-notification-channel-development-smtp-auth + key: username + password: + secretKeyRef: + name: email-notification-channel-development-smtp-auth + key: password + tls: + insecureSkipVerify: true + template: + # Modify as needed with CEL expressions + subject: "OpenChoreo Observability Alert Notification - ${alertName}" + body: | + Alert triggered for your OpenChoreo observability alert rule: ${alertName} + Triggered at: ${alertTimestamp} UTC + Severity: ${alertSeverity} + Description: ${alertDescription} + Value: ${alertValue} + Threshold: ${alertThreshold} + Type: ${alertType} + Component: ${component} + Project: ${project} + Environment: ${environment} + Enabled AI Root Cause Analysis: ${triggerAiRca} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: email-notification-channel-development-smtp-auth + namespace: default +type: Opaque +stringData: + username: smtp-username # Replace with your SMTP username + password: smtp-password # Replace with your SMTP password +EOF +``` + +#### Webhook Notification Channel Example + +You can integrate OpenChoreo's observability alerts with your existing notification systems (such as Slack, Google Chat, etc.) by using a webhook notification channel. +For testing purposes, you can obtain a temporary webhook URL from [webhook.site](https://webhook.site/) and configure a webhook notification channel as follows: + +```bash +kubectl apply -f - <<'EOF' +--- +# Example webhook Notification Channel for development environment +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: webhook-notification-channel-development + namespace: default +spec: + environment: development + type: webhook + webhookConfig: + url: https://webhook.acme.com # Replace with your webhook URL + headers: + Content-Type: + value: "application/json" + # Custom header for webhook authentication (if required) + X-API-Key: + valueFrom: + secretKeyRef: + name: webhook-notification-channel-development-webhook-auth + key: api-key + # Optional: Payload template using CEL expressions (${...}) + # If not provided, the raw alertDetails object will be sent as JSON + # For Slack, use the template below. For other webhooks, customize as needed. + payloadTemplate: | + { + "text": "Alert: ${alertName}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "🚨 OpenChoreo Alert: ${alertName}" + } + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Severity:*\n${alertSeverity}" + }, + { + "type": "mrkdwn", + "text": "*Value:*\n${alertValue}" + }, + { + "type": "mrkdwn", + "text": "*Threshold:*\n${alertThreshold}" + }, + { + "type": "mrkdwn", + "text": "*Component:*\n${component}" + } + ] + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*Description:*\n${alertDescription}" + } + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "Project: ${project} | Environment: ${environment} | Time: ${alertTimestamp}" + } + ] + } + ] + } + +--- +apiVersion: v1 +kind: Secret +metadata: + name: webhook-notification-channel-development-webhook-auth + namespace: default +type: Opaque +stringData: + api-key: webhook-api-key # Replace with your webhook API key (optional) +EOF +``` + +Note: The payload in the notifications can be customized using CEL expressions. Refer to [ObservabilityAlertsNotificationChannel](../reference/api/platform/observabilityalertsnotificationchannel.md) for details on CEL expressions and variables available in payload templates. + +## Developer Workflow + +### Step 3: Deploy the gcp-microservices-demo Sample + +This tutorial is based on the gcp-microservices-demo sample. +Deploy the sample using the following commands if you haven't already: + + +{` +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/gcp-microservice-demo-project.yaml + +# Provision the Redis cache, then promote the binding to the latest release. + +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/resources/redis.yaml +until release=$(kubectl get resource redis -n default -o jsonpath='{.status.latestRelease.name}') && [ -n "$release" ]; do sleep 2; done +kubectl patch resourcereleasebinding redis-development -n default --type=merge -p "{\\"spec\\":{\\"resourceRelease\\":\\"$release\\"}}" + +kubectl apply \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/ad-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/cart-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/checkout-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/currency-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/email-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/frontend-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/payment-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/productcatalog-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/recommendation-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/shipping-component.yaml +`} + + + +### Step 4: Define Alert Rules for Components + +Developers attach alert rules as traits to components once. Those alert rules automatically propagate to all environments as the component is promoted. + +Apply this step to create alert-rule trait instances for: + +- `frontend` component (log-based alert) + - Trigger: when logs from the frontend component contain `rpc error: code = Unavailable` more than 5 times within 5 minutes + - Trait instance name: `frontend-rpc-unavailable-error-log-alert` +- `recommendation` component (metric-based alert) + - Trigger: CPU usage of the recommendation component exceeds 80% for 5 minutes + - Trait instance name: `recommendation-high-cpu-alert` +- `cart` component (metric-based alert) + - Trigger: memory usage of the cart component exceeds 70% for 2 minutes + - Trait instance name: `cartservice-high-memory-alert` + +:::tip +To configure a **budget-based** alert (and have the **FinOps Agent** generate an AI cost analysis report when it fires), see [Configure Budget Alert and Perform Cost Analysis using FinOps Agent](./configure-budget-alert-and-cost-analysis.mdx). +::: + +Attach the alert-rule traits to existing components by appending them to spec.traits if the field already exists, +or creating the array if it does not: + +```bash +# frontend component: log-based alert +if kubectl get component frontend -n default \ + -o jsonpath='{.spec.traits[*].instanceName}' 2>/dev/null \ + | tr ' ' '\n' | grep -qx "frontend-rpc-unavailable-error-log-alert"; then + echo "Trait 'frontend-rpc-unavailable-error-log-alert' already exists on component 'frontend', skipping." +else + kubectl patch component frontend -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits/-", + "value": { + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "frontend-rpc-unavailable-error-log-alert", + "parameters": { + "description": "Alert when frontend logs indicate rpc error: code = Unavailable", + "severity": "critical", + "source": { "type": "log", "query": "rpc error: code = Unavailable" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 5 } + } + } + } + ]' 2>/dev/null || kubectl patch component frontend -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits", + "value": [{ + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "frontend-rpc-unavailable-error-log-alert", + "parameters": { + "description": "Alert when frontend logs indicate rpc error: code = Unavailable", + "severity": "critical", + "source": { "type": "log", "query": "rpc error: code = Unavailable" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 5 } + } + }] + } + ]' +fi + +# recommendation component: metric-based alert (cpu_usage) +if kubectl get component recommendation -n default \ + -o jsonpath='{.spec.traits[*].instanceName}' 2>/dev/null \ + | tr ' ' '\n' | grep -qx "recommendation-high-cpu-alert"; then + echo "Trait 'recommendation-high-cpu-alert' already exists on component 'recommendation', skipping." +else + kubectl patch component recommendation -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits/-", + "value": { + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "recommendation-high-cpu-alert", + "parameters": { + "description": "Alert when recommendationservice CPU usage is greater than 80% for last 5 minutes", + "severity": "critical", + "source": { "type": "metric", "metric": "cpu_usage" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 80 } + } + } + } + ]' 2>/dev/null || kubectl patch component recommendation -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits", + "value": [{ + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "recommendation-high-cpu-alert", + "parameters": { + "description": "Alert when recommendationservice CPU usage is greater than 80% for last 5 minutes", + "severity": "critical", + "source": { "type": "metric", "metric": "cpu_usage" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 80 } + } + }] + } + ]' +fi + +# cart component: metric-based alert (memory_usage) +if kubectl get component cart -n default \ + -o jsonpath='{.spec.traits[*].instanceName}' 2>/dev/null \ + | tr ' ' '\n' | grep -qx "cartservice-high-memory-alert"; then + echo "Trait 'cartservice-high-memory-alert' already exists on component 'cart', skipping." +else + kubectl patch component cart -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits/-", + "value": { + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "cartservice-high-memory-alert", + "parameters": { + "description": "Alert when cartservice memory usage is greater than 70% for last 2 minutes", + "severity": "critical", + "source": { "type": "metric", "metric": "memory_usage" }, + "condition": { "window": "2m", "interval": "1m", "operator": "gt", "threshold": 70 } + } + } + } + ]' 2>/dev/null || kubectl patch component cart -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits", + "value": [{ + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "cartservice-high-memory-alert", + "parameters": { + "description": "Alert when cartservice memory usage is greater than 70% for last 2 minutes", + "severity": "critical", + "source": { "type": "metric", "metric": "memory_usage" }, + "condition": { "window": "2m", "interval": "1m", "operator": "gt", "threshold": 70 } + } + }] + } + ]' +fi + +``` + +#### Notification Channels Are Configured Per Environment + +The trait instances above define **what** to alert on, but they don’t define notification channels. + +Instead, Platform Engineers configure channels per environment using `traitEnvironmentConfigs` in the `ReleaseBinding` CR (next step). +If `traitEnvironmentConfigs` don’t specify channels for a given alert rule, the environment’s default notification channel is used. + +Without a notification channel, the ReleaseBinding will fail to apply the alert rule to the Observability Plane. + +## Testing and Verification + +### Step 5: Configure Failure Scenarios for Testing + +This step creates `ReleaseBinding`s that: + +- Deliberately misconfigure the system in the `development` environment to trigger alerts: + - `frontend` component: overrides `PRODUCT_CATALOG_SERVICE_ADDR` to an invalid endpoint + - `recommendation` component: reduces CPU requests/limits to make high CPU easier to hit + - `cart` component: reduces memory requests/limits to make high memory easier to hit +- Configure alert behavior for the `development` environment via `traitEnvironmentConfigs`: + - Enable/disable alert rules + - Select notification channels + - Toggle incident creation + - Toggle AI root cause analysis + +Apply the failure scenario setup: + +```bash +kubectl apply -f - <<'EOF' +--- +# ReleaseBinding for frontend component with env variable misconfiguration +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: frontend-development + namespace: default +spec: + owner: + projectName: gcp-microservice-demo + componentName: frontend + environment: development + workloadOverrides: + container: + env: + - key: PRODUCT_CATALOG_SERVICE_ADDR + value: "http://localhost:8080" + traitEnvironmentConfigs: + frontend-rpc-unavailable-error-log-alert: + enabled: true + actions: + notifications: + channels: + - "email-notification-channel-development" # Use "webhook-notification-channel-development" if you skipped the email setup and only configured webhook channels + incident: + enabled: true + triggerAiRca: false + +--- +# ReleaseBinding for recommendation component with cpu limit misconfiguration +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: recommendation-development + namespace: default +spec: + owner: + projectName: gcp-microservice-demo + componentName: recommendation + environment: development + componentTypeEnvironmentConfigs: + resources: + requests: + cpu: "10m" + limits: + cpu: "10m" + traitEnvironmentConfigs: + recommendation-high-cpu-alert: + enabled: true + actions: + notifications: + channels: + - "webhook-notification-channel-development" + incident: + enabled: true + triggerAiRca: true + +--- +# ReleaseBinding for cart component with memory limit misconfiguration +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: cart-development + namespace: default +spec: + owner: + projectName: gcp-microservice-demo + componentName: cart + environment: development + componentTypeEnvironmentConfigs: + resources: + requests: + memory: "100Mi" + limits: + memory: "150Mi" + # Note: traitEnvironmentConfigs is omitted here. + # Defaults: alert enabled, incident creation disabled, no AI RCA, uses environment's default notification channel +EOF +``` + +:::note +`actions.incident.triggerAiRca: true` requires `actions.incident.enabled: true`. +::: + +### Step 6: Trigger Alerts + +Run the curl loop to generate traffic and surface the misconfigurations. + +In another terminal, resolve the frontend HTTP route and repeatedly call the homepage and `/cart` to generate the error logs and traffic patterns used by the sample alerts. + +```bash +# Resolve the component route hostname and path prefix +HOSTNAME=$(kubectl get httproute -A -l openchoreo.dev/component=frontend \ + -o jsonpath='{.items[0].spec.hostnames[0]}') +PATH_PREFIX=$(kubectl get httproute -A -l openchoreo.dev/component=frontend \ + -o jsonpath='{.items[0].spec.rules[0].matches[0].path.value}') + +FRONTEND_BASE="http://${HOSTNAME}:19080${PATH_PREFIX}" +echo "Calling: ${FRONTEND_BASE} and ${FRONTEND_BASE}/cart" + +while true; do + # Fire requests to the homepage (triggers the frontend component's log-based alert) + curl -s -o /dev/null "${FRONTEND_BASE}/" || true + + # Fire requests to /cart (triggers the cart component's metric-based alert) + curl -s -o /dev/null "${FRONTEND_BASE}/cart" || true + + sleep 0.5 +done +``` + +### Step 7: Verify Alerts and Incidents + +Verify alert delivery to your configured notification channels: + +- Email channel: check the inbox configured in the email notification channel you applied above +- Webhook channel: check your webhook endpoint (and/or the OpenChoreo observer logs) + +OpenChoreo also persists alert events and incident data in the observability plane. You can view them via the Observer API (Backstage portal or OpenChoreo MCP server). +Also you can acknowledge and resolve incidents via the Backstage portal when the necessary actions are taken. + +### Step 8: Verify AI Root Cause Analysis + +If you have properly configured the [SRE Agent](../ai/sre-agent.mdx), you can verify AI root cause analysis by checking the RCA reports in the Backstage portal when an incident is created. + +## Summary + +You attached OpenChoreo **observability alert rules** to existing components (as `observability-alert-rule` traits), configured **email** and **webhook** notification channels per environment, and enabled **incident creation** (plus AI root cause analysis) via `ReleaseBinding` `traitEnvironmentConfigs`. + +Then you triggered the alerts using controlled misconfigurations, and verified alert delivery (and AI RCA reports when enabled). + +## Next Steps + +- Configure and tune the [SRE Agent](../ai/sre-agent.mdx) for your observability/AI requirements. +- Follow [Configure Budget Alert and Perform Cost Analysis using FinOps Agent](./configure-budget-alert-and-cost-analysis.mdx) to set up budget alerts and AI cost analysis. +- Explore how to view and manage alerts/incidents via the Observer API (Backstage portal and OpenChoreo MCP server). +- Customize webhook formatting using `payloadTemplate` for downstream systems (for example, Slack-compatible payloads). +- Refer to [Observability Alerting](../platform-engineer-guide/observability-alerting.mdx) for how alerting architecture works in OpenChoreo. + +## Cleanup + +Stop the curl loop (Ctrl+C). + +Delete sample resources in reverse order if desired: + +```bash +kubectl delete project gcp-microservice-demo -n default + +kubectl delete observabilityalertsnotificationchannel email-notification-channel-development webhook-notification-channel-development -n default +kubectl delete secret email-notification-channel-development-smtp-auth -n default +kubectl delete secret webhook-notification-channel-development-webhook-auth -n default +``` diff --git a/versioned_docs/version-v1.2.0-rc.2/tutorials/configure-budget-alert-and-cost-analysis.mdx b/versioned_docs/version-v1.2.0-rc.2/tutorials/configure-budget-alert-and-cost-analysis.mdx new file mode 100644 index 00000000..065d7fcb --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/tutorials/configure-budget-alert-and-cost-analysis.mdx @@ -0,0 +1,587 @@ +--- +title: Analyze component cost using FinOps agent +description: Attach a budget-based observability alert rule to a component, trigger it with a controlled cost overrun, and review the AI-generated cost analysis report produced by the FinOps Agent. +sidebar_position: 16 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Configure Budget Alert and Perform Cost Analysis using FinOps Agent + +This tutorial shows how to monitor the cost of an OpenChoreo component using a budget-based **Observability Alert Rule**, route notifications to a webhook channel, and use the **FinOps Agent** to automatically generate an **AI cost analysis** report — including a rightsizing recommendation that can be applied directly from the Backstage portal — whenever the budget threshold is breached. + +To make testing easy, this tutorial includes a **controlled cost-overrun scenario** that deliberately inflates a component's CPU/memory requests so the projected cost crosses the budget threshold within a short period of time. + +## Overview + +OpenChoreo's budget alerts are built on the same role-based workflow as other observability alerts, with the **FinOps Agent** layered on top to provide cost-aware incident enrichment: + +- **Platform Engineers (one-time setup)** + - Deploy the `observability-alert-rule` clustertrait (OpenChoreo ships a default one) + - Configure an `ObservabilityAlertsNotificationChannel` (email/webhook) per environment + - Configure the [FinOps Agent](../ai/finops-agent.mdx) so that budget-related incidents can be enriched with AI cost analysis +- **Developers (once per component)** + - Attach an `observability-alert-rule` trait with `source.type: budget` to the component, specifying the cost threshold and evaluation window +- **Platform Engineers (per environment tuning)** + - Use `traitEnvironmentConfigs` in the `ReleaseBinding` CR to enable the budget alert, select a notification channel, enable incident creation, and turn on `triggerAiCostAnalysis` + +When the budget alert fires, OpenChoreo creates an incident and (if `triggerAiCostAnalysis` is enabled) asks the FinOps Agent to produce a cost analysis report with an optimization recommendation that the developer can apply directly from the portal. + +## Prerequisites + +Before you begin, ensure you have: + +- A running OpenChoreo instance with the observability plane +- `kubectl` configured to talk to the cluster where OpenChoreo is installed +- The **FinOps Agent** configured. See [FinOps Agent](../ai/finops-agent.mdx) for the configuration guide. Without the FinOps Agent, the budget alert and incident will still be created, but no AI cost analysis report will be generated. + +## Platform Engineer Workflow + +### Step 1: Deploy the Alert Rule Trait (One-Time Setup) + +OpenChoreo ships a default clustertrait named `observability-alert-rule` that exposes all the parameters from the ObservabilityAlertRule CR as either `parameters` or `environmentConfigs`. +Platform Engineers can create specialized traits and clustertraits to expose specific parameters from ObservabilityAlertRule CRs to developers. +For example: `observability-log-alert-rule`, `observability-metric-alert-rule`, `observability-incident-rule`, etc. + +If the default `observability-alert-rule` clustertrait is already installed in your cluster, you can skip this step. + +```bash +kubectl apply -f - <<'EOF' +--- +# Trait for Alert Rules +apiVersion: openchoreo.dev/v1alpha1 +kind: ClusterTrait +metadata: + name: observability-alert-rule +spec: + parameters: + openAPIV3Schema: + type: object + properties: + description: + type: string + description: "A human-readable description of what this alert rule monitors and when it triggers." + severity: + type: string + enum: + - info + - warning + - critical + default: warning + description: "The severity level of alerts triggered by this rule. Determines alert priority and notification urgency." + source: + type: object + properties: + type: + type: string + enum: + - log + - metric + - budget + description: "The data source type for the alert rule." + query: + type: string + default: "" + description: "The query expression for log-based alerts. Required when source type is 'log'." + metric: + type: string + default: "" + description: "The predefined metric to monitor for metric-based alerts. Must be one of: cpu_usage, memory_usage. Required when source type is 'metric'." + required: + - type + condition: + type: object + properties: + window: + type: string + default: "5m" + description: "The time window over which data is aggregated before evaluating the alert condition (e.g. 5m, 10m, 30m, 1h)." + interval: + type: string + default: "1m" + description: "The frequency at which the alert rule is evaluated (e.g. 1m, 5m, 15m, 30m)." + operator: + type: string + enum: + - gt + - lt + - gte + - lte + - eq + default: gt + description: "The comparison operator used to evaluate the condition against the threshold (gt: greater than, lt: less than, gte: greater than or equal, lte: less than or equal, eq: equal)." + threshold: + type: integer + default: 10 + description: "The numeric threshold value used with the operator to determine when the alert triggers." + required: + - description + - source + - condition + + environmentConfigs: + openAPIV3Schema: + type: object + properties: + enabled: + type: boolean + default: true + description: "Controls whether this alert rule is active. When disabled, the rule will not trigger alerts." + actions: + type: object + properties: + notifications: + type: object + properties: + channels: + type: array + items: + type: string + default: [] + description: "The notification channel identifiers where alerts should be delivered. Configured per environment by platform engineers. If not provided, defaults to the environment's default notification channel." + incident: + type: object + properties: + enabled: + type: boolean + default: false + description: "Enables incident creation when this alert fires. When enabled, a corresponding incident will be created in the incident management system." + triggerAiCostAnalysis: + type: boolean + default: false + description: "Enables AI-powered cost analysis when an incident is created for a budget alert. Provides automated cost breakdown and optimization recommendations. Requires incident.enabled to also be true and is only valid for budget source type." + triggerAiRca: + type: boolean + default: false + description: "Enables AI-powered root cause analysis when an incident is created. When enabled, provides automated reports of root causes for alert conditions. Requires incident.enabled to also be true." + + validations: + - rule: "${(has(environmentConfigs.actions) && has(environmentConfigs.actions.notifications) && environmentConfigs.actions.notifications.channels.size() > 0) || (has(environment.defaultNotificationChannel) && environment.defaultNotificationChannel != '')}" + message: "A notification channel is mandatory for alert rules (incident-only rules are not supported). Provide environmentConfigs.actions.notifications.channels or set environment.defaultNotificationChannel." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiRca == false || environmentConfigs.actions.incident.enabled == true}" + message: "incident.enabled must be true when triggerAiRca is true. AI-powered root cause analysis requires incident creation to be enabled." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiCostAnalysis == false || environmentConfigs.actions.incident.enabled == true}" + message: "incident.enabled must be true when triggerAiCostAnalysis is true. AI-powered cost analysis requires incident creation to be enabled." + - rule: "${!has(environmentConfigs.actions) || !has(environmentConfigs.actions.incident) || environmentConfigs.actions.incident.triggerAiCostAnalysis == false || parameters.source.type == 'budget'}" + message: "triggerAiCostAnalysis can only be enabled for budget source type alerts." + + creates: + - targetPlane: observabilityplane + includeWhen: ${has(dataplane.observabilityPlaneRef)} + template: + apiVersion: openchoreo.dev/v1alpha1 + kind: ObservabilityAlertRule + metadata: + name: ${metadata.name}-${trait.instanceName} + namespace: ${metadata.namespace} + labels: + # Required for observability backends. Automatically populated by the controller. + openchoreo.dev/component-uid: ${metadata.componentUID} + openchoreo.dev/project-uid: ${metadata.projectUID} + openchoreo.dev/environment-uid: ${metadata.environmentUID} + spec: + name: ${trait.instanceName} + description: ${parameters.description} + severity: ${parameters.severity} + enabled: ${environmentConfigs.enabled} + source: + type: ${parameters.source.type} + query: ${parameters.source.query} + metric: ${parameters.source.metric} + condition: + window: ${parameters.condition.window} + interval: ${parameters.condition.interval} + operator: ${parameters.condition.operator} + threshold: ${parameters.condition.threshold} + actions: + notifications: + channels: >- + ${(has(environmentConfigs.actions) && has(environmentConfigs.actions.notifications) && environmentConfigs.actions.notifications.channels.size() > 0) + ? environmentConfigs.actions.notifications.channels + : [environment.defaultNotificationChannel]} + incident: + enabled: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && (environmentConfigs.actions.incident.enabled || environmentConfigs.actions.incident.triggerAiRca || environmentConfigs.actions.incident.triggerAiCostAnalysis)} + triggerAiCostAnalysis: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && environmentConfigs.actions.incident.enabled && environmentConfigs.actions.incident.triggerAiCostAnalysis} + triggerAiRca: ${has(environmentConfigs.actions) && has(environmentConfigs.actions.incident) && environmentConfigs.actions.incident.enabled && environmentConfigs.actions.incident.triggerAiRca} +EOF + +kubectl get clustertrait observability-alert-rule +``` + +### Step 2: Configure Notification Channels (One-Time Setup per Environment) + +Platform Engineers can configure one or more notification channels per environment (email/webhook), then reference them across all alert rules in that environment. +The first notification channel created in an environment is marked as that environment’s **default** notification channel (used when an alert doesn’t explicitly select channels). + +#### Email Notification Channel Example + +If your organization uses SMTP email for notifications, you can create an email notification channel by applying the following YAML replacing the placeholder values with your own. +Otherwise, you can skip this step and use a webhook notification channel instead. + +```bash +kubectl apply -f - <<'EOF' +--- +# Example email Notification Channel for development environment +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: email-notification-channel-development + namespace: default +spec: + environment: development + type: email + emailConfig: + from: notifications@openchoreo.dev # Replace with your SMTP sender email address + to: + - openchoreo-devops-group@acme.com # Replace with your recipients' email addresses + smtp: + host: mail.acme.com # Replace with your SMTP host + port: 587 # Replace with your SMTP port + auth: + username: + secretKeyRef: + name: email-notification-channel-development-smtp-auth + key: username + password: + secretKeyRef: + name: email-notification-channel-development-smtp-auth + key: password + tls: + insecureSkipVerify: true + template: + # Modify as needed with CEL expressions + subject: "OpenChoreo Observability Alert Notification - ${alertName}" + body: | + Alert triggered for your OpenChoreo observability alert rule: ${alertName} + Triggered at: ${alertTimestamp} UTC + Severity: ${alertSeverity} + Description: ${alertDescription} + Value: ${alertValue} + Threshold: ${alertThreshold} + Type: ${alertType} + Component: ${component} + Project: ${project} + Environment: ${environment} + Enabled AI Root Cause Analysis: ${triggerAiRca} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: email-notification-channel-development-smtp-auth + namespace: default +type: Opaque +stringData: + username: smtp-username # Replace with your SMTP username + password: smtp-password # Replace with your SMTP password +EOF +``` + +#### Webhook Notification Channel Example + +You can integrate OpenChoreo's observability alerts with your existing notification systems (such as Slack, Google Chat, etc.) by using a webhook notification channel. +For testing purposes, you can obtain a temporary webhook URL from [webhook.site](https://webhook.site/) and configure a webhook notification channel as follows: + +```bash +kubectl apply -f - <<'EOF' +--- +# Example webhook Notification Channel for development environment +apiVersion: openchoreo.dev/v1alpha1 +kind: ObservabilityAlertsNotificationChannel +metadata: + name: webhook-notification-channel-development + namespace: default +spec: + environment: development + type: webhook + webhookConfig: + url: https://webhook.acme.com # Replace with your webhook URL + headers: + Content-Type: + value: "application/json" + # Custom header for webhook authentication (if required) + X-API-Key: + valueFrom: + secretKeyRef: + name: webhook-notification-channel-development-webhook-auth + key: api-key + # Optional: Payload template using CEL expressions (${...}) + # If not provided, the raw alertDetails object will be sent as JSON + # For Slack, use the template below. For other webhooks, customize as needed. + payloadTemplate: | + { + "text": "Alert: ${alertName}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "🚨 OpenChoreo Alert: ${alertName}" + } + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Severity:*\n${alertSeverity}" + }, + { + "type": "mrkdwn", + "text": "*Value:*\n${alertValue}" + }, + { + "type": "mrkdwn", + "text": "*Threshold:*\n${alertThreshold}" + }, + { + "type": "mrkdwn", + "text": "*Component:*\n${component}" + } + ] + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*Description:*\n${alertDescription}" + } + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "Project: ${project} | Environment: ${environment} | Time: ${alertTimestamp}" + } + ] + } + ] + } + +--- +apiVersion: v1 +kind: Secret +metadata: + name: webhook-notification-channel-development-webhook-auth + namespace: default +type: Opaque +stringData: + api-key: webhook-api-key # Replace with your webhook API key (optional) +EOF +``` + +Note: The payload in the notifications can be customized using CEL expressions. Refer to [ObservabilityAlertsNotificationChannel](../reference/api/platform/observabilityalertsnotificationchannel.md) for details on CEL expressions and variables available in payload templates. + +## Developer Workflow + +### Step 3: Deploy the gcp-microservices-demo Sample + +This tutorial is based on the gcp-microservices-demo sample. +Deploy the sample using the following commands if you haven't already: + + +{` +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/gcp-microservice-demo-project.yaml + +# Provision the Redis cache, then promote the binding to the latest release. + +kubectl apply -f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/resources/redis.yaml +until release=$(kubectl get resource redis -n default -o jsonpath='{.status.latestRelease.name}') && [ -n "$release" ]; do sleep 2; done +kubectl patch resourcereleasebinding redis-development -n default --type=merge -p "{\\"spec\\":{\\"resourceRelease\\":\\"$release\\"}}" + +kubectl apply \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/ad-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/cart-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/checkout-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/currency-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/email-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/frontend-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/payment-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/productcatalog-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/recommendation-component.yaml \\ +-f https://raw.githubusercontent.com/openchoreo/openchoreo/${versions.githubRef}/samples/gcp-microservices-demo/components/shipping-component.yaml +`} + + + +### Step 4: Define a Budget Alert Rule for the Product Catalog Component + +Developers attach the budget alert rule as a trait to the component once. The alert rule automatically propagates to all environments as the component is promoted. + +In this step we attach a budget-based alert to the `productcatalog` component: + +- Trigger: cost of the productcatalog component exceeds USD 2 in 5 minutes +- Trait instance name: `productcatalog-budget-alert` + +```bash +# productcatalog component: budget-based alert +if kubectl get component productcatalog -n default \ + -o jsonpath='{.spec.traits[*].instanceName}' 2>/dev/null \ + | tr ' ' '\n' | grep -qx "productcatalog-budget-alert"; then + echo "Trait 'productcatalog-budget-alert' already exists on component 'productcatalog', skipping." +else + kubectl patch component productcatalog -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits/-", + "value": { + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "productcatalog-budget-alert", + "parameters": { + "description": "Alert when productcatalog cost for 5mins exceeds USD 2", + "severity": "warning", + "source": { "type": "budget" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 2 } + } + } + } + ]' 2>/dev/null || kubectl patch component productcatalog -n default --type=json -p='[ + { + "op": "add", + "path": "/spec/traits", + "value": [{ + "name": "observability-alert-rule", + "kind": "ClusterTrait", + "instanceName": "productcatalog-budget-alert", + "parameters": { + "description": "Alert when productcatalog cost for 5mins exceeds USD 2", + "severity": "warning", + "source": { "type": "budget" }, + "condition": { "window": "5m", "interval": "1m", "operator": "gt", "threshold": 2 } + } + }] + } + ]' +fi +``` + +#### Notification Channels Are Configured Per Environment + +The trait instance above defines what to alert on, but it doesn't define notification channels. + +Instead, Platform Engineers configure channels per environment using `traitEnvironmentConfigs` in the `ReleaseBinding` CR (next step). +If `traitEnvironmentConfigs` doesn't specify channels for the alert rule, the environment's default notification channel is used. + +Without a notification channel, the ReleaseBinding will fail to apply the alert rule to the Observability Plane. + +## Testing and Verification + +### Step 5: Inflate OpenCost Node Pricing for Faster Alert Triggering + +OpenCost calculates component cost based on the configured per-unit prices of CPU and memory on the underlying nodes. With the default pricing values, the projected cost of the `productcatalog` component grows very slowly, so a budget alert with a low threshold (USD 2) can take a long time to fire during testing. + +To make the budget alert trigger within a few minutes, temporarily override OpenCost's custom pricing model with significantly inflated CPU and RAM prices, then restart the OpenCost deployment so the new values take effect: + +```bash +helm upgrade --install finops-opencost \ + oci://ghcr.io/openchoreo/helm-charts/finops-opencost \ + --namespace openchoreo-observability-plane \ + --version 0.1.2 \ + --reuse-values \ + --set opencost.opencost.customPricing.costModel.CPU="50000" \ + --set opencost.opencost.customPricing.costModel.RAM="10000" \ +&& kubectl rollout restart deploy -n openchoreo-observability-plane opencost +``` + +:::note +This change is purely for accelerating the test scenario in this tutorial. Revert it after testing using the [Cleanup](#cleanup) step below to restore realistic pricing. +::: + +### Step 6: Configure a Cost-Overrun Scenario for Testing + +This step creates a `ReleaseBinding` that: + +- Deliberately inflates the `productcatalog` component's CPU and memory requests/limits in the `development` environment so the projected cost crosses the USD 2 threshold within a few minutes +- Configures the budget alert for the `development` environment via `traitEnvironmentConfigs`: + - Enables the alert rule + - Selects the webhook notification channel + - Enables incident creation + - Turns on `triggerAiCostAnalysis` so the FinOps Agent generates an AI cost analysis report when the incident is created + +Apply the scenario: + +```bash +kubectl apply -f - <<'EOF' +--- +# ReleaseBinding for productcatalog component with oversized resource requests/limits to trigger a budget alert +apiVersion: openchoreo.dev/v1alpha1 +kind: ReleaseBinding +metadata: + name: productcatalog-development + namespace: default +spec: + owner: + projectName: gcp-microservice-demo + componentName: productcatalog + environment: development + componentTypeEnvironmentConfigs: + resources: + requests: + cpu: "500m" + memory: "400Mi" + limits: + cpu: "1000m" + memory: "1000Mi" + traitEnvironmentConfigs: + productcatalog-budget-alert: + enabled: true + actions: + notifications: + channels: + - "webhook-notification-channel-development" + incident: + enabled: true + triggerAiCostAnalysis: true +EOF +``` + +:::note +`actions.incident.triggerAiCostAnalysis: true` requires `actions.incident.enabled: true` and is only valid for alerts with `source.type: budget`. +::: + +### Step 7: Verify the Budget Alert and AI Cost Analysis + +Within a few minutes of applying the productcatalog `ReleaseBinding`, the `productcatalog-budget-alert` should fire because the inflated CPU/memory requests push the cost above the threshold. + +- Confirm alert delivery to the configured webhook notification channel. +- Confirm that an incident was created for the budget alert in the Backstage portal. +- With the FinOps Agent configured, an **AI cost analysis** report is generated for the incident — view it in the Backstage portal alongside the incident. The cost analysis report provides a cost optimization recommendation (typically a rightsizing of CPU/memory requests and limits) and lets you apply the recommendation automatically. + +You can also acknowledge and resolve the incident via the Backstage portal once the recommendation has been applied. + +## Summary + +You attached a **budget-based observability alert rule** to the `productcatalog` component (as an `observability-alert-rule` trait), configured a **webhook notification channel**, and enabled **incident creation** and **AI cost analysis** via `ReleaseBinding` `traitEnvironmentConfigs`. + +Then you triggered the budget alert using a controlled cost-overrun scenario and verified that the **FinOps Agent** produced an AI cost analysis report with an actionable rightsizing recommendation. + +## Next Steps + +- Configure and tune the [FinOps Agent](../ai/finops-agent.mdx) for your cost-analysis requirements. +- See [Configure Component Alerts and Manage Incidents](./component-alerts-and-incidents.mdx) to set up log- and metric-based alerts (and AI Root Cause Analysis via the SRE Agent) on other components. +- Refer to [Observability Alerting](../platform-engineer-guide/observability-alerting.mdx) for how alerting architecture works in OpenChoreo. + +## Cleanup + +Restore OpenCost to its original pricing by reapplying the upstream values file used by the FinOps community module. This reverts the inflated CPU/RAM prices set in Step 5: + +```bash +helm upgrade --install finops-opencost \ + oci://ghcr.io/openchoreo/helm-charts/finops-opencost \ + --namespace openchoreo-observability-plane \ + --reset-values \ + --version 0.1.2 \ +&& kubectl rollout restart deploy -n openchoreo-observability-plane opencost +``` + +Delete sample resources in reverse order if desired: + +```bash +kubectl delete project gcp-microservice-demo -n default + +kubectl delete observabilityalertsnotificationchannel webhook-notification-channel-development -n default +kubectl delete secret webhook-notification-channel-development-webhook-auth -n default +``` diff --git a/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-prebuilt-image.mdx b/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-prebuilt-image.mdx new file mode 100644 index 00000000..4cbec1b0 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-prebuilt-image.mdx @@ -0,0 +1,274 @@ +--- +title: Deploy a Prebuilt Container Image +description: Deploy your existing container images to OpenChoreo from public or private registries without using the Workflow Plane. +sidebar_position: 5 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Deploy a Prebuilt Container Image + +This guide walks you through deploying a prebuilt container image to OpenChoreo. This is useful when you have existing container images built by external CI/CD pipelines and want to deploy them without using OpenChoreo's Workflow Plane. + +## Overview + +OpenChoreo supports deploying applications from prebuilt container images, commonly referred to as "Bring Your Own Image" (BYOI). You can deploy images from: + +- **Public registries** - No additional configuration needed +- **Private registries** - Requires setting up image pull credentials + +## Prerequisites + +Before you begin, ensure you have: + +- **OpenChoreo installed** in your Kubernetes cluster +- **kubectl** configured to access your cluster +- **A container image** to deploy + +## Deploy from a Public Registry + +Deploying an image from a public registry is straightforward - simply create the Component and Workload resources. + +### Example + +```bash +kubectl apply -f - <\"}}}" +' +``` + +Replace `` with the output from the previous command. For other secret backends, store the same Docker config JSON under the key `registry-credentials`. + +### Step 2 — Configure Your ClusterComponentType + +The `deployment/service` ClusterComponentType needs two additions to support private registry pulls: + +**An ExternalSecret** to sync the credentials from your secret store into the workload namespace: + +```yaml +- id: registry-pull-secret + template: + apiVersion: external-secrets.io/v1 + kind: ExternalSecret + metadata: + name: registry-pull-secret + namespace: ${metadata.namespace} + spec: + refreshInterval: 15s + secretStoreRef: + name: ${dataplane.secretStore} + kind: ClusterSecretStore + target: + name: registry-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + - secretKey: .dockerconfigjson + remoteRef: + key: registry-credentials + # For OpenBao local dev setup, secrets are stored under the 'value' property + property: value +``` + +**`imagePullSecrets`** in the Deployment template so pods can authenticate when pulling: + +```yaml +- id: deployment + template: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: ${metadata.name} + namespace: ${metadata.namespace} + spec: + template: + spec: + imagePullSecrets: + - name: registry-pull-secret + containers: + - name: main + image: ${workload.container.image} + # ... rest of container config +``` + +### Step 3 — Deploy the Component and Workload + +Once credentials are stored and your ClusterComponentType is updated, deploy the Component and Workload the same way as a public image — just point the image field to your private registry: + +```bash +kubectl apply -f - < +``` + +### Test Your Application + +```bash +curl http://development-default.openchoreoapis.localhost:19080/my-private-app-http +``` + +--- + +## Summary + +You've learned how to deploy prebuilt container images using the OpenChoreo BYOI (Bring Your Own Image) flow from both public and private registries. + +## Next Steps + +- [Set up Secret Management](../platform-engineer-guide/secret-management.mdx) for automatic credential rotation +- [Explore more examples](../getting-started/examples-catalog.mdx) of deploying applications diff --git a/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-with-configurations.mdx b/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-with-configurations.mdx new file mode 100644 index 00000000..928745b4 --- /dev/null +++ b/versioned_docs/version-v1.2.0-rc.2/tutorials/deploy-with-configurations.mdx @@ -0,0 +1,246 @@ +--- +title: Deploy an Application with Configurations and Secrets +description: Learn how to inject environment variables, config files, and secrets into your OpenChoreo worker deployments. +sidebar_position: 6 +--- + +import CodeBlock from "@theme/CodeBlock"; +import { versions } from "../_constants.mdx"; + +# Deploy an Application with Configurations and Secrets + +This guide walks you through deploying an application that uses environment variables, configuration files, and secrets. OpenChoreo lets you inject all of these into your workload without baking them into your container image. + +## Overview + +When deploying real applications, you typically need to: + +- Pass **environment variables** (log levels, feature flags) +- Mount **configuration files** (app settings, certificates) +- Inject **secrets** (database passwords, API tokens) from an external secret store + +OpenChoreo handles all of these through the `Workload` resource and the `SecretReference` resource. + +## Prerequisites + +Before you begin, ensure you have: + +- **OpenChoreo installed** in your Kubernetes cluster +- **kubectl** configured to access your cluster +- **External Secrets Operator (ESO)** installed (required for secrets) +- Secrets stored in your secret backend (this guide uses the default OpenBao dev setup) + +:::note +For production secret management, see [Secret Management](../platform-engineer-guide/secret-management.mdx) to configure a proper secret backend. +::: + +## Step 1 — Store Secrets in OpenBao + +Store the secret values your application needs. This example stores a database password and a GitHub personal access token. + +```bash +kubectl exec -n openbao openbao-0 -- sh -c ' + export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root + bao kv put secret/db-password value="supersecret" + bao kv put secret/github-pat value="ghp_your_token_here" +' +``` + +## Step 2 — Create SecretReferences + +`SecretReference` resources tell OpenChoreo how to pull a specific secret from your external store and make it available to your workload. + +```bash +kubectl apply -f - < -l openchoreo.dev/component=config-tutorial-app +``` + +Verify the ConfigMaps, ExternalSecrets, and Secrets were created for the configurations: + +```bash +kubectl get configmap -A | grep config-tutorial-app +kubectl get externalsecret -A | grep config-tutorial-app +kubectl get secrets -A | grep config-tutorial-app +``` + +## Summary + +You've learned how to deploy an application with environment variables, configuration files, and secrets using OpenChoreo's `Workload` and `SecretReference` resources, and how to override configurations per environment using `ReleaseBinding`. + +## Next Steps + +- [Set up Secret Management](../platform-engineer-guide/secret-management.mdx) for production secret backends +- [Explore more examples](../getting-started/examples-catalog.mdx) of deploying applications diff --git a/versioned_sidebars/version-v1.2.0-rc.2-sidebars.json b/versioned_sidebars/version-v1.2.0-rc.2-sidebars.json new file mode 100644 index 00000000..23de51cd --- /dev/null +++ b/versioned_sidebars/version-v1.2.0-rc.2-sidebars.json @@ -0,0 +1,728 @@ +{ + "docsSidebar": [ + { + "type": "category", + "label": "Overview", + "collapsed": false, + "items": [ + "overview/what-is-openchoreo", + "overview/architecture" + ] + }, + { + "type": "category", + "label": "Get Started", + "collapsed": false, + "link": { + "type": "generated-index", + "title": "Get Started", + "description": "Choose the Quick Start to try OpenChoreo with just Docker, or install it on your own Kubernetes cluster" + }, + "items": [ + "getting-started/quick-start-guide", + { + "type": "doc", + "id": "getting-started/try-it-out/on-k3d-locally", + "label": "Run Locally on K3d" + }, + { + "type": "doc", + "id": "getting-started/try-it-out/on-your-environment", + "label": "Run in Your Environment" + }, + { + "type": "doc", + "id": "getting-started/cli-installation", + "label": "CLI Installation" + }, + "getting-started/deploy-and-explore", + "getting-started/examples-catalog" + ] + }, + { + "type": "category", + "label": "Concepts", + "link": { + "type": "generated-index", + "title": "Concepts", + "description": "Understand the fundamental abstractions and relationships in OpenChoreo" + }, + "items": [ + "concepts/developer-abstractions", + "concepts/platform-abstractions", + "concepts/runtime-model", + "concepts/resource-relationships" + ] + }, + { + "type": "category", + "label": "Platform Engineer Guide", + "link": { + "type": "generated-index", + "title": "Platform Engineer Guide", + "description": "Setup, configuration, and governance for platform engineers" + }, + "items": [ + { + "type": "category", + "label": "Platform Setup", + "description": "Install, configure, and connect your OpenChoreo infrastructure", + "items": [ + "platform-engineer-guide/deployment-topology", + "platform-engineer-guide/multi-cluster-connectivity", + "platform-engineer-guide/air-gapped-installation", + "platform-engineer-guide/external-ca-tls-setup", + "platform-engineer-guide/namespace-management", + "platform-engineer-guide/container-registry-configuration", + "platform-engineer-guide/identity-configuration", + "platform-engineer-guide/backstage-configuration", + "platform-engineer-guide/backstage-ownership", + "platform-engineer-guide/backstage-scaffolder-templates", + "platform-engineer-guide/secret-management" + ] + }, + { + "type": "category", + "label": "Backstage Plugins", + "description": "Install OpenChoreo plugins into your existing Backstage app", + "link": { + "type": "doc", + "id": "platform-engineer-guide/backstage-plugins/overview" + }, + "items": [ + "platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2", + "platform-engineer-guide/backstage-plugins/installing-into-existing-backstage", + "platform-engineer-guide/backstage-plugins/catalog-sync", + "platform-engineer-guide/backstage-plugins/entity-views", + "platform-engineer-guide/backstage-plugins/permission-policy", + "platform-engineer-guide/backstage-plugins/troubleshooting", + "platform-engineer-guide/backstage-plugins/compatibility-matrix" + ] + }, + { + "type": "category", + "label": "Component Types & Traits", + "description": "Define and customize workload templates with schemas and CEL", + "items": [ + "platform-engineer-guide/component-types/overview", + "platform-engineer-guide/component-types/templating-syntax", + "platform-engineer-guide/component-types/schema-syntax", + "platform-engineer-guide/component-types/patching-syntax", + "platform-engineer-guide/component-types/validation-rules" + ] + }, + { + "type": "doc", + "id": "platform-engineer-guide/resource-types", + "label": "Resource Types" + }, + { + "type": "category", + "label": "Workflows & CI", + "description": "Define workflows, configure build infrastructure, and manage CI pipelines", + "items": [ + "platform-engineer-guide/workflows/overview", + "platform-engineer-guide/workflows/creating-workflows", + "platform-engineer-guide/workflows/schema-syntax", + "platform-engineer-guide/workflows/running-workflows", + { + "type": "category", + "label": "CI", + "description": "Configure CI workflow governance, workload publishing, and build triggers", + "items": [ + "platform-engineer-guide/workflows/ci-governance", + "platform-engineer-guide/workflows/workload-generation", + "platform-engineer-guide/workflows/workflow-workload-configuration", + "platform-engineer-guide/workflows/auto-build", + "platform-engineer-guide/workflows/external-ci" + ] + } + ] + }, + { + "type": "category", + "label": "API Gateway", + "description": "Configure API gateway modules and topology", + "items": [ + "platform-engineer-guide/api-gateway/modules", + "platform-engineer-guide/api-gateway/topology" + ] + }, + { + "type": "category", + "label": "Observability", + "description": "Configure monitoring alerts and notification channels", + "items": [ + "platform-engineer-guide/observability-alerting" + ] + }, + { + "type": "category", + "label": "Authorization & Access Control", + "description": "Configure roles and bindings for access control", + "items": [ + "platform-engineer-guide/authorization/overview", + "platform-engineer-guide/authorization", + { + "type": "doc", + "id": "platform-engineer-guide/authorization/custom-roles", + "label": "Custom Roles and Bindings" + }, + { + "type": "doc", + "id": "platform-engineer-guide/authorization/conditions", + "label": "Conditions" + } + ] + }, + { + "type": "category", + "label": "GitOps", + "description": "Manage platform resources with Git-based workflows", + "link": { + "type": "generated-index", + "title": "GitOps", + "description": "Manage platform resources with Git-based workflows" + }, + "items": [ + "platform-engineer-guide/gitops/overview", + "platform-engineer-guide/gitops/using-flux-cd", + { + "type": "category", + "label": "Automations", + "description": "Automate builds, releases, and promotions with GitOps workflows", + "link": { + "type": "generated-index", + "title": "Automations", + "description": "Automate builds, releases, and promotions with GitOps workflows" + }, + "items": [ + "platform-engineer-guide/gitops/automations/build-and-release-workflows", + "platform-engineer-guide/gitops/automations/bulk-promote" + ] + } + ] + }, + { + "type": "category", + "label": "Modules", + "description": "Extend OpenChoreo with pluggable modules", + "items": [ + "platform-engineer-guide/modules/overview", + { + "type": "category", + "label": "Building a Module", + "link": { + "type": "doc", + "id": "platform-engineer-guide/modules/building-a-module" + }, + "items": [ + "platform-engineer-guide/modules/observability-logging-adapter-api", + "platform-engineer-guide/modules/observability-metrics-adapter-api", + "platform-engineer-guide/modules/observability-tracing-adapter-api" + ] + } + ] + }, + { + "type": "category", + "label": "Operations & Maintenance", + "description": "CLI configuration, upgrades, and day-2 operations", + "items": [ + "platform-engineer-guide/cli-configuration", + { + "type": "category", + "label": "Upgrades", + "description": "Upgrade policy and per-version upgrade guides for OpenChoreo", + "link": { + "type": "generated-index", + "title": "Upgrades", + "description": "Upgrade policy and per-version upgrade guides for OpenChoreo" + }, + "items": [ + "platform-engineer-guide/upgrades/overview", + "platform-engineer-guide/upgrades/v1.1-to-v1.2", + "platform-engineer-guide/upgrades/v1.0-to-v1.1" + ] + }, + "platform-engineer-guide/cluster-agent-rbac" + ] + } + ] + }, + { + "type": "category", + "label": "Developer Guide", + "link": { + "type": "generated-index", + "title": "Developer Guide", + "description": "Build, deploy, and operate applications on OpenChoreo" + }, + "items": [ + { + "type": "category", + "label": "Projects and Components", + "description": "Create and manage projects and components", + "link": { + "type": "generated-index", + "title": "Projects and Components" + }, + "items": [ + "developer-guide/projects-and-components/overview", + "developer-guide/projects-and-components/creating-a-project", + "developer-guide/projects-and-components/creating-a-component" + ] + }, + { + "type": "category", + "label": "Define Your Workload", + "description": "Define containers, endpoints, and runtime configuration", + "link": { + "type": "generated-index", + "title": "Define Your Workload" + }, + "items": [ + "developer-guide/workload/overview", + { + "type": "doc", + "id": "developer-guide/dependencies/endpoints", + "label": "Endpoint Dependencies" + }, + { + "type": "doc", + "id": "developer-guide/dependencies/resources", + "label": "Resource Dependencies" + } + ] + }, + { + "type": "category", + "label": "Build Your Code", + "description": "Configure CI builds, workload descriptors, and private repository access", + "link": { + "type": "generated-index", + "title": "Build Your Code" + }, + "items": [ + "developer-guide/workflows/ci/overview", + "developer-guide/workflows/ci/workload-descriptor", + "developer-guide/workflows/ci/auto-build", + "developer-guide/workflows/ci/private-repository" + ] + }, + { + "type": "category", + "label": "Deploying Applications", + "description": "Deploy, promote, and manage applications across environments", + "link": { + "type": "generated-index", + "title": "Deploying Applications" + }, + "items": [ + "developer-guide/deploying-applications/overview", + "developer-guide/deploying-applications/deploy-and-promote", + "developer-guide/deploying-applications/environment-overrides", + "developer-guide/deploying-applications/logs-and-troubleshooting" + ] + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "link": { + "type": "generated-index", + "title": "Tutorials", + "description": "End-to-end scenarios and hands-on walkthroughs" + }, + "items": [ + "tutorials/deploy-prebuilt-image", + "tutorials/build-and-deploy-private", + "tutorials/deploy-with-configurations", + "tutorials/component-alerts-and-incidents", + "tutorials/configure-budget-alert-and-cost-analysis" + ] + }, + { + "type": "doc", + "id": "ecosystem/overview", + "label": "Ecosystem" + }, + { + "type": "category", + "label": "Working with AI", + "link": { + "type": "generated-index", + "title": "Working with AI", + "description": "AI assistants, MCP servers, and built-in agents for OpenChoreo" + }, + "items": [ + { + "type": "doc", + "id": "ai/overview", + "label": "Overview" + }, + { + "type": "category", + "label": "MCP Servers", + "description": "Connect AI assistants to OpenChoreo via MCP", + "items": [ + "ai/mcp-servers", + "ai/mcp-prompt-scenarios" + ] + }, + { + "type": "category", + "label": "Built-in Agents", + "description": "AI-powered agents for cost optimization, root cause analysis, and diagnostics", + "items": [ + "ai/finops-agent", + "ai/sre-agent", + "ai/portal-assistant" + ] + } + ] + }, + { + "type": "category", + "label": "References", + "link": { + "type": "generated-index", + "title": "References", + "description": "API reference, CLI reference, Helm charts, CEL, and MCP servers" + }, + "items": [ + { + "type": "category", + "label": "Helm Charts", + "description": "Configuration reference for OpenChoreo Helm charts", + "link": { + "type": "generated-index", + "title": "Helm Charts" + }, + "items": [ + "reference/helm/control-plane", + "reference/helm/data-plane", + "reference/helm/workflow-plane", + "reference/helm/observability-plane" + ] + }, + { + "type": "category", + "label": "API Reference", + "description": "Kubernetes CRD specifications for all OpenChoreo resources", + "link": { + "type": "generated-index", + "title": "API Reference" + }, + "items": [ + { + "type": "category", + "label": "Application Resources", + "description": "Define, configure, and build applications on the platform", + "link": { + "type": "generated-index", + "title": "Application Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/application/project", + "label": "Project" + }, + { + "type": "doc", + "id": "reference/api/application/component", + "label": "Component" + }, + { + "type": "doc", + "id": "reference/api/application/workflowrun", + "label": "WorkflowRun" + }, + { + "type": "doc", + "id": "reference/api/application/workload", + "label": "Workload" + }, + { + "type": "doc", + "id": "reference/api/application/resource", + "label": "Resource" + } + ] + }, + { + "type": "category", + "label": "Platform Resources", + "description": "Platform engineer-managed resources for infrastructure, governance, and operations", + "link": { + "type": "generated-index", + "title": "Platform Resources" + }, + "items": [ + { + "type": "category", + "label": "Infrastructure", + "description": "Define where workloads, builds, and observability services run", + "link": { + "type": "generated-index", + "title": "Infrastructure Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/platform/dataplane", + "label": "DataPlane" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterdataplane", + "label": "ClusterDataPlane" + }, + { + "type": "doc", + "id": "reference/api/platform/workflowplane", + "label": "WorkflowPlane" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterworkflowplane", + "label": "ClusterWorkflowPlane" + }, + { + "type": "doc", + "id": "reference/api/platform/observabilityplane", + "label": "ObservabilityPlane" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterobservabilityplane", + "label": "ClusterObservabilityPlane" + } + ] + }, + { + "type": "category", + "label": "Governance", + "description": "Templates and policies that shape how applications are built and deployed", + "link": { + "type": "generated-index", + "title": "Governance Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/platform/componenttype", + "label": "ComponentType" + }, + { + "type": "doc", + "id": "reference/api/platform/clustercomponenttype", + "label": "ClusterComponentType" + }, + { + "type": "doc", + "id": "reference/api/platform/trait", + "label": "Trait" + }, + { + "type": "doc", + "id": "reference/api/platform/clustertrait", + "label": "ClusterTrait" + }, + { + "type": "doc", + "id": "reference/api/platform/resourcetype", + "label": "ResourceType" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterresourcetype", + "label": "ClusterResourceType" + }, + { + "type": "doc", + "id": "reference/api/platform/workflow", + "label": "Workflow" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterworkflow", + "label": "ClusterWorkflow" + }, + { + "type": "doc", + "id": "reference/api/platform/secretreference", + "label": "SecretReference" + } + ] + }, + { + "type": "category", + "label": "Deployment", + "description": "Control how applications are promoted and released across environments", + "link": { + "type": "generated-index", + "title": "Deployment Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/platform/deployment-pipeline", + "label": "DeploymentPipeline" + }, + { + "type": "doc", + "id": "reference/api/platform/environment", + "label": "Environment" + }, + { + "type": "doc", + "id": "reference/api/platform/releasebinding", + "label": "ReleaseBinding" + }, + { + "type": "doc", + "id": "reference/api/platform/resourcereleasebinding", + "label": "ResourceReleaseBinding" + } + ] + }, + { + "type": "category", + "label": "Observability", + "description": "Configure monitoring alerts and how teams get notified", + "link": { + "type": "generated-index", + "title": "Observability Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/platform/observabilityalertrule", + "label": "ObservabilityAlertRule" + }, + { + "type": "doc", + "id": "reference/api/platform/observabilityalertsnotificationchannel", + "label": "ObservabilityAlertsNotificationChannel" + } + ] + }, + { + "type": "category", + "label": "Authorization", + "description": "Control who can access and manage platform resources", + "link": { + "type": "generated-index", + "title": "Authorization Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/platform/authzrole", + "label": "AuthzRole" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterauthzrole", + "label": "ClusterAuthzRole" + }, + { + "type": "doc", + "id": "reference/api/platform/authzrolebinding", + "label": "AuthzRoleBinding" + }, + { + "type": "doc", + "id": "reference/api/platform/clusterauthzrolebinding", + "label": "ClusterAuthzRoleBinding" + } + ] + } + ] + }, + { + "type": "category", + "label": "Runtime Resources", + "description": "Controller-managed resources for releases and deployments", + "link": { + "type": "generated-index", + "title": "Runtime Resources" + }, + "items": [ + { + "type": "doc", + "id": "reference/api/runtime/componentrelease", + "label": "ComponentRelease" + }, + { + "type": "doc", + "id": "reference/api/runtime/resourcerelease", + "label": "ResourceRelease" + }, + { + "type": "doc", + "id": "reference/api/runtime/renderedrelease", + "label": "RenderedRelease" + } + ] + } + ] + }, + { + "type": "category", + "label": "CEL Reference", + "description": "Context variables, built-in functions, and configuration helpers for CEL expressions", + "link": { + "type": "generated-index", + "title": "CEL Reference" + }, + "items": [ + { + "type": "doc", + "id": "reference/cel/context-variables", + "label": "Context Variables" + }, + { + "type": "doc", + "id": "reference/cel/built-in-functions", + "label": "Built-in Functions" + }, + { + "type": "doc", + "id": "reference/cel/helper-functions", + "label": "Helper Functions" + } + ] + }, + { + "type": "doc", + "id": "reference/mcp-servers", + "label": "MCP Servers" + }, + { + "type": "doc", + "id": "reference/cli-reference", + "label": "CLI Reference" + } + ] + }, + { + "type": "doc", + "id": "releases/release-and-support-process", + "label": "Releases" + }, + { + "type": "doc", + "id": "changelog", + "label": "Changelog" + }, + { + "type": "doc", + "id": "reference/faq", + "label": "FAQ" + } + ] +} diff --git a/versions.json b/versions.json index d53df385..fca57ead 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ [ + "v1.2.0-rc.2", "v1.2.0-rc.1", "v1.2.0-m.1", "v1.1.x",