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
300 changes: 300 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,56 @@ servers:

paths:
/rules:
patch:
operationId: BulkUpdateAlertRules
summary: Bulk update alert rules
description: >
Updates one or more alert rules by their stable IDs. Each rule is
updated independently; per-rule status is returned in the response
so partial success is visible to the caller.
Supports label overrides, drop/restore toggles (platform rules only),
and classification label updates.
When both classification and labels are set for a rule, classification
is applied first, then labels. These steps are not atomic: if the label
update fails after classification succeeded, the classification change
remains applied and the per-rule result reports failure.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BulkUpdateAlertRulesRequest"
responses:
"200":
description: Update results (may include per-rule errors)
content:
application/json:
schema:
$ref: "#/components/schemas/BulkUpdateAlertRulesResponse"
"400":
description: Invalid request body
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"401":
description: Missing or invalid authorization token
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"413":
description: Request body exceeds the 1 MB limit
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Unexpected server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
delete:
operationId: BulkDeleteUserDefinedAlertRules
summary: Bulk delete user-defined alert rules
Expand Down Expand Up @@ -108,6 +158,141 @@ paths:
schema:
$ref: "#/components/schemas/ErrorResponse"

/rules/{ruleId}:
parameters:
- name: ruleId
in: path
required: true
schema:
type: string
description: Stable alert rule ID.
patch:
operationId: UpdateAlertRule
summary: Update a single alert rule
description: >
Updates one alert rule by its stable ID. Supports label overrides,
drop/restore toggles (platform rules only), and classification label
updates. Same mutation semantics as BulkUpdateAlertRules for a single ID.
When both classification and labels are set, classification is applied
first, then labels. These steps are not atomic: if the label update
fails after classification succeeded, the classification change remains
applied and the request returns an error.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateAlertRuleRequest"
responses:
"200":
description: >
Update result. On success statusCode is 204; the id may differ from
the path ruleId when labels change the stable ID.
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateAlertRuleResult"
"400":
description: >
Invalid request body, blank ruleId, or invalid update fields
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"401":
description: Missing or invalid authorization token
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"403":
description: Forbidden (insufficient RBAC permissions)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Alert rule not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"405":
description: Operation not allowed (e.g. rule is externally managed)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"409":
description: Conflict (e.g. concurrent update)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"413":
description: Request body exceeds the 1 MB limit
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Unexpected server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
delete:
operationId: DeleteAlertRule
summary: Delete a single alert rule
description: >
Deletes one alert rule by its stable ID. Same mutation semantics as
BulkDeleteUserDefinedAlertRules for a single ID.
responses:
"204":
description: Alert rule deleted successfully
"400":
description: Invalid ruleId (e.g. blank after trimming)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"401":
description: Missing or invalid authorization token
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"403":
description: Forbidden (insufficient RBAC permissions)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Alert rule not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"405":
description: Operation not allowed (e.g. platform or externally managed)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"409":
description: Conflict (e.g. concurrent update)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Unexpected server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"

Comment thread
sradco marked this conversation as resolved.
components:
schemas:
AlertRuleSpec:
Expand Down Expand Up @@ -219,6 +404,121 @@ components:
$ref: "#/components/schemas/DeleteAlertRuleResult"
description: Per-rule deletion results.

AlertRuleClassificationUpdate:
type: object
description: >
Partial update for alert rule classification labels.
Each field supports three states: omitted (leave unchanged),
null (clear the override), or a string value (set the override).
The three-state semantics require a custom JSON decoder; the Go
type AlertRuleClassificationPatch is used at runtime instead of
the generated struct.
x-go-type: AlertRuleClassificationPatch
properties:
openshift_io_alert_rule_component:
type: string
nullable: true
description: Component classification label override.
openshift_io_alert_rule_layer:
type: string
nullable: true
description: Layer classification label override.
openshift_io_alert_rule_component_from:
type: string
nullable: true
description: Dynamic component source label key.
openshift_io_alert_rule_layer_from:
type: string
nullable: true
description: Dynamic layer source label key.

BulkUpdateAlertRulesRequest:
type: object
required:
- ruleIds
properties:
ruleIds:
type: array
minItems: 1
maxItems: 100
items:
type: string
description: List of stable alert rule IDs to update (at most 100 per request).
labels:
type: object
additionalProperties:
type: string
nullable: true
description: >
Label key/value pairs to set. A null or empty-string value removes
the label. Omitting this field leaves existing labels unchanged.
alertingRuleEnabled:
type: boolean
nullable: true
description: >
When false, drops the alert rule via an AlertRelabelConfig Drop
action — the rule no longer appears in Prometheus query results.
When true, restores a previously dropped rule.
Only supported for platform alert rules.
classification:
$ref: "#/components/schemas/AlertRuleClassificationUpdate"

UpdateAlertRuleRequest:
type: object
description: >
Partial update for a single alert rule. At least one of labels,
alertingRuleEnabled, or classification must be set. alertingRuleEnabled
cannot be combined with labels or classification in the same request.
properties:
labels:
type: object
additionalProperties:
type: string
nullable: true
description: >
Label key/value pairs to set. A null or empty-string value removes
the label. Omitting this field leaves existing labels unchanged.
alertingRuleEnabled:
type: boolean
nullable: true
description: >
When false, drops the alert rule via an AlertRelabelConfig Drop
action — the rule no longer appears in Prometheus query results.
When true, restores a previously dropped rule.
Only supported for platform alert rules.
classification:
$ref: "#/components/schemas/AlertRuleClassificationUpdate"

