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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions .ai/spec/how/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
| `internal/controller/console/reconciler.go` | `ReconcileConsoleUIResources()`, `ReconcileConsoleUIDeploymentAndPlugin()`, `RemoveConsoleUI()` | Console UI Phase 1 + Phase 2 + cleanup |
| `internal/controller/console/deployment.go` | `GenerateConsoleUIDeployment()` | Console UI deployment generation |
| `internal/controller/console/assets.go` | ConsolePlugin CR generator, nginx config, service, network policy | Console UI resource generation |
| `internal/controller/alertsadapter/reconciler.go` | `ReconcileAlertsAdapterResources()`, `ReconcileAlertsAdapterDeployment()`, `RemoveAlertsAdapter()`, `RestartAlertsAdapter()` | Alerts adapter Phase 1 + Phase 2 + operand teardown (disable/finalizer) + rolling restart |
| `internal/controller/alertsadapter/deployment.go` | `GenerateDeployment()` | Alerts adapter deployment generation |
| `internal/controller/alertsadapter/assets.go` | SA, ClusterRole, ClusterRoleBinding, monitoring RoleBinding, NetworkPolicy generators | Alerts adapter resource generation |
| `internal/controller/reconciler/interface.go` | `Reconciler` interface | Dependency injection interface for component packages |
| `internal/controller/utils/constants.go` | ~200 constants | Resource names, ports, paths, annotation keys, defaults |
| `internal/controller/utils/errors.go` | ~80 error message constants | Structured error messages for all operations |
Expand Down Expand Up @@ -69,10 +72,14 @@ OLSConfigReconciler.Reconcile()
+-- console.ReconcileConsoleUIResources()
+-- postgres.ReconcilePostgresResources()
+-- appserver.ReconcileAppServerResources()
+-- alertsadapter.ReconcileAlertsAdapterResources()
(opt-in via configMapRef; RemoveAlertsAdapter() when disabled; no ConfigMap validation;
mount at /etc/alerts-adapter when CM exists)
6. reconcileDeploymentsAndStatus() -- Phase 2: Deployments, Services, TLS certs, status
+-- console.ReconcileConsoleUIDeploymentAndPlugin()
+-- postgres.ReconcilePostgresDeployment()
+-- appserver.ReconcileAppServerDeployment()
+-- alertsadapter.ReconcileAlertsAdapterDeployment() # when configMapRef set
+-- checkDeploymentStatus() per deployment -> build newStatus
+-- UpdateStatusCondition()
```
Expand All @@ -90,14 +97,14 @@ External secret/configmap changes
-> Match against SystemResources list (by name+namespace)
-> OR match against WatcherAnnotationKey annotation
-> Resolve "ACTIVE_BACKEND" to appserver deployment name
-> Call RestartAppServer() / RestartPostgres() / RestartConsoleUI()
-> Call RestartAppServer() / RestartPostgres() / RestartConsoleUI() / RestartAlertsAdapter()
-> Set force-reload annotation with current timestamp
```

## Key Abstractions

### Image Management
Default images are stored in a `defaultImages` map in `cmd/main.go` keyed by logical name (e.g., `"lightspeed-service"`, `"postgres-image"`, `"console-plugin"`). Default values come from `internal/relatedimages/` which reads `related_images.json` at build time. Command-line flags override individual images. The map is passed to the reconciler via `OLSConfigReconcilerOptions` as individual named fields (e.g., `LightspeedServiceImage`, `ConsoleUIImage`).
Default images are stored in a `defaultImages` map in `cmd/main.go` keyed by logical name (e.g., `"lightspeed-service"`, `"postgres-image"`, `"console-plugin"`, `"alerts-adapter"`). Default values come from `internal/relatedimages/` which reads `related_images.json` at build time. Command-line flags override individual images. The map is passed to the reconciler via `OLSConfigReconcilerOptions` as individual named fields (e.g., `LightspeedServiceImage`, `ConsoleUIImage`, `AlertsAdapterImage`).

### WatcherConfig
Declarative configuration for external resource watching. Contains:
Expand All @@ -108,7 +115,7 @@ Declarative configuration for external resource watching. Contains:
The special deployment name `"ACTIVE_BACKEND"` resolves to the AppServer deployment name (`lightspeed-app-server`).

### Component Package Pattern
Each component (appserver, postgres, console) follows the same package structure:
Each component (appserver, postgres, console, alertsadapter) follows the same package structure:
- `reconciler.go`: Phase 1 (resources) and Phase 2 (deployment) entry points
- `deployment.go`: Deployment spec generation and update detection
- `assets.go` and/or `config.go`: Resource and config generation
Expand All @@ -117,17 +124,18 @@ The packages receive `reconciler.Reconciler` interface, never import the control
### Reconciler Interface (`internal/controller/reconciler/interface.go`)
Embeds `client.Client` and adds getter methods for:
- `GetScheme()`, `GetLogger()`, `GetNamespace()`
- Image getters: `GetAppServerImage()`, `GetPostgresImage()`, `GetConsoleUIImage()`, `GetOpenShiftMCPServerImage()`, `GetDataverseExporterImage()`
- Image getters: `GetAppServerImage()`, `GetPostgresImage()`, `GetConsoleUIImage()`, `GetAlertsAdapterImage()`, `GetOpenShiftMCPServerImage()`, `GetDataverseExporterImage()`
- Version getters: `GetOpenShiftMajor()`, `GetOpenshiftMinor()`
- Config getters: `IsPrometheusAvailable()`, `GetWatcherConfig()`

### Finalizer Pattern
The OLSConfig CR uses finalizer `ols.openshift.io/finalizer` (defined in `utils.OLSConfigFinalizer`). On deletion:
1. Remove Console UI (deactivate plugin, delete ConsolePlugin CR)
2. List all owned resources via owner references
3. Explicitly delete owned resources
4. Wait up to 3 minutes for deletion (poll every 5 seconds)
5. Remove finalizer (proceeds even if cleanup times out)
2. Remove alerts adapter operand resources (`alertsadapter.RemoveAlertsAdapter()`: deployment, namespaced RBAC, SA, NetworkPolicy, monitoring RoleBinding; proposals ClusterRole/ClusterRoleBinding when the platform permits delete)
3. List all owned resources via owner references
4. Explicitly delete owned resources
5. Wait up to 3 minutes for deletion (poll every 5 seconds)
6. Remove finalizer (proceeds even if cleanup times out)

## Integration Points