UpdateAlertRuleResult:
type: object
required:
- id
- statusCode
properties:
id:
type: string
description: The stable alert rule ID that was processed.
statusCode:
type: integer
format: int32
minimum: 100
maximum: 599
description: HTTP status code for this rule's update result.
message:
type: string
description: Error message if update failed; omitted on success.

BulkUpdateAlertRulesResponse:
type: object
required:
- rules
properties:
rules:
type: array
items:
$ref: "#/components/schemas/UpdateAlertRuleResult"
description: Per-rule update results.

ErrorResponse:
type: object
required:
Expand Down
54 changes: 54 additions & 0 deletions docs/alert-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,57 @@ OpenShift supports routing user workload alerts to:
This is a cluster configuration choice and does not change the plugin API shape. The plugin reads alerts from Alertmanager (for firing/silenced) and Prometheus (for pending), then merges platform and user workload results when available.

The plugin intentionally reads from only the in-cluster Alertmanager endpoints. Supporting multiple external Alertmanagers would introduce ambiguous alert state and silencing outcomes because each instance can apply different routing, inhibition, and silence configurations.

### Managing alert rules via the Management API

| Operation | Single | Bulk |
|---|---|---|
| Create | `POST /api/v1/alerting/rules` | n/a |
| Update (labels, drop/restore, classification) | `PATCH /api/v1/alerting/rules/{ruleId}` | `PATCH /api/v1/alerting/rules` |
| Delete | `DELETE /api/v1/alerting/rules/{ruleId}` | `DELETE /api/v1/alerting/rules` |

**Single update** (`PATCH /rules/{ruleId}`):
- Request body uses `UpdateAlertRuleRequest` (labels and/or classification, or
`alertingRuleEnabled` alone for drop/restore).
- Success: HTTP `200` with `UpdateAlertRuleResult` (`statusCode: 204`). The
returned `id` may differ from the path `ruleId` when labels change the stable ID.
- Failure: standard `ErrorResponse` with the corresponding HTTP status
(400/401/403/404/405/409/413/500). Errors include a message so callers can act on them.
- Non-atomic combined updates: when both `classification` and `labels` are set,
classification is applied first, then labels. If the label step fails, the
classification change may already be persisted and the request still returns
an error. Retry or inspect cluster state before re-applying classification.

**Bulk update** (`PATCH /rules`):
- Request body includes `ruleIds` (1–100) plus the same mutation fields.
- Always returns HTTP `200` with per-rule `statusCode`/`message` entries so
partial success is visible.
- Same non-atomic classification-then-labels behavior as single update; a failed
label step is reported on that rule's result while classification may remain.

**Single delete** (`DELETE /rules/{ruleId}`):
- Success: HTTP `204`.
- Failure: `ErrorResponse` with HTTP status (400/401/403/404/405/409/500).

**Bulk delete** (`DELETE /rules`):
- Request body includes `ruleIds`.
- Always returns HTTP `200` with per-rule results.

Comment on lines +51 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
echo '--- alerting rules paths and responses ---'
rg -n -A40 '/alerting/rules' api/openapi.yaml | head -300
echo '--- ruleIds constraints ---'
rg -n -B3 -A12 'ruleIds' api/openapi.yaml

Repository: openshift/monitoring-plugin

Length of output: 1270


🏁 Script executed:

#!/bin/bash
set -eu
echo '--- OpenAPI paths containing alert rules ---'
rg -n -i -B3 -A35 'rules' api/openapi.yaml | head -500
echo '--- response definitions and status references ---'
rg -n -i -B3 -A12 'responses:|statusCode|ErrorResponse' api/openapi.yaml | head -500

Repository: openshift/monitoring-plugin

Length of output: 28662


Document the bulk delete ruleIds limit.

The single-update and single-delete status lists match api/openapi.yaml. State that bulk delete accepts 1–100 ruleIds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/alert-management.md` around lines 51 - 77, Update the “Bulk delete”
section to state that its request body accepts 1–100 ruleIds, matching the
documented bulk update limit and API contract.

### Managing user-defined alert rules

| Rule ownership | Editable? | Classification? | Drop/Restore? |
|---|---|---|---|
| User-owned | Yes (direct PR mutation) | Yes (set labels directly) | No (ARC not supported) |
| Operator-managed | No (reconciled) | No | No |
| GitOps-managed | No (reconciled) | No | No |

**User-owned** rules can be fully edited (labels, severity, expr, annotations)
via the update API, which mutates the PrometheusRule directly.

**Operator-managed** and **GitOps-managed** user-defined rules cannot be edited
because the owning controller would reconcile the change. These alerts can only
be **silenced** via Alertmanager silences.

ARC-based operations (classification overrides, drop/restore) are not available
for any user-defined rule because the user workload stack does not process
AlertRelabelConfigs. If this capability is needed, open an RFE against CMO.
Loading