Expand Down
12 changes: 8 additions & 4 deletions .ai/spec/how/reconciliation.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,26 @@ Reconcile(ctx, req)
-> handleFinalizer() # Add/remove finalizer, run cleanup
-> reconcileOperatorResources() # ServiceMonitor, NetworkPolicy (operator-level)
-> annotateExternalResources() # Validate secrets, annotate for watching
-> reconcileIndependentResources() # Phase 1: console, postgres, backend resources
-> reconcileIndependentResources() # Phase 1: console, postgres, backend, alerts adapter resources
| |-- console.ReconcileConsoleUIResources()
| |-- postgres.ReconcilePostgresResources()
| +-- appserver.ReconcileAppServerResources()
| |-- appserver.ReconcileAppServerResources()
| +-- alertsadapter.ReconcileAlertsAdapterResources()
| (opt-in via configMapRef; RemoveAlertsAdapter() when disabled; no ConfigMap validation;
| mount at /etc/alerts-adapter when CM exists)
-> reconcileDeploymentsAndStatus() # Phase 2: deployments + status update
|-- console.ReconcileConsoleUIDeploymentAndPlugin()
|-- postgres.ReconcilePostgresDeployment()
|-- appserver.ReconcileAppServerDeployment()
|-- alertsadapter.ReconcileAlertsAdapterDeployment() # when configMapRef set
|-- checkDeploymentStatus() for each # Collect diagnostics
+-- UpdateStatusCondition() # Single status update
```

## Key Abstractions

### Reconciler Interface
The `reconciler.Reconciler` interface breaks the circular dependency between the main controller and component packages. Component packages (appserver, postgres, console) receive this interface instead of importing the controller package directly. It embeds `client.Client` and adds getter methods for images, namespace, and OpenShift version.
The `reconciler.Reconciler` interface breaks the circular dependency between the main controller and component packages. Component packages (appserver, postgres, console, alertsadapter) receive this interface instead of importing the controller package directly. It embeds `client.Client` and adds getter methods for images, namespace, and OpenShift version.

### ReconcileSteps Pattern
Both phases use a slice of `ReconcileSteps` structs, each containing a Name, reconcile function, and (for Phase 2) a ConditionType and Deployment name. Phase 1 iterates with continue-on-error; Phase 2 iterates but tracks all conditions and diagnostics.
Expand All @@ -44,7 +48,7 @@ Two ownership models:
2. **External resources**: Watches() with custom predicates. Annotation-based filtering. Secret/ConfigMap handlers compare data and trigger deployment restarts.

### Finalizer Cleanup
The `finalizeOLSConfig()` method uses `listOwnedResources()` which queries every resource type by owner reference UID (not labels). This is more reliable than label-based cleanup. The wait loop polls with a fixed interval and timeout, using `wait.PollUntilContextTimeout`.
The `finalizeOLSConfig()` method removes Console UI, deletes alerts adapter operand resources via `alertsadapter.RemoveAlertsAdapter()` (deployment, namespaced RBAC, SA, NetworkPolicy, cross-namespace monitoring RoleBinding; proposals ClusterRole/ClusterRoleBinding when permitted—may remain on managed OpenShift if admission webhook blocks delete), then uses `listOwnedResources()` which queries every resource type by owner reference UID (not labels). This is more reliable than label-based cleanup. The wait loop polls with a fixed interval and timeout, using `wait.PollUntilContextTimeout`.

### Status Update Mechanics
`UpdateStatusCondition()` uses `retry.RetryOnConflict` with `client.MergeFrom` patch. It preserves `LastTransitionTime` for conditions whose status hasn't changed. It re-fetches the CR before each update attempt to get the latest ResourceVersion.
Expand Down
8 changes: 4 additions & 4 deletions .ai/spec/what/bundle-composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ The lightspeed-operator OLM bundle installs both the lightspeed-operator control

### Agentic Operand Deployment

16. [PLANNED: OLS-3236] The lightspeed-operator deploys the agentic alerts adapter and the agentic console plugin as fully reconciled operands, with Phase 1/2 reconciliation, status conditions, health monitoring, and finalizer cleanup. The agentic-operator does not deploy these operands.
17. [PLANNED: OLS-3236] Agentic operand images default to `:main` tags until Konflux onboarding provides SHA-pinned productized images. CLI flags (`--alerts-adapter-image`, `--agentic-console-image`) on the lightspeed-operator deployment override the defaults.
16. The lightspeed-operator reconciles the agentic alerts adapter as a fully managed operand (OLS-3348, opt-in via `spec.ols.deployment.alertsAdapter.configMapRef`): Phase 1/2 reconciliation when enabled, `AlertsAdapterReady` status condition (`NotConfigured` when disabled), health monitoring, operand teardown on disable, ConfigMap watcher restarts, and finalizer cleanup via `RemoveAlertsAdapter()`. The agentic console plugin remains [PLANNED: OLS-3236].
17. Agentic operand images default to `:main` tags until Konflux onboarding provides SHA-pinned productized images. The `--alerts-adapter-image` flag is implemented on the lightspeed-operator binary; wiring it into the CSV deployment spec is [PLANNED: OLS-3236]. The `--agentic-console-image` flag is [PLANNED: OLS-3236].

## Configuration Surface

Expand All @@ -48,7 +48,7 @@ The lightspeed-operator OLM bundle installs both the lightspeed-operator control
| Agentic controller startup flags | CSV deployment spec args | Operand image overrides for the agentic controller |
| Agentic controller `--sandbox-mode` | CSV deployment spec args | `bare-pod` (default) or `sandbox-claim` — selects sandbox provisioning strategy |
| Agentic controller `--agentic-sandbox-image` | CSV deployment spec args | [PLANNED: OLS-3236] Sandbox container image (default: `:main` tag, overridable) |
| Lightspeed controller `--alerts-adapter-image` | CSV deployment spec args | [PLANNED: OLS-3236] Alerts adapter container image (default: `:main` tag) |
| Lightspeed controller `--alerts-adapter-image` | `cmd/main.go` flag (implemented); CSV deployment spec args [PLANNED: OLS-3236] | Alerts adapter container image (default: Konflux `:main` tag) |
| Lightspeed controller `--agentic-console-image` | CSV deployment spec args | [PLANNED: OLS-3236] Agentic console plugin container image (default: `:main` tag) |

## Constraints
Expand All @@ -61,4 +61,4 @@ The lightspeed-operator OLM bundle installs both the lightspeed-operator control

| Ticket | Summary |
|---|---|
| OLS-3236 | Migrate agentic console deployment from agentic-operator to lightspeed-operator. Add alerts-adapter as new operand. Add `--alerts-adapter-image` and `--agentic-console-image` flags to lightspeed-operator CSV deployment. Remove `--agentic-console-image` from agentic-operator CSV deployment. |
| OLS-3236 | Migrate agentic console deployment from agentic-operator to lightspeed-operator. Wire `--alerts-adapter-image` and `--agentic-console-image` into lightspeed-operator CSV deployment. Remove `--agentic-console-image` from agentic-operator CSV deployment. |
9 changes: 6 additions & 3 deletions .ai/spec/what/crd-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ Field path (relative to `spec.ols.deployment`) | JSON key | Go type | Notes
`mcpServer` | `mcpServer` | `ContainerConfig` | MCP server container. Resources only
`console` | `console` | `Config` | Console container. Has replicas field but operator forces 1
`database` | `database` | `Config` | Database container. Has replicas field but operator forces 1
`alertsAdapter` | `alertsAdapter` | `Config` | [PLANNED: OLS-3236] Agentic alerts adapter container. Replicas forced to 1
`alertsAdapter` | `alertsAdapter` | `AlertsAdapterSpec` | Agentic alerts adapter deployment and user-managed runtime config reference. Replicas forced to 1

`AlertsAdapterSpec` embeds `Config` (deployment scheduling/resources) and optional `configMapRef` (`LocalObjectReference`). Setting `configMapRef` **enables** the alerts adapter operand. The referenced ConfigMap name is `configMapRef.name` (commonly `alerts-adapter-config`; see [adapter manifests](https://github.com/openshift/lightspeed-agentic-alerts-adapter/tree/main/manifests)). The operator does not create or validate ConfigMap content. When the ConfigMap exists, it is mounted at `/etc/alerts-adapter`; when absent, no config volume is mounted. The adapter reads `config.yaml` from that path and uses built-in defaults when the file is missing or invalid.
`agenticConsole` | `agenticConsole` | `Config` | [PLANNED: OLS-3236] Agentic console plugin container. Replicas forced to 1

20. Replicas are only user-configurable for the API container (`spec.ols.deployment.api.replicas`). For console, database, alerts adapter, and agentic console, the operator always overrides replicas to 1 regardless of spec value.
Expand Down Expand Up @@ -280,7 +282,7 @@ Condition types used by the operator:
- `ApiReady` -- API server deployment health
- `CacheReady` -- PostgreSQL cache deployment health
- `ConsolePluginReady` -- Console UI plugin deployment health
- `AlertsAdapterReady` -- [PLANNED: OLS-3236] Agentic alerts adapter deployment health
- `AlertsAdapterReady` -- Agentic alerts adapter deployment health
- `AgenticConsolePluginReady` -- [PLANNED: OLS-3236] Agentic console plugin deployment health
- `ResourceReconciliation` -- Overall resource reconciliation status (set directly, not deployment-based)

Expand Down Expand Up @@ -372,7 +374,8 @@ Path | Type | Default | Required | Validation | Description
`spec.ols.deployment.database.nodeSelector` | `map[string]string` | -- | No | -- | Database node selector
`spec.ols.deployment.database.affinity` | `*Affinity` | -- | No | -- | Database affinity
`spec.ols.deployment.database.topologySpreadConstraints` | `[]TopologySpreadConstraint` | -- | No | -- | Database topology spread
`spec.ols.deployment.alertsAdapter` | `Config` | -- | No | -- | [PLANNED: OLS-3236] Alerts adapter deployment
`spec.ols.deployment.alertsAdapter` | `AlertsAdapterSpec` | -- | No | -- | Alerts adapter deployment and config reference
`spec.ols.deployment.alertsAdapter.configMapRef` | `LocalObjectReference` | (none) | No | -- | Opt-in switch and runtime config reference: ConfigMap name in operator namespace; mounted at `/etc/alerts-adapter` when present (adapter reads `config.yaml`)
`spec.ols.deployment.alertsAdapter.replicas` | `*int32` | `1` | No | Min=0 | Alerts adapter replicas (operator forces 1)
`spec.ols.deployment.alertsAdapter.resources` | `*ResourceRequirements` | -- | No | -- | Alerts adapter resources
`spec.ols.deployment.alertsAdapter.tolerations` | `[]Toleration` | -- | No | -- | Alerts adapter tolerations
Expand Down
Loading