From 29f43c847ff0de479a13bccb1df248cb005e5208 Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Wed, 16 Sep 2026 11:15:42 +0200 Subject: [PATCH 1/7] Add Alert Agents api definitions --- .../DualReplica.yaml | 2890 +++++++++++++++++ etcd/v1/types_pacemakercluster.go | 200 ++ ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 224 ++ etcd/v1/zz_generated.deepcopy.go | 60 + .../DualReplica.yaml | 224 ++ etcd/v1/zz_generated.model_name.go | 10 + etcd/v1/zz_generated.swagger_doc_generated.go | 34 +- .../DualReplica.yaml | 2890 +++++++++++++++++ etcd/v1alpha1/types_pacemakercluster.go | 200 ++ ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 224 ++ etcd/v1alpha1/zz_generated.deepcopy.go | 60 + .../DualReplica.yaml | 224 ++ etcd/v1alpha1/zz_generated.model_name.go | 10 + .../zz_generated.swagger_doc_generated.go | 34 +- .../generated_openapi/zz_generated.openapi.go | 284 +- openapi/openapi.json | 168 + 16 files changed, 7720 insertions(+), 16 deletions(-) diff --git a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index dde9ce6e9f1..72c7bfc3ca9 100644 --- a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1933,3 +1933,2893 @@ tests: reason: Schedulable message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" + + - name: Should accept cluster status with alertAgents entirely absent + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept cluster status with only the Taint alert agent observed + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept an alert agent with Unknown Configured status pending observation + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + - type: Configured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + - type: Configured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept a node with alertAgentScripts entirely absent + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should reject alertAgents missing the Configured condition + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "conditions must contain a condition of type Configured" + - name: Should reject alertAgents entry missing name + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "Required value" + - name: Should reject alertAgents with duplicate names + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "alert agent names must be unique" + - name: Should reject node alertAgentScripts missing the ScriptPresent condition + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" + expectedStatusError: "conditions must contain a condition of type ScriptPresent" + - name: Should reject node alertAgentScripts with duplicate names + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Present" + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Present" + expectedStatusError: "alert agent names must be unique" diff --git a/etcd/v1/types_pacemakercluster.go b/etcd/v1/types_pacemakercluster.go index a481f5e1bd4..72bed056baf 100644 --- a/etcd/v1/types_pacemakercluster.go +++ b/etcd/v1/types_pacemakercluster.go @@ -15,6 +15,7 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) + // - AlertAgentHealthyConditionType (for each alert agent in status.alertAgents, when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -86,6 +87,7 @@ const ( // - NodeFencingAvailableConditionType // - NodeFencingHealthyConditionType // - ResourceHealthyConditionType (for each resource in the node's resources list) + // - AlertAgentScriptHealthyConditionType (for each entry in the node's alertAgentScripts list) // When True, the node is healthy with reason "NodeHealthy". // When False, the node is unhealthy with reason "NodeUnhealthy". NodeHealthyConditionType = "Healthy" @@ -398,6 +400,109 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) +// Cluster-level condition types for PacemakerCluster.status.alertAgents[].conditions +const ( + // AlertAgentHealthyConditionType tracks the overall health of a pacemaker alert agent. + // This is an aggregate condition that reflects the health of all alert agent-level conditions. + // Specifically, it aggregates the following conditions: + // - AlertAgentConfiguredConditionType + // When True, the alert agent is healthy with reason "AlertAgentHealthy". + // When False, the alert agent is unhealthy with reason "AlertAgentUnhealthy". + // When Unknown, the alert agent's health has not yet been observed by the status collector + // with reason "Pending". This is expected to be temporary. + AlertAgentHealthyConditionType = "Healthy" + + // AlertAgentConfiguredConditionType tracks whether the alert agent is registered in the CIB + // with the expected script path and event filter. + // When True, the alert agent is registered as expected with reason "Configured". + // When False, the alert agent is not registered with reason "Missing", or is registered with + // an unexpected path or filter with reason "Misconfigured". This is an unexpected state. + // When Unknown, the CIB registration has not yet been observed by the status collector with + // reason "Pending". This is expected to be temporary. + AlertAgentConfiguredConditionType = "Configured" +) + +// AlertAgentHealthy condition reasons +const ( + // AlertAgentHealthyReasonHealthy means the alert agent is healthy and operating normally. + AlertAgentHealthyReasonHealthy = "AlertAgentHealthy" + + // AlertAgentHealthyReasonUnhealthy means the alert agent has issues that need investigation. + AlertAgentHealthyReasonUnhealthy = "AlertAgentUnhealthy" + + // AlertAgentHealthyReasonPending means the alert agent's health has not yet been observed by + // the status collector. This is expected to be temporary. + AlertAgentHealthyReasonPending = "Pending" +) + +// AlertAgentConfigured condition reasons +const ( + // AlertAgentConfiguredReasonConfigured means the alert agent is registered in the CIB with the + // expected script path and event filter. This is the normal operating state. + AlertAgentConfiguredReasonConfigured = "Configured" + + // AlertAgentConfiguredReasonMissing means the alert agent is not registered in the CIB. + // This is an unexpected state. + AlertAgentConfiguredReasonMissing = "Missing" + + // AlertAgentConfiguredReasonMisconfigured means the alert agent is registered in the CIB with + // an unexpected script path or event filter. This is an unexpected state. + AlertAgentConfiguredReasonMisconfigured = "Misconfigured" + + // AlertAgentConfiguredReasonPending means the alert agent's CIB registration has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentConfiguredReasonPending = "Pending" +) + +// Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions +const ( + // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. + // This is an aggregate condition that reflects the health of all alert agent script-level conditions. + // Specifically, it aggregates the following conditions: + // - AlertAgentScriptPresentConditionType + // When True, the alert agent script is healthy with reason "AlertAgentScriptHealthy". + // When False, the alert agent script is unhealthy with reason "AlertAgentScriptUnhealthy". + // When Unknown, the script's presence has not yet been observed by the status collector with + // reason "Pending". This is expected to be temporary. + AlertAgentScriptHealthyConditionType = "Healthy" + + // AlertAgentScriptPresentConditionType tracks whether the alert agent's script file is present + // and executable on this node. + // When True, the script is present and executable with reason "Present". + // When False, the script is missing from this node with reason "Missing". This is an unexpected state. + // When Unknown, presence has not yet been observed by the status collector with reason "Pending". + // This is expected to be temporary. + AlertAgentScriptPresentConditionType = "ScriptPresent" +) + +// AlertAgentScriptHealthy condition reasons +const ( + // AlertAgentScriptHealthyReasonHealthy means the alert agent script is healthy and operating normally. + AlertAgentScriptHealthyReasonHealthy = "AlertAgentScriptHealthy" + + // AlertAgentScriptHealthyReasonUnhealthy means the alert agent script has issues that need investigation. + AlertAgentScriptHealthyReasonUnhealthy = "AlertAgentScriptUnhealthy" + + // AlertAgentScriptHealthyReasonPending means the alert agent script's health has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentScriptHealthyReasonPending = "Pending" +) + +// AlertAgentScriptPresent condition reasons +const ( + // AlertAgentScriptPresentReasonPresent means the alert agent script is present and executable on this node. + // This is the normal operating state. + AlertAgentScriptPresentReasonPresent = "Present" + + // AlertAgentScriptPresentReasonMissing means the alert agent script is missing from this node. + // This is an unexpected state that can occur when MCO has not yet delivered the script to this node. + AlertAgentScriptPresentReasonMissing = "Missing" + + // AlertAgentScriptPresentReasonPending means the script's presence on this node has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentScriptPresentReasonPending = "Pending" +) + // PacemakerNodeAddressType represents the type of a node address. // Currently only InternalIP is supported. // +kubebuilder:validation:Enum=InternalIP @@ -447,6 +552,20 @@ const ( PacemakerClusterResourceNameEtcd PacemakerClusterResourceName = "Etcd" ) +// PacemakerClusterAlertAgentName represents the name of a pacemaker alert agent. +// +kubebuilder:validation:Enum=Taint Alert Agent;Untaint Alert Agent +// +enum +type PacemakerClusterAlertAgentName string + +// PacemakerClusterAlertAgentName values +const ( + // PacemakerClusterAlertAgentNameTaint is the alert agent that taints a node after it is fenced. + PacemakerClusterAlertAgentNameTaint PacemakerClusterAlertAgentName = "Taint Alert Agent" + + // PacemakerClusterAlertAgentNameUntaint is the alert agent that removes a node's taint once it rejoins the cluster. + PacemakerClusterAlertAgentNameUntaint PacemakerClusterAlertAgentName = "Untaint Alert Agent" +) + // FencingMethod represents the method used by a fencing agent to isolate failed nodes. // Valid values are "Redfish" and "IPMI". // +kubebuilder:validation:Enum=Redfish;IPMI @@ -534,6 +653,20 @@ type PacemakerClusterStatus struct { // +kubebuilder:validation:MaxItems=5 // +required Nodes *[]PacemakerClusterNodeStatus `json:"nodes,omitempty"` + + // alertAgents contains the cluster-wide registration status of pacemaker alert + // agents used for auto-tainting nodes after fencing events. + // This field is optional and is omitted when alert agent status has not yet been + // collected by the status collector (including by a collector version that + // predates this field) or when no alert agents are configured. + // Names must be unique within this array. + // +listType=map + // +listMapKey=name + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" + // +optional + AlertAgents []PacemakerClusterAlertAgentStatus `json:"alertAgents,omitempty"` } // PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including @@ -619,6 +752,21 @@ type PacemakerClusterNodeStatus struct { // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="fencing agent names must be unique" // +required FencingAgents []PacemakerClusterFencingAgentStatus `json:"fencingAgents,omitempty"` + + // alertAgentScripts contains the presence status of each alert agent's script on + // this node. Alert agents are registered cluster-wide in the CIB, + // but their scripts are delivered independently to each node by MCO, so presence + // is tracked per node to catch delivery gaps between nodes. + // This field is optional and is omitted when script-presence status has not yet + // been collected by the status collector (including by a collector version that + // predates this field). Names must be unique within this array. + // +listType=map + // +listMapKey=name + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" + // +optional + AlertAgentScripts []PacemakerClusterAlertAgentScriptStatus `json:"alertAgentScripts,omitempty"` } // PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. @@ -718,6 +866,58 @@ type PacemakerClusterResourceStatus struct { Name PacemakerClusterResourceName `json:"name,omitempty"` } +// PacemakerClusterAlertAgentStatus represents the cluster-wide registration status +// of a pacemaker alert agent. +type PacemakerClusterAlertAgentStatus struct { + // conditions represent the observations of the alert agent's current state. + // Known condition types are "Healthy" (aggregate) and "Configured" (registered + // in the CIB with the expected script path and event filter). + // If this alert agent's state has not yet been observed by the status collector, + // publish these conditions with status "Unknown" and reason "Pending". + // Reserve "False" for an observed failure. + // Each of these conditions is required, so the array must contain at least 2 items. + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=2 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Configured')",message="conditions must contain a condition of type Configured" + // +required + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // name is the name of the pacemaker alert agent. + // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + // +required + Name PacemakerClusterAlertAgentName `json:"name,omitempty"` +} + +// PacemakerClusterAlertAgentScriptStatus represents the presence of an alert +// agent's script on a specific node. Alert agent registration is cluster-wide, +// but the script it invokes must exist locally on whichever node the triggering +// event occurs on, since Pacemaker executes it there — this is tracked per node +type PacemakerClusterAlertAgentScriptStatus struct { + // conditions represent the observations of the alert agent script's state on this node. + // Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + // file exists and is executable on this node). + // If this script's presence has not yet been observed by the status collector, publish + // these conditions with status "Unknown" and reason "Pending". + // Reserve "False" for an observed failure. + // Each of these conditions is required, so the array must contain at least 2 items. + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=2 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'ScriptPresent')",message="conditions must contain a condition of type ScriptPresent" + // +required + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // name is the name of the pacemaker alert agent this script belongs to. + // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + // +required + Name PacemakerClusterAlertAgentName `json:"name,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PacemakerClusterList contains a list of PacemakerCluster objects. PacemakerCluster is a cluster-scoped singleton // resource; only one instance named "cluster" may exist. This list type exists only to satisfy Kubernetes API diff --git a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 0cad7e278b2..d860c7f8fc1 100644 --- a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -51,6 +51,115 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: + alertAgents: + description: |- + alertAgents contains the cluster-wide registration status of pacemaker alert + agents used for auto-tainting nodes after fencing events. + This field is optional and is omitted when alert agent status has not yet been + collected by the status collector (including by a collector version that + predates this field) or when no alert agents are configured. + Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentStatus represents the cluster-wide registration status + of a pacemaker alert agent. + properties: + conditions: + description: |- + conditions represent the observations of the alert agent's current state. + Known condition types are "Healthy" (aggregate) and "Configured" (registered + in the CIB with the expected script path and event filter). + If this alert agent's state has not yet been observed by the status collector, + publish these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type Configured + rule: self.exists(c, c.type == 'Configured') + name: + description: |- + name is the name of the pacemaker alert agent. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -186,6 +295,121 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic + alertAgentScripts: + description: |- + alertAgentScripts contains the presence status of each alert agent's script on + this node. Alert agents are registered cluster-wide in the CIB, + but their scripts are delivered independently to each node by MCO, so presence + is tracked per node to catch delivery gaps between nodes. + This field is optional and is omitted when script-presence status has not yet + been collected by the status collector (including by a collector version that + predates this field). Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentScriptStatus represents the presence of an alert + agent's script on a specific node. Alert agent registration is cluster-wide, + but the script it invokes must exist locally on whichever node the triggering + event occurs on, since Pacemaker executes it there — this is tracked per node + properties: + conditions: + description: |- + conditions represent the observations of the alert agent script's state on this node. + Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + file exists and is executable on this node). + If this script's presence has not yet been observed by the status collector, publish + these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type + Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type + ScriptPresent + rule: self.exists(c, c.type == 'ScriptPresent') + name: + description: |- + name is the name of the pacemaker alert agent this script belongs to. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. diff --git a/etcd/v1/zz_generated.deepcopy.go b/etcd/v1/zz_generated.deepcopy.go index c529240e40c..c435f24bc6f 100644 --- a/etcd/v1/zz_generated.deepcopy.go +++ b/etcd/v1/zz_generated.deepcopy.go @@ -37,6 +37,52 @@ func (in *PacemakerCluster) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopyInto(out *PacemakerClusterAlertAgentScriptStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentScriptStatus. +func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAlertAgentScriptStatus { + if in == nil { + return nil + } + out := new(PacemakerClusterAlertAgentScriptStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PacemakerClusterAlertAgentStatus) DeepCopyInto(out *PacemakerClusterAlertAgentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentStatus. +func (in *PacemakerClusterAlertAgentStatus) DeepCopy() *PacemakerClusterAlertAgentStatus { + if in == nil { + return nil + } + out := new(PacemakerClusterAlertAgentStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -122,6 +168,13 @@ func (in *PacemakerClusterNodeStatus) DeepCopyInto(out *PacemakerClusterNodeStat (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.AlertAgentScripts != nil { + in, out := &in.AlertAgentScripts, &out.AlertAgentScripts + *out = make([]PacemakerClusterAlertAgentScriptStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -180,6 +233,13 @@ func (in *PacemakerClusterStatus) DeepCopyInto(out *PacemakerClusterStatus) { } } } + if in.AlertAgents != nil { + in, out := &in.AlertAgents, &out.AlertAgents + *out = make([]PacemakerClusterAlertAgentStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index c9ec52f3829..cdedbc636a7 100644 --- a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -52,6 +52,115 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: + alertAgents: + description: |- + alertAgents contains the cluster-wide registration status of pacemaker alert + agents used for auto-tainting nodes after fencing events. + This field is optional and is omitted when alert agent status has not yet been + collected by the status collector (including by a collector version that + predates this field) or when no alert agents are configured. + Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentStatus represents the cluster-wide registration status + of a pacemaker alert agent. + properties: + conditions: + description: |- + conditions represent the observations of the alert agent's current state. + Known condition types are "Healthy" (aggregate) and "Configured" (registered + in the CIB with the expected script path and event filter). + If this alert agent's state has not yet been observed by the status collector, + publish these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type Configured + rule: self.exists(c, c.type == 'Configured') + name: + description: |- + name is the name of the pacemaker alert agent. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -187,6 +296,121 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic + alertAgentScripts: + description: |- + alertAgentScripts contains the presence status of each alert agent's script on + this node. Alert agents are registered cluster-wide in the CIB, + but their scripts are delivered independently to each node by MCO, so presence + is tracked per node to catch delivery gaps between nodes. + This field is optional and is omitted when script-presence status has not yet + been collected by the status collector (including by a collector version that + predates this field). Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentScriptStatus represents the presence of an alert + agent's script on a specific node. Alert agent registration is cluster-wide, + but the script it invokes must exist locally on whichever node the triggering + event occurs on, since Pacemaker executes it there — this is tracked per node + properties: + conditions: + description: |- + conditions represent the observations of the alert agent script's state on this node. + Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + file exists and is executable on this node). + If this script's presence has not yet been observed by the status collector, publish + these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type + Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type + ScriptPresent + rule: self.exists(c, c.type == 'ScriptPresent') + name: + description: |- + name is the name of the pacemaker alert agent this script belongs to. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. diff --git a/etcd/v1/zz_generated.model_name.go b/etcd/v1/zz_generated.model_name.go index 9e13a7167e4..e7715ef8e9c 100644 --- a/etcd/v1/zz_generated.model_name.go +++ b/etcd/v1/zz_generated.model_name.go @@ -10,6 +10,16 @@ func (in PacemakerCluster) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerCluster" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { + return "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in PacemakerClusterAlertAgentStatus) OpenAPIModelName() string { + return "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1/zz_generated.swagger_doc_generated.go b/etcd/v1/zz_generated.swagger_doc_generated.go index e9e47b47cfd..56c539893bb 100644 --- a/etcd/v1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1/zz_generated.swagger_doc_generated.go @@ -21,6 +21,26 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { return map_PacemakerCluster } +var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ + "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "name": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", +} + +func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { + return map_PacemakerClusterAlertAgentScriptStatus +} + +var map_PacemakerClusterAlertAgentStatus = map[string]string{ + "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "name": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", +} + +func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { + return map_PacemakerClusterAlertAgentStatus +} + var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -43,12 +63,13 @@ func (PacemakerClusterList) SwaggerDoc() map[string]string { } var map_PacemakerClusterNodeStatus = map[string]string{ - "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", - "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", - "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", - "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", - "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", - "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", + "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", + "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", + "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", + "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", + "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", + "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -70,6 +91,7 @@ var map_PacemakerClusterStatus = map[string]string{ "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", + "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 6c919c01946..18ab32b9215 100644 --- a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1933,3 +1933,2893 @@ tests: reason: Schedulable message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" + + - name: Should accept cluster status with alertAgents entirely absent + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept cluster status with only the Taint alert agent observed + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept an alert agent with Unknown Configured status pending observation + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + - type: Configured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + - type: Configured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Pending" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept a node with alertAgentScripts entirely absent + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should reject alertAgents missing the Configured condition + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "conditions must contain a condition of type Configured" + - name: Should reject alertAgents entry missing name + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "Required value" + - name: Should reject alertAgents with duplicate names + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + expectedStatusError: "alert agent names must be unique" + - name: Should reject node alertAgentScripts missing the ScriptPresent condition + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" + expectedStatusError: "conditions must contain a condition of type ScriptPresent" + - name: Should reject node alertAgentScripts with duplicate names + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Present" + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Present" + expectedStatusError: "alert agent names must be unique" diff --git a/etcd/v1alpha1/types_pacemakercluster.go b/etcd/v1alpha1/types_pacemakercluster.go index b627413474b..a403d7c1ec8 100644 --- a/etcd/v1alpha1/types_pacemakercluster.go +++ b/etcd/v1alpha1/types_pacemakercluster.go @@ -15,6 +15,7 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) + // - AlertAgentHealthyConditionType (for each alert agent in status.alertAgents, when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -86,6 +87,7 @@ const ( // - NodeFencingAvailableConditionType // - NodeFencingHealthyConditionType // - ResourceHealthyConditionType (for each resource in the node's resources list) + // - AlertAgentScriptHealthyConditionType (for each entry in the node's alertAgentScripts list) // When True, the node is healthy with reason "NodeHealthy". // When False, the node is unhealthy with reason "NodeUnhealthy". NodeHealthyConditionType = "Healthy" @@ -398,6 +400,109 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) +// Cluster-level condition types for PacemakerCluster.status.alertAgents[].conditions +const ( + // AlertAgentHealthyConditionType tracks the overall health of a pacemaker alert agent. + // This is an aggregate condition that reflects the health of all alert agent-level conditions. + // Specifically, it aggregates the following conditions: + // - AlertAgentConfiguredConditionType + // When True, the alert agent is healthy with reason "AlertAgentHealthy". + // When False, the alert agent is unhealthy with reason "AlertAgentUnhealthy". + // When Unknown, the alert agent's health has not yet been observed by the status collector + // with reason "Pending". This is expected to be temporary. + AlertAgentHealthyConditionType = "Healthy" + + // AlertAgentConfiguredConditionType tracks whether the alert agent is registered in the CIB + // with the expected script path and event filter. + // When True, the alert agent is registered as expected with reason "Configured". + // When False, the alert agent is not registered with reason "Missing", or is registered with + // an unexpected path or filter with reason "Misconfigured". This is an unexpected state. + // When Unknown, the CIB registration has not yet been observed by the status collector with + // reason "Pending". This is expected to be temporary. + AlertAgentConfiguredConditionType = "Configured" +) + +// AlertAgentHealthy condition reasons +const ( + // AlertAgentHealthyReasonHealthy means the alert agent is healthy and operating normally. + AlertAgentHealthyReasonHealthy = "AlertAgentHealthy" + + // AlertAgentHealthyReasonUnhealthy means the alert agent has issues that need investigation. + AlertAgentHealthyReasonUnhealthy = "AlertAgentUnhealthy" + + // AlertAgentHealthyReasonPending means the alert agent's health has not yet been observed by + // the status collector. This is expected to be temporary. + AlertAgentHealthyReasonPending = "Pending" +) + +// AlertAgentConfigured condition reasons +const ( + // AlertAgentConfiguredReasonConfigured means the alert agent is registered in the CIB with the + // expected script path and event filter. This is the normal operating state. + AlertAgentConfiguredReasonConfigured = "Configured" + + // AlertAgentConfiguredReasonMissing means the alert agent is not registered in the CIB. + // This is an unexpected state. + AlertAgentConfiguredReasonMissing = "Missing" + + // AlertAgentConfiguredReasonMisconfigured means the alert agent is registered in the CIB with + // an unexpected script path or event filter. This is an unexpected state. + AlertAgentConfiguredReasonMisconfigured = "Misconfigured" + + // AlertAgentConfiguredReasonPending means the alert agent's CIB registration has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentConfiguredReasonPending = "Pending" +) + +// Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions +const ( + // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. + // This is an aggregate condition that reflects the health of all alert agent script-level conditions. + // Specifically, it aggregates the following conditions: + // - AlertAgentScriptPresentConditionType + // When True, the alert agent script is healthy with reason "AlertAgentScriptHealthy". + // When False, the alert agent script is unhealthy with reason "AlertAgentScriptUnhealthy". + // When Unknown, the script's presence has not yet been observed by the status collector with + // reason "Pending". This is expected to be temporary. + AlertAgentScriptHealthyConditionType = "Healthy" + + // AlertAgentScriptPresentConditionType tracks whether the alert agent's script file is present + // and executable on this node. + // When True, the script is present and executable with reason "Present". + // When False, the script is missing from this node with reason "Missing". This is an unexpected state. + // When Unknown, presence has not yet been observed by the status collector with reason "Pending". + // This is expected to be temporary. + AlertAgentScriptPresentConditionType = "ScriptPresent" +) + +// AlertAgentScriptHealthy condition reasons +const ( + // AlertAgentScriptHealthyReasonHealthy means the alert agent script is healthy and operating normally. + AlertAgentScriptHealthyReasonHealthy = "AlertAgentScriptHealthy" + + // AlertAgentScriptHealthyReasonUnhealthy means the alert agent script has issues that need investigation. + AlertAgentScriptHealthyReasonUnhealthy = "AlertAgentScriptUnhealthy" + + // AlertAgentScriptHealthyReasonPending means the alert agent script's health has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentScriptHealthyReasonPending = "Pending" +) + +// AlertAgentScriptPresent condition reasons +const ( + // AlertAgentScriptPresentReasonPresent means the alert agent script is present and executable on this node. + // This is the normal operating state. + AlertAgentScriptPresentReasonPresent = "Present" + + // AlertAgentScriptPresentReasonMissing means the alert agent script is missing from this node. + // This is an unexpected state that can occur when MCO has not yet delivered the script to this node. + AlertAgentScriptPresentReasonMissing = "Missing" + + // AlertAgentScriptPresentReasonPending means the script's presence on this node has not yet been + // observed by the status collector. This is expected to be temporary. + AlertAgentScriptPresentReasonPending = "Pending" +) + // PacemakerNodeAddressType represents the type of a node address. // Currently only InternalIP is supported. // +kubebuilder:validation:Enum=InternalIP @@ -447,6 +552,20 @@ const ( PacemakerClusterResourceNameEtcd PacemakerClusterResourceName = "Etcd" ) +// PacemakerClusterAlertAgentName represents the name of a pacemaker alert agent. +// +kubebuilder:validation:Enum=Taint Alert Agent;Untaint Alert Agent +// +enum +type PacemakerClusterAlertAgentName string + +// PacemakerClusterAlertAgentName values +const ( + // PacemakerClusterAlertAgentNameTaint is the alert agent that taints a node after it is fenced. + PacemakerClusterAlertAgentNameTaint PacemakerClusterAlertAgentName = "Taint Alert Agent" + + // PacemakerClusterAlertAgentNameUntaint is the alert agent that removes a node's taint once it rejoins the cluster. + PacemakerClusterAlertAgentNameUntaint PacemakerClusterAlertAgentName = "Untaint Alert Agent" +) + // FencingMethod represents the method used by a fencing agent to isolate failed nodes. // Valid values are "Redfish" and "IPMI". // +kubebuilder:validation:Enum=Redfish;IPMI @@ -534,6 +653,20 @@ type PacemakerClusterStatus struct { // +kubebuilder:validation:MaxItems=5 // +required Nodes *[]PacemakerClusterNodeStatus `json:"nodes,omitempty"` + + // alertAgents contains the cluster-wide registration status of pacemaker alert + // agents used for auto-tainting nodes after fencing events. + // This field is optional and is omitted when alert agent status has not yet been + // collected by the status collector (including by a collector version that + // predates this field) or when no alert agents are configured. + // Names must be unique within this array. + // +listType=map + // +listMapKey=name + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" + // +optional + AlertAgents []PacemakerClusterAlertAgentStatus `json:"alertAgents,omitempty"` } // PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including @@ -619,6 +752,21 @@ type PacemakerClusterNodeStatus struct { // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="fencing agent names must be unique" // +required FencingAgents []PacemakerClusterFencingAgentStatus `json:"fencingAgents,omitempty"` + + // alertAgentScripts contains the presence status of each alert agent's script on + // this node. Alert agents are registered cluster-wide in the CIB, + // but their scripts are delivered independently to each node by MCO, so presence + // is tracked per node to catch delivery gaps between nodes. + // This field is optional and is omitted when script-presence status has not yet + // been collected by the status collector (including by a collector version that + // predates this field). Names must be unique within this array. + // +listType=map + // +listMapKey=name + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" + // +optional + AlertAgentScripts []PacemakerClusterAlertAgentScriptStatus `json:"alertAgentScripts,omitempty"` } // PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. @@ -718,6 +866,58 @@ type PacemakerClusterResourceStatus struct { Name PacemakerClusterResourceName `json:"name,omitempty"` } +// PacemakerClusterAlertAgentStatus represents the cluster-wide registration status +// of a pacemaker alert agent. +type PacemakerClusterAlertAgentStatus struct { + // conditions represent the observations of the alert agent's current state. + // Known condition types are "Healthy" (aggregate) and "Configured" (registered + // in the CIB with the expected script path and event filter). + // If this alert agent's state has not yet been observed by the status collector, + // publish these conditions with status "Unknown" and reason "Pending". + // Reserve "False" for an observed failure. + // Each of these conditions is required, so the array must contain at least 2 items. + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=2 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Configured')",message="conditions must contain a condition of type Configured" + // +required + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // name is the name of the pacemaker alert agent. + // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + // +required + Name PacemakerClusterAlertAgentName `json:"name,omitempty"` +} + +// PacemakerClusterAlertAgentScriptStatus represents the presence of an alert +// agent's script on a specific node. Alert agent registration is cluster-wide, +// but the script it invokes must exist locally on whichever node the triggering +// event occurs on, since Pacemaker executes it there — this is tracked per node +type PacemakerClusterAlertAgentScriptStatus struct { + // conditions represent the observations of the alert agent script's state on this node. + // Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + // file exists and is executable on this node). + // If this script's presence has not yet been observed by the status collector, publish + // these conditions with status "Unknown" and reason "Pending". + // Reserve "False" for an observed failure. + // Each of these conditions is required, so the array must contain at least 2 items. + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=2 + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" + // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'ScriptPresent')",message="conditions must contain a condition of type ScriptPresent" + // +required + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // name is the name of the pacemaker alert agent this script belongs to. + // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + // +required + Name PacemakerClusterAlertAgentName `json:"name,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PacemakerClusterList contains a list of PacemakerCluster objects. PacemakerCluster is a cluster-scoped singleton // resource; only one instance named "cluster" may exist. This list type exists only to satisfy Kubernetes API diff --git a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index e26afefbb18..087725c7a34 100644 --- a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -51,6 +51,115 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: + alertAgents: + description: |- + alertAgents contains the cluster-wide registration status of pacemaker alert + agents used for auto-tainting nodes after fencing events. + This field is optional and is omitted when alert agent status has not yet been + collected by the status collector (including by a collector version that + predates this field) or when no alert agents are configured. + Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentStatus represents the cluster-wide registration status + of a pacemaker alert agent. + properties: + conditions: + description: |- + conditions represent the observations of the alert agent's current state. + Known condition types are "Healthy" (aggregate) and "Configured" (registered + in the CIB with the expected script path and event filter). + If this alert agent's state has not yet been observed by the status collector, + publish these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type Configured + rule: self.exists(c, c.type == 'Configured') + name: + description: |- + name is the name of the pacemaker alert agent. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -186,6 +295,121 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic + alertAgentScripts: + description: |- + alertAgentScripts contains the presence status of each alert agent's script on + this node. Alert agents are registered cluster-wide in the CIB, + but their scripts are delivered independently to each node by MCO, so presence + is tracked per node to catch delivery gaps between nodes. + This field is optional and is omitted when script-presence status has not yet + been collected by the status collector (including by a collector version that + predates this field). Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentScriptStatus represents the presence of an alert + agent's script on a specific node. Alert agent registration is cluster-wide, + but the script it invokes must exist locally on whichever node the triggering + event occurs on, since Pacemaker executes it there — this is tracked per node + properties: + conditions: + description: |- + conditions represent the observations of the alert agent script's state on this node. + Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + file exists and is executable on this node). + If this script's presence has not yet been observed by the status collector, publish + these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type + Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type + ScriptPresent + rule: self.exists(c, c.type == 'ScriptPresent') + name: + description: |- + name is the name of the pacemaker alert agent this script belongs to. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. diff --git a/etcd/v1alpha1/zz_generated.deepcopy.go b/etcd/v1alpha1/zz_generated.deepcopy.go index 17bf978510d..39f6e07ae93 100644 --- a/etcd/v1alpha1/zz_generated.deepcopy.go +++ b/etcd/v1alpha1/zz_generated.deepcopy.go @@ -37,6 +37,52 @@ func (in *PacemakerCluster) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopyInto(out *PacemakerClusterAlertAgentScriptStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentScriptStatus. +func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAlertAgentScriptStatus { + if in == nil { + return nil + } + out := new(PacemakerClusterAlertAgentScriptStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PacemakerClusterAlertAgentStatus) DeepCopyInto(out *PacemakerClusterAlertAgentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentStatus. +func (in *PacemakerClusterAlertAgentStatus) DeepCopy() *PacemakerClusterAlertAgentStatus { + if in == nil { + return nil + } + out := new(PacemakerClusterAlertAgentStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -122,6 +168,13 @@ func (in *PacemakerClusterNodeStatus) DeepCopyInto(out *PacemakerClusterNodeStat (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.AlertAgentScripts != nil { + in, out := &in.AlertAgentScripts, &out.AlertAgentScripts + *out = make([]PacemakerClusterAlertAgentScriptStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -180,6 +233,13 @@ func (in *PacemakerClusterStatus) DeepCopyInto(out *PacemakerClusterStatus) { } } } + if in.AlertAgents != nil { + in, out := &in.AlertAgents, &out.AlertAgents + *out = make([]PacemakerClusterAlertAgentStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index e867f16f114..bf5186e30bd 100644 --- a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -52,6 +52,115 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: + alertAgents: + description: |- + alertAgents contains the cluster-wide registration status of pacemaker alert + agents used for auto-tainting nodes after fencing events. + This field is optional and is omitted when alert agent status has not yet been + collected by the status collector (including by a collector version that + predates this field) or when no alert agents are configured. + Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentStatus represents the cluster-wide registration status + of a pacemaker alert agent. + properties: + conditions: + description: |- + conditions represent the observations of the alert agent's current state. + Known condition types are "Healthy" (aggregate) and "Configured" (registered + in the CIB with the expected script path and event filter). + If this alert agent's state has not yet been observed by the status collector, + publish these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type Configured + rule: self.exists(c, c.type == 'Configured') + name: + description: |- + name is the name of the pacemaker alert agent. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -187,6 +296,121 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic + alertAgentScripts: + description: |- + alertAgentScripts contains the presence status of each alert agent's script on + this node. Alert agents are registered cluster-wide in the CIB, + but their scripts are delivered independently to each node by MCO, so presence + is tracked per node to catch delivery gaps between nodes. + This field is optional and is omitted when script-presence status has not yet + been collected by the status collector (including by a collector version that + predates this field). Names must be unique within this array. + items: + description: |- + PacemakerClusterAlertAgentScriptStatus represents the presence of an alert + agent's script on a specific node. Alert agent registration is cluster-wide, + but the script it invokes must exist locally on whichever node the triggering + event occurs on, since Pacemaker executes it there — this is tracked per node + properties: + conditions: + description: |- + conditions represent the observations of the alert agent script's state on this node. + Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script + file exists and is executable on this node). + If this script's presence has not yet been observed by the status collector, publish + these conditions with status "Unknown" and reason "Pending". + Reserve "False" for an observed failure. + Each of these conditions is required, so the array must contain at least 2 items. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 2 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: conditions must contain a condition of type + Healthy + rule: self.exists(c, c.type == 'Healthy') + - message: conditions must contain a condition of type + ScriptPresent + rule: self.exists(c, c.type == 'ScriptPresent') + name: + description: |- + name is the name of the pacemaker alert agent this script belongs to. + Valid values are "Taint Alert Agent" and "Untaint Alert Agent". + enum: + - Taint Alert Agent + - Untaint Alert Agent + type: string + required: + - conditions + - name + type: object + maxItems: 8 + minItems: 0 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: alert agent names must be unique + rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. diff --git a/etcd/v1alpha1/zz_generated.model_name.go b/etcd/v1alpha1/zz_generated.model_name.go index 11fac8dad4c..f83b15bf405 100644 --- a/etcd/v1alpha1/zz_generated.model_name.go +++ b/etcd/v1alpha1/zz_generated.model_name.go @@ -10,6 +10,16 @@ func (in PacemakerCluster) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerCluster" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { + return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in PacemakerClusterAlertAgentStatus) OpenAPIModelName() string { + return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go index dc6f224288e..a33dc5be4ef 100644 --- a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go @@ -21,6 +21,26 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { return map_PacemakerCluster } +var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ + "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "name": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", +} + +func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { + return map_PacemakerClusterAlertAgentScriptStatus +} + +var map_PacemakerClusterAlertAgentStatus = map[string]string{ + "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "name": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", +} + +func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { + return map_PacemakerClusterAlertAgentStatus +} + var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -43,12 +63,13 @@ func (PacemakerClusterList) SwaggerDoc() map[string]string { } var map_PacemakerClusterNodeStatus = map[string]string{ - "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", - "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", - "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", - "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", - "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", - "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", + "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", + "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", + "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", + "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", + "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", + "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -70,6 +91,7 @@ var map_PacemakerClusterStatus = map[string]string{ "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", + "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 16f4728a9ae..3e7394578b2 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -666,6 +666,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA consolev1.Link{}.OpenAPIModelName(): schema_openshift_api_console_v1_Link(ref), consolev1.NamespaceDashboardSpec{}.OpenAPIModelName(): schema_openshift_api_console_v1_NamespaceDashboardSpec(ref), etcdv1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerCluster(ref), + etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref), + etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref), etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref), etcdv1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterList(ref), etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref), @@ -673,6 +675,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA etcdv1.PacemakerClusterStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerNodeAddress(ref), etcdv1alpha1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerCluster(ref), + etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(ref), + etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref), etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref), etcdv1alpha1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterList(ref), etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref), @@ -30094,6 +30098,98 @@ func schema_openshift_api_etcd_v1_PacemakerCluster(ref common.ReferenceCallback) } } +func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(metav1.Condition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, + }, + }, + }, + Required: []string{"conditions", "name"}, + }, + }, + Dependencies: []string{ + metav1.Condition{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(metav1.Condition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, + }, + }, + }, + Required: []string{"conditions", "name"}, + }, + }, + Dependencies: []string{ + metav1.Condition{}.OpenAPIModelName()}, + } +} + func schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -30297,12 +30393,34 @@ func schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref common.Referenc }, }, }, + "alertAgentScripts": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName()), + }, + }, + }, + }, + }, }, Required: []string{"conditions", "nodeName", "addresses", "resources", "fencingAgents"}, }, }, Dependencies: []string{ - etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, + etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, } } @@ -30409,12 +30527,34 @@ func schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref common.ReferenceCal }, }, }, + "alertAgents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName()), + }, + }, + }, + }, + }, }, Required: []string{"conditions", "lastUpdated", "nodes"}, }, }, Dependencies: []string{ - etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, + etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, } } @@ -30491,6 +30631,98 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerCluster(ref common.ReferenceCal } } +func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(metav1.Condition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, + }, + }, + }, + Required: []string{"conditions", "name"}, + }, + }, + Dependencies: []string{ + metav1.Condition{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(metav1.Condition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, + }, + }, + }, + Required: []string{"conditions", "name"}, + }, + }, + Dependencies: []string{ + metav1.Condition{}.OpenAPIModelName()}, + } +} + func schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -30694,12 +30926,34 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref common.Re }, }, }, + "alertAgentScripts": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName()), + }, + }, + }, + }, + }, }, Required: []string{"conditions", "nodeName", "addresses", "resources", "fencingAgents"}, }, }, Dependencies: []string{ - etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, + etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, } } @@ -30806,12 +31060,34 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterStatus(ref common.Refere }, }, }, + "alertAgents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName()), + }, + }, + }, + }, + }, }, Required: []string{"conditions", "lastUpdated", "nodes"}, }, }, Dependencies: []string{ - etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, + etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, } } diff --git a/openapi/openapi.json b/openapi/openapi.json index 99f806ce8fe..3277ecfa3ee 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -16758,6 +16758,66 @@ } } }, + "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus": { + "description": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + "type": "object", + "required": [ + "conditions", + "name" + ], + "properties": { + "conditions": { + "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" + }, + "x-kubernetes-list-map-keys": [ + "type" + ], + "x-kubernetes-list-type": "map" + }, + "name": { + "description": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "type": "string", + "enum": [ + "Taint Alert Agent", + "Untaint Alert Agent" + ] + } + } + }, + "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus": { + "description": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + "type": "object", + "required": [ + "conditions", + "name" + ], + "properties": { + "conditions": { + "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" + }, + "x-kubernetes-list-map-keys": [ + "type" + ], + "x-kubernetes-list-type": "map" + }, + "name": { + "description": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "type": "string", + "enum": [ + "Taint Alert Agent", + "Untaint Alert Agent" + ] + } + } + }, "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -16843,6 +16903,18 @@ }, "x-kubernetes-list-type": "atomic" }, + "alertAgentScripts": { + "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus" + }, + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, "conditions": { "description": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", "type": "array", @@ -16924,6 +16996,18 @@ "nodes" ], "properties": { + "alertAgents": { + "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus" + }, + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, "conditions": { "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "type": "array", @@ -17002,6 +17086,66 @@ } } }, + "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus": { + "description": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", + "type": "object", + "required": [ + "conditions", + "name" + ], + "properties": { + "conditions": { + "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" + }, + "x-kubernetes-list-map-keys": [ + "type" + ], + "x-kubernetes-list-type": "map" + }, + "name": { + "description": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "type": "string", + "enum": [ + "Taint Alert Agent", + "Untaint Alert Agent" + ] + } + } + }, + "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus": { + "description": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", + "type": "object", + "required": [ + "conditions", + "name" + ], + "properties": { + "conditions": { + "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" + }, + "x-kubernetes-list-map-keys": [ + "type" + ], + "x-kubernetes-list-type": "map" + }, + "name": { + "description": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "type": "string", + "enum": [ + "Taint Alert Agent", + "Untaint Alert Agent" + ] + } + } + }, "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -17087,6 +17231,18 @@ }, "x-kubernetes-list-type": "atomic" }, + "alertAgentScripts": { + "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus" + }, + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, "conditions": { "description": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", "type": "array", @@ -17168,6 +17324,18 @@ "nodes" ], "properties": { + "alertAgents": { + "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus" + }, + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, "conditions": { "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "type": "array", From 5d0274a9e2bb24482a871f696e1c7acab42c0bb5 Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Wed, 16 Sep 2026 13:52:52 +0200 Subject: [PATCH 2/7] Addressed pr review feedback --- .golangci.yaml | 4 +- etcd/README.md | 54 +- .../DualReplica.yaml | 512 ++++++++++++++++++ etcd/v1/types_pacemakercluster.go | 12 +- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 12 +- .../DualReplica.yaml | 12 +- etcd/v1/zz_generated.swagger_doc_generated.go | 12 +- .../DualReplica.yaml | 512 ++++++++++++++++++ etcd/v1alpha1/types_pacemakercluster.go | 12 +- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 12 +- .../DualReplica.yaml | 12 +- .../zz_generated.swagger_doc_generated.go | 12 +- .../generated_openapi/zz_generated.openapi.go | 24 +- openapi/openapi.json | 24 +- 14 files changed, 1157 insertions(+), 69 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 1b8472410f5..986c636e541 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -119,8 +119,8 @@ linters: - kubeapilinter # PacemakerCluster intentionally marks Conditions as required with XValidation rules # to enforce specific condition types are always present. - path: etcd/v1/types_pacemakercluster.go - text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus) is missing the following markers: optional" + path: etcd/v1/types_pacemakercluster.go|etcd/v1alpha1/types_pacemakercluster.go + text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus|PacemakerClusterAlertAgentStatus|PacemakerClusterAlertAgentScriptStatus) is missing the following markers: optional" - linters: - kubeapilinter path: features|payload-command/ diff --git a/etcd/README.md b/etcd/README.md index b92d553df7e..3d325f9e8a8 100644 --- a/etcd/README.md +++ b/etcd/README.md @@ -54,6 +54,11 @@ status: # Optional on creation, populated via status subresou - type: InService - type: NodeCountAsExpected lastUpdated: # Required when status present, cannot decrease + alertAgents: # Optional: cluster-wide alert agent registration (0-8 items) + - name: # "Taint Alert Agent" or "Untaint Alert Agent" + conditions: # Required: Alert agent-level conditions (min 2 items) + - type: Healthy + - type: Configured nodes: # Control-plane nodes (0-5, expects 2 for TNF) - nodeName: # RFC 1123 subdomain name addresses: # Required: List of node addresses (1-8 items) @@ -86,6 +91,11 @@ status: # Optional on creation, populated via status subresou - name: # e.g., "master-0_redfish" (unique, max 300 chars) method: # Fencing method: "Redfish" or "IPMI" conditions: [...] # Same 8 conditions as resources (abbreviated) + alertAgentScripts: # Optional: per-node alert agent script presence (0-8 items) + - name: # "Taint Alert Agent" or "Untaint Alert Agent" + conditions: # Required: Alert agent script-level conditions (min 2 items) + - type: Healthy + - type: ScriptPresent ``` ### Fencing Agents @@ -104,6 +114,22 @@ Unlike regular pacemaker resources (Kubelet, Etcd), fencing agents are tracked s - **FencingAvailable**: True if at least one agent is healthy (fencing works), False if all agents unhealthy (degrades operator) - **FencingHealthy**: True if all agents are healthy (ideal state), False if any agent is unhealthy (emits warning events) +### Alert Agents + +Alert agents are pacemaker alert handlers used to automatically taint a node after it is fenced, and remove +that taint once the node rejoins the cluster. There are two known alert agents: "Taint Alert Agent" and +"Untaint Alert Agent". Unlike resources and fencing agents, alert agents are registered cluster-wide (a single +CIB object shared by all nodes via Pacemaker's CIB replication), so their registration status is tracked once +in `status.alertAgents` rather than per node. + +The script each alert agent invokes, however, must exist locally on whichever node the triggering event +occurs on, since Pacemaker executes it there. Script delivery is handled independently per node by MCO, so +presence is tracked per node in `status.nodes[].alertAgentScripts` to catch delivery gaps between nodes. + +Both `alertAgents` and `alertAgentScripts` are optional fields. They are omitted when this status has not yet +been collected by the status collector (including by a collector version that predates these fields), and +`alertAgents` is additionally omitted when no alert agents are configured. + ### Cluster-Level Conditions | Condition | True | False | @@ -141,6 +167,24 @@ Each resource in the `resources` array and each fencing agent in the `fencingAge | `Started` | Resource is started (`Started`) | Resource is stopped (`Stopped`) | | `Schedulable` | Resource is schedulable (`Schedulable`) | Resource is not schedulable (`Unschedulable`) | +### Alert Agent Conditions + +Each entry in the `alertAgents` array has its own conditions. + +| Condition | True | False | Unknown | +|-----------|------|-------|---------| +| `Healthy` | Alert agent is healthy (`AlertAgentHealthy`) | Alert agent has issues (`AlertAgentUnhealthy`) | Not yet observed (`Pending`) | +| `Configured` | Registered in the CIB as expected (`Configured`) | Not registered (`Missing`) or registered with an unexpected path/filter (`Misconfigured`) | Not yet observed (`Pending`) | + +### Alert Agent Script Conditions + +Each entry in a node's `alertAgentScripts` array has its own conditions. + +| Condition | True | False | Unknown | +|-----------|------|-------|---------| +| `Healthy` | Alert agent script is healthy (`AlertAgentScriptHealthy`) | Alert agent script has issues (`AlertAgentScriptUnhealthy`) | Not yet observed (`Pending`) | +| `ScriptPresent` | Script is present and executable on this node (`Present`) | Script is missing from this node (`Missing`) | Not yet observed (`Pending`) | + ### Validation Rules **Resource naming:** @@ -170,10 +214,11 @@ Each resource in the `resources` array and each fencing agent in the `fencingAge **Status fields:** - `status` - Optional on creation (pointer type), populated via status subresource -- When status is present, all fields within are required: +- When status is present, `conditions`, `lastUpdated`, and `nodes` are required; `alertAgents` is optional: - `conditions` - Required array of cluster conditions (min 3 items) - `lastUpdated` - Required timestamp for staleness detection - `nodes` - Required array of control-plane node statuses (min 0, max 5; empty allowed for catastrophic failures) + - `alertAgents` - Optional array of cluster-wide alert agent registration status (min 0, max 8 items); omitted when not yet collected or when no alert agents are configured **Node fields (when node present):** - `nodeName` - Required, RFC 1123 subdomain @@ -181,15 +226,22 @@ Each resource in the `resources` array and each fencing agent in the `fencingAge - `conditions` - Required (min 9 items with specific types enforced via XValidation) - `resources` - Required (min 2 items: Kubelet and Etcd) - `fencingAgents` - Required (min 1, max 8 items) +- `alertAgentScripts` - Optional (min 0, max 8 items); omitted when not yet collected by the status collector **Conditions validation:** - Cluster-level: MinItems=3 (Healthy, InService, NodeCountAsExpected) - Node-level: MinItems=9 (Healthy, Online, InService, Active, Ready, Clean, Member, FencingAvailable, FencingHealthy) - Resource-level: MinItems=8 (Healthy, InService, Managed, Enabled, Operational, Active, Started, Schedulable) - Fencing agent-level: MinItems=8 (same conditions as resources) +- Alert agent-level: MinItems=2, MaxItems=8 (Healthy, Configured) +- Alert agent script-level: MinItems=2, MaxItems=8 (Healthy, ScriptPresent) All condition arrays have XValidation rules to ensure specific condition types are present. +**Alert agent names:** +- Valid values are: `Taint Alert Agent`, `Untaint Alert Agent` +- Names must be unique within the `alertAgents` and `alertAgentScripts` arrays (enforced via XValidation), but neither array requires both names to be present + **Resource names:** - Valid values are: `Kubelet`, `Etcd` - Both resources must be present in each node's `resources` array diff --git a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 72c7bfc3ca9..cf944e0f303 100644 --- a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -3684,6 +3684,518 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: Should accept a node with alertAgentScripts fully populated + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" - name: Should reject alertAgents missing the Configured condition initial: | apiVersion: etcd.openshift.io/v1 diff --git a/etcd/v1/types_pacemakercluster.go b/etcd/v1/types_pacemakercluster.go index 72bed056baf..ef613464821 100644 --- a/etcd/v1/types_pacemakercluster.go +++ b/etcd/v1/types_pacemakercluster.go @@ -659,6 +659,7 @@ type PacemakerClusterStatus struct { // This field is optional and is omitted when alert agent status has not yet been // collected by the status collector (including by a collector version that // predates this field) or when no alert agents are configured. + // When present, this array contains at most 8 entries. // Names must be unique within this array. // +listType=map // +listMapKey=name @@ -759,7 +760,8 @@ type PacemakerClusterNodeStatus struct { // is tracked per node to catch delivery gaps between nodes. // This field is optional and is omitted when script-presence status has not yet // been collected by the status collector (including by a collector version that - // predates this field). Names must be unique within this array. + // predates this field). When present, this array contains at most 8 entries. + // Names must be unique within this array. // +listType=map // +listMapKey=name // +kubebuilder:validation:MinItems=0 @@ -875,7 +877,7 @@ type PacemakerClusterAlertAgentStatus struct { // If this alert agent's state has not yet been observed by the status collector, // publish these conditions with status "Unknown" and reason "Pending". // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 items. + // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=2 @@ -885,7 +887,7 @@ type PacemakerClusterAlertAgentStatus struct { // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker alert agent. + // name is the name of the pacemaker alert agent. This field is required. // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". // +required Name PacemakerClusterAlertAgentName `json:"name,omitempty"` @@ -902,7 +904,7 @@ type PacemakerClusterAlertAgentScriptStatus struct { // If this script's presence has not yet been observed by the status collector, publish // these conditions with status "Unknown" and reason "Pending". // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 items. + // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=2 @@ -912,7 +914,7 @@ type PacemakerClusterAlertAgentScriptStatus struct { // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker alert agent this script belongs to. + // name is the name of the pacemaker alert agent this script belongs to. This field is required. // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". // +required Name PacemakerClusterAlertAgentName `json:"name,omitempty"` diff --git a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index d860c7f8fc1..2c6fba1f76b 100644 --- a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -58,6 +58,7 @@ spec: This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. + When present, this array contains at most 8 entries. Names must be unique within this array. items: description: |- @@ -72,7 +73,7 @@ spec: If this alert agent's state has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -141,7 +142,7 @@ spec: rule: self.exists(c, c.type == 'Configured') name: description: |- - name is the name of the pacemaker alert agent. + name is the name of the pacemaker alert agent. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent @@ -303,7 +304,8 @@ spec: is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that - predates this field). Names must be unique within this array. + predates this field). When present, this array contains at most 8 entries. + Names must be unique within this array. items: description: |- PacemakerClusterAlertAgentScriptStatus represents the presence of an alert @@ -319,7 +321,7 @@ spec: If this script's presence has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -391,7 +393,7 @@ spec: rule: self.exists(c, c.type == 'ScriptPresent') name: description: |- - name is the name of the pacemaker alert agent this script belongs to. + name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent diff --git a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index cdedbc636a7..8bbbec570e7 100644 --- a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -59,6 +59,7 @@ spec: This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. + When present, this array contains at most 8 entries. Names must be unique within this array. items: description: |- @@ -73,7 +74,7 @@ spec: If this alert agent's state has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -142,7 +143,7 @@ spec: rule: self.exists(c, c.type == 'Configured') name: description: |- - name is the name of the pacemaker alert agent. + name is the name of the pacemaker alert agent. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent @@ -304,7 +305,8 @@ spec: is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that - predates this field). Names must be unique within this array. + predates this field). When present, this array contains at most 8 entries. + Names must be unique within this array. items: description: |- PacemakerClusterAlertAgentScriptStatus represents the presence of an alert @@ -320,7 +322,7 @@ spec: If this script's presence has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -392,7 +394,7 @@ spec: rule: self.exists(c, c.type == 'ScriptPresent') name: description: |- - name is the name of the pacemaker alert agent this script belongs to. + name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent diff --git a/etcd/v1/zz_generated.swagger_doc_generated.go b/etcd/v1/zz_generated.swagger_doc_generated.go index 56c539893bb..e56cf680030 100644 --- a/etcd/v1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1/zz_generated.swagger_doc_generated.go @@ -23,8 +23,8 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", - "name": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", + "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", + "name": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", } func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { @@ -33,8 +33,8 @@ func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterAlertAgentStatus = map[string]string{ "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", - "name": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", + "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", + "name": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", } func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { @@ -69,7 +69,7 @@ var map_PacemakerClusterNodeStatus = map[string]string{ "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", - "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -91,7 +91,7 @@ var map_PacemakerClusterStatus = map[string]string{ "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", - "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 18ab32b9215..67d473d17aa 100644 --- a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -3684,6 +3684,518 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: Should accept a node with alertAgentScripts fully populated + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + lastUpdated: "2024-01-01T00:00:01Z" + alertAgents: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentHealthy + message: "Healthy" + - type: Configured + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Configured + message: "Configured" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" - name: Should reject alertAgents missing the Configured condition initial: | apiVersion: etcd.openshift.io/v1alpha1 diff --git a/etcd/v1alpha1/types_pacemakercluster.go b/etcd/v1alpha1/types_pacemakercluster.go index a403d7c1ec8..7d0bb70c724 100644 --- a/etcd/v1alpha1/types_pacemakercluster.go +++ b/etcd/v1alpha1/types_pacemakercluster.go @@ -659,6 +659,7 @@ type PacemakerClusterStatus struct { // This field is optional and is omitted when alert agent status has not yet been // collected by the status collector (including by a collector version that // predates this field) or when no alert agents are configured. + // When present, this array contains at most 8 entries. // Names must be unique within this array. // +listType=map // +listMapKey=name @@ -759,7 +760,8 @@ type PacemakerClusterNodeStatus struct { // is tracked per node to catch delivery gaps between nodes. // This field is optional and is omitted when script-presence status has not yet // been collected by the status collector (including by a collector version that - // predates this field). Names must be unique within this array. + // predates this field). When present, this array contains at most 8 entries. + // Names must be unique within this array. // +listType=map // +listMapKey=name // +kubebuilder:validation:MinItems=0 @@ -875,7 +877,7 @@ type PacemakerClusterAlertAgentStatus struct { // If this alert agent's state has not yet been observed by the status collector, // publish these conditions with status "Unknown" and reason "Pending". // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 items. + // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=2 @@ -885,7 +887,7 @@ type PacemakerClusterAlertAgentStatus struct { // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker alert agent. + // name is the name of the pacemaker alert agent. This field is required. // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". // +required Name PacemakerClusterAlertAgentName `json:"name,omitempty"` @@ -902,7 +904,7 @@ type PacemakerClusterAlertAgentScriptStatus struct { // If this script's presence has not yet been observed by the status collector, publish // these conditions with status "Unknown" and reason "Pending". // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 items. + // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=2 @@ -912,7 +914,7 @@ type PacemakerClusterAlertAgentScriptStatus struct { // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker alert agent this script belongs to. + // name is the name of the pacemaker alert agent this script belongs to. This field is required. // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". // +required Name PacemakerClusterAlertAgentName `json:"name,omitempty"` diff --git a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 087725c7a34..43bf95579c7 100644 --- a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -58,6 +58,7 @@ spec: This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. + When present, this array contains at most 8 entries. Names must be unique within this array. items: description: |- @@ -72,7 +73,7 @@ spec: If this alert agent's state has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -141,7 +142,7 @@ spec: rule: self.exists(c, c.type == 'Configured') name: description: |- - name is the name of the pacemaker alert agent. + name is the name of the pacemaker alert agent. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent @@ -303,7 +304,8 @@ spec: is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that - predates this field). Names must be unique within this array. + predates this field). When present, this array contains at most 8 entries. + Names must be unique within this array. items: description: |- PacemakerClusterAlertAgentScriptStatus represents the presence of an alert @@ -319,7 +321,7 @@ spec: If this script's presence has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -391,7 +393,7 @@ spec: rule: self.exists(c, c.type == 'ScriptPresent') name: description: |- - name is the name of the pacemaker alert agent this script belongs to. + name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent diff --git a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index bf5186e30bd..ef0c5a7d523 100644 --- a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -59,6 +59,7 @@ spec: This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. + When present, this array contains at most 8 entries. Names must be unique within this array. items: description: |- @@ -73,7 +74,7 @@ spec: If this alert agent's state has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -142,7 +143,7 @@ spec: rule: self.exists(c, c.type == 'Configured') name: description: |- - name is the name of the pacemaker alert agent. + name is the name of the pacemaker alert agent. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent @@ -304,7 +305,8 @@ spec: is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that - predates this field). Names must be unique within this array. + predates this field). When present, this array contains at most 8 entries. + Names must be unique within this array. items: description: |- PacemakerClusterAlertAgentScriptStatus represents the presence of an alert @@ -320,7 +322,7 @@ spec: If this script's presence has not yet been observed by the status collector, publish these conditions with status "Unknown" and reason "Pending". Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 items. + Each of these conditions is required, so the array must contain at least 2 and at most 8 items. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -392,7 +394,7 @@ spec: rule: self.exists(c, c.type == 'ScriptPresent') name: description: |- - name is the name of the pacemaker alert agent this script belongs to. + name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are "Taint Alert Agent" and "Untaint Alert Agent". enum: - Taint Alert Agent diff --git a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go index a33dc5be4ef..f8ca49c326d 100644 --- a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go @@ -23,8 +23,8 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", - "name": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", + "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", + "name": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", } func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { @@ -33,8 +33,8 @@ func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterAlertAgentStatus = map[string]string{ "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", - "name": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", + "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", + "name": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", } func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { @@ -69,7 +69,7 @@ var map_PacemakerClusterNodeStatus = map[string]string{ "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", - "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -91,7 +91,7 @@ var map_PacemakerClusterStatus = map[string]string{ "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", - "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 3e7394578b2..884aa2854dc 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -30115,7 +30115,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref com }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30129,7 +30129,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref com }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Description: "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", Type: []string{"string"}, Format: "", Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, @@ -30161,7 +30161,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref common.Re }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30175,7 +30175,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref common.Re }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Description: "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", Type: []string{"string"}, Format: "", Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, @@ -30403,7 +30403,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref common.Referenc }, }, SchemaProps: spec.SchemaProps{ - Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30537,7 +30537,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30648,7 +30648,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(r }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30662,7 +30662,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(r }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Description: "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", Type: []string{"string"}, Format: "", Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, @@ -30694,7 +30694,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref com }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30708,7 +30708,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref com }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + Description: "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", Type: []string{"string"}, Format: "", Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, @@ -30936,7 +30936,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref common.Re }, }, SchemaProps: spec.SchemaProps{ - Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -31070,7 +31070,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterStatus(ref common.Refere }, }, SchemaProps: spec.SchemaProps{ - Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index 3277ecfa3ee..932b5eb131e 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -16767,7 +16767,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", "type": "array", "items": { "default": {}, @@ -16779,7 +16779,7 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "description": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", "type": "string", "enum": [ "Taint Alert Agent", @@ -16797,7 +16797,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", "type": "array", "items": { "default": {}, @@ -16809,7 +16809,7 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "description": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", "type": "string", "enum": [ "Taint Alert Agent", @@ -16904,7 +16904,7 @@ "x-kubernetes-list-type": "atomic" }, "alertAgentScripts": { - "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", "type": "array", "items": { "default": {}, @@ -16997,7 +16997,7 @@ ], "properties": { "alertAgents": { - "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", "type": "array", "items": { "default": {}, @@ -17095,7 +17095,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", "type": "array", "items": { "default": {}, @@ -17107,7 +17107,7 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker alert agent this script belongs to. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "description": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", "type": "string", "enum": [ "Taint Alert Agent", @@ -17125,7 +17125,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 items.", + "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", "type": "array", "items": { "default": {}, @@ -17137,7 +17137,7 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker alert agent. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", + "description": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", "type": "string", "enum": [ "Taint Alert Agent", @@ -17232,7 +17232,7 @@ "x-kubernetes-list-type": "atomic" }, "alertAgentScripts": { - "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). Names must be unique within this array.", + "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", "type": "array", "items": { "default": {}, @@ -17325,7 +17325,7 @@ ], "properties": { "alertAgents": { - "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. Names must be unique within this array.", + "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", "type": "array", "items": { "default": {}, From 81f3674fc4e6b9401c2fc9a7d3dd7b5a58c8e70b Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Thu, 17 Sep 2026 18:13:41 +0200 Subject: [PATCH 3/7] Addressed PR comments and reduced custom fields count --- .golangci.yaml | 2 +- etcd/README.md | 46 +- .../DualReplica.yaml | 2827 +++++------------ etcd/v1/types_pacemakercluster.go | 138 +- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 116 +- etcd/v1/zz_generated.deepcopy.go | 30 - .../DualReplica.yaml | 116 +- etcd/v1/zz_generated.model_name.go | 5 - etcd/v1/zz_generated.swagger_doc_generated.go | 13 +- .../DualReplica.yaml | 2827 +++++------------ etcd/v1alpha1/types_pacemakercluster.go | 138 +- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 116 +- etcd/v1alpha1/zz_generated.deepcopy.go | 30 - .../DualReplica.yaml | 116 +- etcd/v1alpha1/zz_generated.model_name.go | 5 - .../zz_generated.swagger_doc_generated.go | 13 +- .../generated_openapi/zz_generated.openapi.go | 146 +- openapi/openapi.json | 88 +- 18 files changed, 1731 insertions(+), 5041 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 986c636e541..45fbb8408ec 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -120,7 +120,7 @@ linters: # PacemakerCluster intentionally marks Conditions as required with XValidation rules # to enforce specific condition types are always present. path: etcd/v1/types_pacemakercluster.go|etcd/v1alpha1/types_pacemakercluster.go - text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus|PacemakerClusterAlertAgentStatus|PacemakerClusterAlertAgentScriptStatus) is missing the following markers: optional" + text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus|PacemakerClusterAlertAgentScriptStatus) is missing the following markers: optional" - linters: - kubeapilinter path: features|payload-command/ diff --git a/etcd/README.md b/etcd/README.md index 3d325f9e8a8..4b434d65da4 100644 --- a/etcd/README.md +++ b/etcd/README.md @@ -53,12 +53,8 @@ status: # Optional on creation, populated via status subresou - type: Healthy - type: InService - type: NodeCountAsExpected + - type: AlertAgentsConfigured # Optional 4th condition: cluster-wide alert agent CIB registration lastUpdated: # Required when status present, cannot decrease - alertAgents: # Optional: cluster-wide alert agent registration (0-8 items) - - name: # "Taint Alert Agent" or "Untaint Alert Agent" - conditions: # Required: Alert agent-level conditions (min 2 items) - - type: Healthy - - type: Configured nodes: # Control-plane nodes (0-5, expects 2 for TNF) - nodeName: # RFC 1123 subdomain name addresses: # Required: List of node addresses (1-8 items) @@ -119,24 +115,25 @@ Unlike regular pacemaker resources (Kubelet, Etcd), fencing agents are tracked s Alert agents are pacemaker alert handlers used to automatically taint a node after it is fenced, and remove that taint once the node rejoins the cluster. There are two known alert agents: "Taint Alert Agent" and "Untaint Alert Agent". Unlike resources and fencing agents, alert agents are registered cluster-wide (a single -CIB object shared by all nodes via Pacemaker's CIB replication), so their registration status is tracked once -in `status.alertAgents` rather than per node. +CIB object shared by all nodes via Pacemaker's CIB replication), so their registration status is tracked once, +as the aggregate `AlertAgentsConfigured` condition on `status.conditions`. The script each alert agent invokes, however, must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there. Script delivery is handled independently per node by MCO, so presence is tracked per node in `status.nodes[].alertAgentScripts` to catch delivery gaps between nodes. -Both `alertAgents` and `alertAgentScripts` are optional fields. They are omitted when this status has not yet -been collected by the status collector (including by a collector version that predates these fields), and -`alertAgents` is additionally omitted when no alert agents are configured. +The `AlertAgentsConfigured` condition and `alertAgentScripts` are both optional. They are omitted, or reported +`Unknown`/`Pending`, when this status has not yet been collected by the status collector, including by a +collector version that predates them. ### Cluster-Level Conditions -| Condition | True | False | -|-----------|------|-------| -| `Healthy` | Cluster is healthy (`ClusterHealthy`) | Cluster has issues (`ClusterUnhealthy`) | -| `InService` | In service (`InService`) | In maintenance (`InMaintenance`) | -| `NodeCountAsExpected` | Node count is as expected (`AsExpected`) | Wrong count (`InsufficientNodes`, `ExcessiveNodes`) | +| Condition | True | False | Unknown | +|-----------|------|-------|---------| +| `Healthy` | Cluster is healthy (`ClusterHealthy`) | Cluster has issues (`ClusterUnhealthy`) | n/a | +| `InService` | In service (`InService`) | In maintenance (`InMaintenance`) | n/a | +| `NodeCountAsExpected` | Node count is as expected (`AsExpected`) | Wrong count (`InsufficientNodes`, `ExcessiveNodes`) | n/a | +| `AlertAgentsConfigured` (optional) | All known alert agents registered in the CIB as expected (`Configured`) | At least one agent not registered (`Missing`) or misconfigured (`Misconfigured`) | Not yet observed this run (`Pending`) | ### Node-Level Conditions @@ -167,15 +164,6 @@ Each resource in the `resources` array and each fencing agent in the `fencingAge | `Started` | Resource is started (`Started`) | Resource is stopped (`Stopped`) | | `Schedulable` | Resource is schedulable (`Schedulable`) | Resource is not schedulable (`Unschedulable`) | -### Alert Agent Conditions - -Each entry in the `alertAgents` array has its own conditions. - -| Condition | True | False | Unknown | -|-----------|------|-------|---------| -| `Healthy` | Alert agent is healthy (`AlertAgentHealthy`) | Alert agent has issues (`AlertAgentUnhealthy`) | Not yet observed (`Pending`) | -| `Configured` | Registered in the CIB as expected (`Configured`) | Not registered (`Missing`) or registered with an unexpected path/filter (`Misconfigured`) | Not yet observed (`Pending`) | - ### Alert Agent Script Conditions Each entry in a node's `alertAgentScripts` array has its own conditions. @@ -214,11 +202,10 @@ Each entry in a node's `alertAgentScripts` array has its own conditions. **Status fields:** - `status` - Optional on creation (pointer type), populated via status subresource -- When status is present, `conditions`, `lastUpdated`, and `nodes` are required; `alertAgents` is optional: - - `conditions` - Required array of cluster conditions (min 3 items) +- When status is present, `conditions`, `lastUpdated`, and `nodes` are required: + - `conditions` - Required array of cluster conditions (min 3 items: Healthy, InService, NodeCountAsExpected); the optional 4th `AlertAgentsConfigured` condition may also be present - `lastUpdated` - Required timestamp for staleness detection - `nodes` - Required array of control-plane node statuses (min 0, max 5; empty allowed for catastrophic failures) - - `alertAgents` - Optional array of cluster-wide alert agent registration status (min 0, max 8 items); omitted when not yet collected or when no alert agents are configured **Node fields (when node present):** - `nodeName` - Required, RFC 1123 subdomain @@ -229,18 +216,17 @@ Each entry in a node's `alertAgentScripts` array has its own conditions. - `alertAgentScripts` - Optional (min 0, max 8 items); omitted when not yet collected by the status collector **Conditions validation:** -- Cluster-level: MinItems=3 (Healthy, InService, NodeCountAsExpected) +- Cluster-level: MinItems=3 (Healthy, InService, NodeCountAsExpected); the optional `AlertAgentsConfigured` condition is not required by XValidation - Node-level: MinItems=9 (Healthy, Online, InService, Active, Ready, Clean, Member, FencingAvailable, FencingHealthy) - Resource-level: MinItems=8 (Healthy, InService, Managed, Enabled, Operational, Active, Started, Schedulable) - Fencing agent-level: MinItems=8 (same conditions as resources) -- Alert agent-level: MinItems=2, MaxItems=8 (Healthy, Configured) - Alert agent script-level: MinItems=2, MaxItems=8 (Healthy, ScriptPresent) All condition arrays have XValidation rules to ensure specific condition types are present. **Alert agent names:** - Valid values are: `Taint Alert Agent`, `Untaint Alert Agent` -- Names must be unique within the `alertAgents` and `alertAgentScripts` arrays (enforced via XValidation), but neither array requires both names to be present +- Names must be unique within the `alertAgentScripts` array (enforced via XValidation); the array does not require both names to be present **Resource names:** - Valid values are: `Kubelet`, `Etcd` diff --git a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index cf944e0f303..0c7714ed191 100644 --- a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1934,2016 +1934,857 @@ tests: message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" - - name: Should accept cluster status with alertAgents entirely absent + - name: Should accept cluster status with AlertAgentsConfigured Unknown pending observation initial: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: name: cluster updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Alert agent registration has not yet been observed by the status collector" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy + reason: Managed + message: "Managed" + - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService + reason: Enabled + message: "Enabled" + - type: Operational status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected + reason: Operational + message: "Operational" + - type: Active status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept cluster status with only the Taint alert agent observed - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept an alert agent with Unknown Configured status pending observation - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy + reason: Managed + message: "Managed" + - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService + reason: Enabled + message: "Enabled" + - type: Operational status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected + reason: Operational + message: "Operational" + - type: Active status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - - type: Configured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Alert agent registration has not yet been observed by the status collector" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - - type: Configured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts entirely absent - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts fully populated + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept cluster status with AlertAgentsConfigured False Missing initial: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: name: cluster updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "False" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Missing + message: "tnf-untaint-alert is not registered in the CIB" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" expected: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "False" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Missing + message: "tnf-untaint-alert is not registered in the CIB" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept a node with alertAgentScripts entirely absent + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: @@ -3966,31 +2807,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4171,38 +2987,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Should reject alertAgents missing the Configured condition - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | + expected: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: @@ -4225,19 +3010,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Extra - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Extra - message: "Placeholder" nodes: - nodeName: master-0.example.com addresses: @@ -4418,8 +3190,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "conditions must contain a condition of type Configured" - - name: Should reject alertAgents entry missing name + - name: Should accept a node with alertAgentScripts fully populated initial: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster @@ -4448,19 +3219,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4641,14 +3399,32 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "Required value" - - name: Should reject alertAgents with duplicate names - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + expected: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: @@ -4671,31 +3447,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4876,7 +3627,31 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "alert agent names must be unique" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" - name: Should reject node alertAgentScripts missing the ScriptPresent condition initial: | apiVersion: etcd.openshift.io/v1 diff --git a/etcd/v1/types_pacemakercluster.go b/etcd/v1/types_pacemakercluster.go index ef613464821..c02f6351b7f 100644 --- a/etcd/v1/types_pacemakercluster.go +++ b/etcd/v1/types_pacemakercluster.go @@ -15,7 +15,7 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) - // - AlertAgentHealthyConditionType (for each alert agent in status.alertAgents, when populated) + // - ClusterAlertAgentsConfiguredConditionType (when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -31,6 +31,42 @@ const ( // When True, the expected number of nodes are present with reason "AsExpected". // When False, the node count is incorrect with reason "InsufficientNodes" or "ExcessiveNodes". ClusterNodeCountAsExpectedConditionType = "NodeCountAsExpected" + + // ClusterAlertAgentsConfiguredConditionType tracks whether all known pacemaker alert agents + // (tnf-taint-alert, tnf-untaint-alert) are registered in the CIB with the expected script path + // and event filter. Alert agents are cluster-wide CIB objects: a single registration is shared + // by all nodes via Pacemaker's CIB replication, unlike fencing agents and resources which are + // node-scoped, so this is a single aggregate condition. + // When True, all known alert agents are registered as expected with reason "Configured". + // When False, at least one alert agent is not registered with reason "Missing", or all are + // registered but at least one has an unexpected script path or event filter with reason + // "Misconfigured" (Missing takes priority over Misconfigured when both problems exist across + // different agents). The message names the specific agent(s) affected. + // When Unknown, alert agent registration has not yet been observed this run by the status + // collector with reason "Pending". This is expected to be temporary, e.g. immediately after + // upgrade or before the first successful CIB collection completes. + ClusterAlertAgentsConfiguredConditionType = "AlertAgentsConfigured" +) + +// ClusterAlertAgentsConfigured condition reasons +const ( + // ClusterAlertAgentsConfiguredReasonConfigured means all known alert agents are registered in + // the CIB with the expected script path and event filter. This is the normal operating state. + ClusterAlertAgentsConfiguredReasonConfigured = "Configured" + + // ClusterAlertAgentsConfiguredReasonMissing means at least one known alert agent is not + // registered in the CIB at all. This is an unexpected state and takes priority over + // Misconfigured when both problems exist across different agents. + ClusterAlertAgentsConfiguredReasonMissing = "Missing" + + // ClusterAlertAgentsConfiguredReasonMisconfigured means every known alert agent is registered, + // but at least one has an unexpected script path or event filter. This is an unexpected state. + ClusterAlertAgentsConfiguredReasonMisconfigured = "Misconfigured" + + // ClusterAlertAgentsConfiguredReasonPending means alert agent registration has not yet been + // observed this run by the status collector. Used only with status "Unknown". This is expected + // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. + ClusterAlertAgentsConfiguredReasonPending = "Pending" ) // ClusterHealthy condition reasons @@ -400,60 +436,6 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) -// Cluster-level condition types for PacemakerCluster.status.alertAgents[].conditions -const ( - // AlertAgentHealthyConditionType tracks the overall health of a pacemaker alert agent. - // This is an aggregate condition that reflects the health of all alert agent-level conditions. - // Specifically, it aggregates the following conditions: - // - AlertAgentConfiguredConditionType - // When True, the alert agent is healthy with reason "AlertAgentHealthy". - // When False, the alert agent is unhealthy with reason "AlertAgentUnhealthy". - // When Unknown, the alert agent's health has not yet been observed by the status collector - // with reason "Pending". This is expected to be temporary. - AlertAgentHealthyConditionType = "Healthy" - - // AlertAgentConfiguredConditionType tracks whether the alert agent is registered in the CIB - // with the expected script path and event filter. - // When True, the alert agent is registered as expected with reason "Configured". - // When False, the alert agent is not registered with reason "Missing", or is registered with - // an unexpected path or filter with reason "Misconfigured". This is an unexpected state. - // When Unknown, the CIB registration has not yet been observed by the status collector with - // reason "Pending". This is expected to be temporary. - AlertAgentConfiguredConditionType = "Configured" -) - -// AlertAgentHealthy condition reasons -const ( - // AlertAgentHealthyReasonHealthy means the alert agent is healthy and operating normally. - AlertAgentHealthyReasonHealthy = "AlertAgentHealthy" - - // AlertAgentHealthyReasonUnhealthy means the alert agent has issues that need investigation. - AlertAgentHealthyReasonUnhealthy = "AlertAgentUnhealthy" - - // AlertAgentHealthyReasonPending means the alert agent's health has not yet been observed by - // the status collector. This is expected to be temporary. - AlertAgentHealthyReasonPending = "Pending" -) - -// AlertAgentConfigured condition reasons -const ( - // AlertAgentConfiguredReasonConfigured means the alert agent is registered in the CIB with the - // expected script path and event filter. This is the normal operating state. - AlertAgentConfiguredReasonConfigured = "Configured" - - // AlertAgentConfiguredReasonMissing means the alert agent is not registered in the CIB. - // This is an unexpected state. - AlertAgentConfiguredReasonMissing = "Missing" - - // AlertAgentConfiguredReasonMisconfigured means the alert agent is registered in the CIB with - // an unexpected script path or event filter. This is an unexpected state. - AlertAgentConfiguredReasonMisconfigured = "Misconfigured" - - // AlertAgentConfiguredReasonPending means the alert agent's CIB registration has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentConfiguredReasonPending = "Pending" -) - // Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions const ( // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. @@ -625,7 +607,11 @@ type PacemakerClusterStatus struct { // The "Healthy" condition is an aggregate that tracks the overall health of the cluster. // The "InService" condition tracks whether the cluster is in service (not in maintenance mode). // The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - // Each of these conditions is required, so the array must contain at least 3 items. + // Each of these three conditions is required, so the array must contain at least 3 items. + // A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + // collector that supports it has completed a successful collection; its absence is not a + // validation error and does not indicate a failure. This preserves compatibility with an older + // status collector that didn't support alert agents. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=3 @@ -653,21 +639,6 @@ type PacemakerClusterStatus struct { // +kubebuilder:validation:MaxItems=5 // +required Nodes *[]PacemakerClusterNodeStatus `json:"nodes,omitempty"` - - // alertAgents contains the cluster-wide registration status of pacemaker alert - // agents used for auto-tainting nodes after fencing events. - // This field is optional and is omitted when alert agent status has not yet been - // collected by the status collector (including by a collector version that - // predates this field) or when no alert agents are configured. - // When present, this array contains at most 8 entries. - // Names must be unique within this array. - // +listType=map - // +listMapKey=name - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" - // +optional - AlertAgents []PacemakerClusterAlertAgentStatus `json:"alertAgents,omitempty"` } // PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including @@ -868,31 +839,6 @@ type PacemakerClusterResourceStatus struct { Name PacemakerClusterResourceName `json:"name,omitempty"` } -// PacemakerClusterAlertAgentStatus represents the cluster-wide registration status -// of a pacemaker alert agent. -type PacemakerClusterAlertAgentStatus struct { - // conditions represent the observations of the alert agent's current state. - // Known condition types are "Healthy" (aggregate) and "Configured" (registered - // in the CIB with the expected script path and event filter). - // If this alert agent's state has not yet been observed by the status collector, - // publish these conditions with status "Unknown" and reason "Pending". - // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - // +listType=map - // +listMapKey=type - // +kubebuilder:validation:MinItems=2 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Configured')",message="conditions must contain a condition of type Configured" - // +required - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // name is the name of the pacemaker alert agent. This field is required. - // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - // +required - Name PacemakerClusterAlertAgentName `json:"name,omitempty"` -} - // PacemakerClusterAlertAgentScriptStatus represents the presence of an alert // agent's script on a specific node. Alert agent registration is cluster-wide, // but the script it invokes must exist locally on whichever node the triggering diff --git a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 2c6fba1f76b..0cad2322cef 100644 --- a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -51,116 +51,6 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: - alertAgents: - description: |- - alertAgents contains the cluster-wide registration status of pacemaker alert - agents used for auto-tainting nodes after fencing events. - This field is optional and is omitted when alert agent status has not yet been - collected by the status collector (including by a collector version that - predates this field) or when no alert agents are configured. - When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentStatus represents the cluster-wide registration status - of a pacemaker alert agent. - properties: - conditions: - description: |- - conditions represent the observations of the alert agent's current state. - Known condition types are "Healthy" (aggregate) and "Configured" (registered - in the CIB with the expected script path and event filter). - If this alert agent's state has not yet been observed by the status collector, - publish these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type Configured - rule: self.exists(c, c.type == 'Configured') - name: - description: |- - name is the name of the pacemaker alert agent. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -168,7 +58,11 @@ spec: The "Healthy" condition is an aggregate that tracks the overall health of the cluster. The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - Each of these conditions is required, so the array must contain at least 3 items. + Each of these three conditions is required, so the array must contain at least 3 items. + A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + collector that supports it has completed a successful collection; its absence is not a + validation error and does not indicate a failure. This preserves compatibility with an older + status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. diff --git a/etcd/v1/zz_generated.deepcopy.go b/etcd/v1/zz_generated.deepcopy.go index c435f24bc6f..acaedbcfe33 100644 --- a/etcd/v1/zz_generated.deepcopy.go +++ b/etcd/v1/zz_generated.deepcopy.go @@ -60,29 +60,6 @@ func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAl return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PacemakerClusterAlertAgentStatus) DeepCopyInto(out *PacemakerClusterAlertAgentStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]metav1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentStatus. -func (in *PacemakerClusterAlertAgentStatus) DeepCopy() *PacemakerClusterAlertAgentStatus { - if in == nil { - return nil - } - out := new(PacemakerClusterAlertAgentStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -233,13 +210,6 @@ func (in *PacemakerClusterStatus) DeepCopyInto(out *PacemakerClusterStatus) { } } } - if in.AlertAgents != nil { - in, out := &in.AlertAgents, &out.AlertAgents - *out = make([]PacemakerClusterAlertAgentStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } return } diff --git a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 8bbbec570e7..ee1fe45ec9c 100644 --- a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -52,116 +52,6 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: - alertAgents: - description: |- - alertAgents contains the cluster-wide registration status of pacemaker alert - agents used for auto-tainting nodes after fencing events. - This field is optional and is omitted when alert agent status has not yet been - collected by the status collector (including by a collector version that - predates this field) or when no alert agents are configured. - When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentStatus represents the cluster-wide registration status - of a pacemaker alert agent. - properties: - conditions: - description: |- - conditions represent the observations of the alert agent's current state. - Known condition types are "Healthy" (aggregate) and "Configured" (registered - in the CIB with the expected script path and event filter). - If this alert agent's state has not yet been observed by the status collector, - publish these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type Configured - rule: self.exists(c, c.type == 'Configured') - name: - description: |- - name is the name of the pacemaker alert agent. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -169,7 +59,11 @@ spec: The "Healthy" condition is an aggregate that tracks the overall health of the cluster. The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - Each of these conditions is required, so the array must contain at least 3 items. + Each of these three conditions is required, so the array must contain at least 3 items. + A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + collector that supports it has completed a successful collection; its absence is not a + validation error and does not indicate a failure. This preserves compatibility with an older + status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. diff --git a/etcd/v1/zz_generated.model_name.go b/etcd/v1/zz_generated.model_name.go index e7715ef8e9c..9e7b6e26bb0 100644 --- a/etcd/v1/zz_generated.model_name.go +++ b/etcd/v1/zz_generated.model_name.go @@ -15,11 +15,6 @@ func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus" } -// OpenAPIModelName returns the OpenAPI model name for this type. -func (in PacemakerClusterAlertAgentStatus) OpenAPIModelName() string { - return "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus" -} - // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1/zz_generated.swagger_doc_generated.go b/etcd/v1/zz_generated.swagger_doc_generated.go index e56cf680030..15d8600389b 100644 --- a/etcd/v1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1/zz_generated.swagger_doc_generated.go @@ -31,16 +31,6 @@ func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { return map_PacemakerClusterAlertAgentScriptStatus } -var map_PacemakerClusterAlertAgentStatus = map[string]string{ - "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "name": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", -} - -func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { - return map_PacemakerClusterAlertAgentStatus -} - var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -88,10 +78,9 @@ func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterStatus = map[string]string{ "": "PacemakerClusterStatus contains the actual pacemaker cluster status information. As part of validating the status object, we need to ensure that the lastUpdated timestamp may not be set to an earlier timestamp than the current value. The validation rule checks if oldSelf has lastUpdated before comparing, to handle the initial status creation case.", - "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", - "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 67d473d17aa..450facd300f 100644 --- a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1934,2016 +1934,857 @@ tests: message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" - - name: Should accept cluster status with alertAgents entirely absent + - name: Should accept cluster status with AlertAgentsConfigured Unknown pending observation initial: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: name: cluster updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Alert agent registration has not yet been observed by the status collector" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy + reason: Managed + message: "Managed" + - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService + reason: Enabled + message: "Enabled" + - type: Operational status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected + reason: Operational + message: "Operational" + - type: Active status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept cluster status with only the Taint alert agent observed - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept an alert agent with Unknown Configured status pending observation - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy + reason: Managed + message: "Managed" + - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService + reason: Enabled + message: "Enabled" + - type: Operational status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected + reason: Operational + message: "Operational" + - type: Active status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - - type: Configured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "Unknown" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Pending + message: "Alert agent registration has not yet been observed by the status collector" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - - type: Configured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Pending" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts entirely absent - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts fully populated + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept cluster status with AlertAgentsConfigured False Missing initial: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: name: cluster updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "False" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Missing + message: "tnf-untaint-alert is not registered in the CIB" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet conditions: - type: Healthy status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" + reason: ResourceHealthy + message: "Healthy" - type: InService status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" reason: InService message: "In service" - - type: NodeCountAsExpected + - type: Managed status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" expected: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + status: + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ClusterHealthy + message: "Cluster is healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: NodeCountAsExpected + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AsExpected + message: "Expected nodes present" + - type: AlertAgentsConfigured + status: "False" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Missing + message: "tnf-untaint-alert is not registered in the CIB" + lastUpdated: "2024-01-01T00:00:01Z" + nodes: + - nodeName: master-0.example.com + addresses: + - type: InternalIP + address: "192.168.1.1" + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: NodeHealthy + message: "Node healthy" + - type: Online + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Online + message: "Online" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Ready + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Ready + message: "Ready" + - type: Clean + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Clean + message: "Clean" + - type: Member + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Member + message: "Member" + - type: FencingAvailable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingAvailable + message: "Fencing available" + - type: FencingHealthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: FencingHealthy + message: "All fencing agents healthy" + resources: + - name: Kubelet + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Etcd + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + fencingAgents: + - name: master-0.example.com_redfish + method: Redfish + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: InService + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: InService + message: "In service" + - type: Managed + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Managed + message: "Managed" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Enabled + message: "Enabled" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Operational + message: "Operational" + - type: Active + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Active + message: "Active" + - type: Started + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Started + message: "Started" + - type: Schedulable + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Schedulable + message: "Schedulable" + - name: Should accept a node with alertAgentScripts entirely absent + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: @@ -3966,31 +2807,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4171,38 +2987,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Should reject alertAgents missing the Configured condition - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | + expected: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: @@ -4225,19 +3010,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Extra - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Extra - message: "Placeholder" nodes: - nodeName: master-0.example.com addresses: @@ -4418,8 +3190,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "conditions must contain a condition of type Configured" - - name: Should reject alertAgents entry missing name + - name: Should accept a node with alertAgentScripts fully populated initial: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster @@ -4448,19 +3219,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4641,14 +3399,32 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "Required value" - - name: Should reject alertAgents with duplicate names - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + expected: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: @@ -4671,31 +3447,6 @@ tests: reason: AsExpected message: "Expected nodes present" lastUpdated: "2024-01-01T00:00:01Z" - alertAgents: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentHealthy - message: "Healthy" - - type: Configured - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Configured - message: "Configured" nodes: - nodeName: master-0.example.com addresses: @@ -4876,7 +3627,31 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expectedStatusError: "alert agent names must be unique" + alertAgentScripts: + - name: Taint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" + - name: Untaint Alert Agent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: AlertAgentScriptHealthy + message: "Healthy" + - type: ScriptPresent + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Present + message: "Script present" - name: Should reject node alertAgentScripts missing the ScriptPresent condition initial: | apiVersion: etcd.openshift.io/v1alpha1 diff --git a/etcd/v1alpha1/types_pacemakercluster.go b/etcd/v1alpha1/types_pacemakercluster.go index 7d0bb70c724..3e5c2e7b404 100644 --- a/etcd/v1alpha1/types_pacemakercluster.go +++ b/etcd/v1alpha1/types_pacemakercluster.go @@ -15,7 +15,7 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) - // - AlertAgentHealthyConditionType (for each alert agent in status.alertAgents, when populated) + // - ClusterAlertAgentsConfiguredConditionType (when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -31,6 +31,42 @@ const ( // When True, the expected number of nodes are present with reason "AsExpected". // When False, the node count is incorrect with reason "InsufficientNodes" or "ExcessiveNodes". ClusterNodeCountAsExpectedConditionType = "NodeCountAsExpected" + + // ClusterAlertAgentsConfiguredConditionType tracks whether all known pacemaker alert agents + // (tnf-taint-alert, tnf-untaint-alert) are registered in the CIB with the expected script path + // and event filter. Alert agents are cluster-wide CIB objects: a single registration is shared + // by all nodes via Pacemaker's CIB replication, unlike fencing agents and resources which are + // node-scoped, so this is a single aggregate condition. + // When True, all known alert agents are registered as expected with reason "Configured". + // When False, at least one alert agent is not registered with reason "Missing", or all are + // registered but at least one has an unexpected script path or event filter with reason + // "Misconfigured" (Missing takes priority over Misconfigured when both problems exist across + // different agents). The message names the specific agent(s) affected. + // When Unknown, alert agent registration has not yet been observed this run by the status + // collector with reason "Pending". This is expected to be temporary, e.g. immediately after + // upgrade or before the first successful CIB collection completes. + ClusterAlertAgentsConfiguredConditionType = "AlertAgentsConfigured" +) + +// ClusterAlertAgentsConfigured condition reasons +const ( + // ClusterAlertAgentsConfiguredReasonConfigured means all known alert agents are registered in + // the CIB with the expected script path and event filter. This is the normal operating state. + ClusterAlertAgentsConfiguredReasonConfigured = "Configured" + + // ClusterAlertAgentsConfiguredReasonMissing means at least one known alert agent is not + // registered in the CIB at all. This is an unexpected state and takes priority over + // Misconfigured when both problems exist across different agents. + ClusterAlertAgentsConfiguredReasonMissing = "Missing" + + // ClusterAlertAgentsConfiguredReasonMisconfigured means every known alert agent is registered, + // but at least one has an unexpected script path or event filter. This is an unexpected state. + ClusterAlertAgentsConfiguredReasonMisconfigured = "Misconfigured" + + // ClusterAlertAgentsConfiguredReasonPending means alert agent registration has not yet been + // observed this run by the status collector. Used only with status "Unknown". This is expected + // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. + ClusterAlertAgentsConfiguredReasonPending = "Pending" ) // ClusterHealthy condition reasons @@ -400,60 +436,6 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) -// Cluster-level condition types for PacemakerCluster.status.alertAgents[].conditions -const ( - // AlertAgentHealthyConditionType tracks the overall health of a pacemaker alert agent. - // This is an aggregate condition that reflects the health of all alert agent-level conditions. - // Specifically, it aggregates the following conditions: - // - AlertAgentConfiguredConditionType - // When True, the alert agent is healthy with reason "AlertAgentHealthy". - // When False, the alert agent is unhealthy with reason "AlertAgentUnhealthy". - // When Unknown, the alert agent's health has not yet been observed by the status collector - // with reason "Pending". This is expected to be temporary. - AlertAgentHealthyConditionType = "Healthy" - - // AlertAgentConfiguredConditionType tracks whether the alert agent is registered in the CIB - // with the expected script path and event filter. - // When True, the alert agent is registered as expected with reason "Configured". - // When False, the alert agent is not registered with reason "Missing", or is registered with - // an unexpected path or filter with reason "Misconfigured". This is an unexpected state. - // When Unknown, the CIB registration has not yet been observed by the status collector with - // reason "Pending". This is expected to be temporary. - AlertAgentConfiguredConditionType = "Configured" -) - -// AlertAgentHealthy condition reasons -const ( - // AlertAgentHealthyReasonHealthy means the alert agent is healthy and operating normally. - AlertAgentHealthyReasonHealthy = "AlertAgentHealthy" - - // AlertAgentHealthyReasonUnhealthy means the alert agent has issues that need investigation. - AlertAgentHealthyReasonUnhealthy = "AlertAgentUnhealthy" - - // AlertAgentHealthyReasonPending means the alert agent's health has not yet been observed by - // the status collector. This is expected to be temporary. - AlertAgentHealthyReasonPending = "Pending" -) - -// AlertAgentConfigured condition reasons -const ( - // AlertAgentConfiguredReasonConfigured means the alert agent is registered in the CIB with the - // expected script path and event filter. This is the normal operating state. - AlertAgentConfiguredReasonConfigured = "Configured" - - // AlertAgentConfiguredReasonMissing means the alert agent is not registered in the CIB. - // This is an unexpected state. - AlertAgentConfiguredReasonMissing = "Missing" - - // AlertAgentConfiguredReasonMisconfigured means the alert agent is registered in the CIB with - // an unexpected script path or event filter. This is an unexpected state. - AlertAgentConfiguredReasonMisconfigured = "Misconfigured" - - // AlertAgentConfiguredReasonPending means the alert agent's CIB registration has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentConfiguredReasonPending = "Pending" -) - // Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions const ( // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. @@ -625,7 +607,11 @@ type PacemakerClusterStatus struct { // The "Healthy" condition is an aggregate that tracks the overall health of the cluster. // The "InService" condition tracks whether the cluster is in service (not in maintenance mode). // The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - // Each of these conditions is required, so the array must contain at least 3 items. + // Each of these three conditions is required, so the array must contain at least 3 items. + // A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + // collector that supports it has completed a successful collection; its absence is not a + // validation error and does not indicate a failure. This preserves compatibility with an older + // status collector that didn't support alert agents. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=3 @@ -653,21 +639,6 @@ type PacemakerClusterStatus struct { // +kubebuilder:validation:MaxItems=5 // +required Nodes *[]PacemakerClusterNodeStatus `json:"nodes,omitempty"` - - // alertAgents contains the cluster-wide registration status of pacemaker alert - // agents used for auto-tainting nodes after fencing events. - // This field is optional and is omitted when alert agent status has not yet been - // collected by the status collector (including by a collector version that - // predates this field) or when no alert agents are configured. - // When present, this array contains at most 8 entries. - // Names must be unique within this array. - // +listType=map - // +listMapKey=name - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" - // +optional - AlertAgents []PacemakerClusterAlertAgentStatus `json:"alertAgents,omitempty"` } // PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including @@ -868,31 +839,6 @@ type PacemakerClusterResourceStatus struct { Name PacemakerClusterResourceName `json:"name,omitempty"` } -// PacemakerClusterAlertAgentStatus represents the cluster-wide registration status -// of a pacemaker alert agent. -type PacemakerClusterAlertAgentStatus struct { - // conditions represent the observations of the alert agent's current state. - // Known condition types are "Healthy" (aggregate) and "Configured" (registered - // in the CIB with the expected script path and event filter). - // If this alert agent's state has not yet been observed by the status collector, - // publish these conditions with status "Unknown" and reason "Pending". - // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - // +listType=map - // +listMapKey=type - // +kubebuilder:validation:MinItems=2 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Configured')",message="conditions must contain a condition of type Configured" - // +required - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // name is the name of the pacemaker alert agent. This field is required. - // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - // +required - Name PacemakerClusterAlertAgentName `json:"name,omitempty"` -} - // PacemakerClusterAlertAgentScriptStatus represents the presence of an alert // agent's script on a specific node. Alert agent registration is cluster-wide, // but the script it invokes must exist locally on whichever node the triggering diff --git a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 43bf95579c7..663cd423ca3 100644 --- a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -51,116 +51,6 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: - alertAgents: - description: |- - alertAgents contains the cluster-wide registration status of pacemaker alert - agents used for auto-tainting nodes after fencing events. - This field is optional and is omitted when alert agent status has not yet been - collected by the status collector (including by a collector version that - predates this field) or when no alert agents are configured. - When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentStatus represents the cluster-wide registration status - of a pacemaker alert agent. - properties: - conditions: - description: |- - conditions represent the observations of the alert agent's current state. - Known condition types are "Healthy" (aggregate) and "Configured" (registered - in the CIB with the expected script path and event filter). - If this alert agent's state has not yet been observed by the status collector, - publish these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type Configured - rule: self.exists(c, c.type == 'Configured') - name: - description: |- - name is the name of the pacemaker alert agent. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -168,7 +58,11 @@ spec: The "Healthy" condition is an aggregate that tracks the overall health of the cluster. The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - Each of these conditions is required, so the array must contain at least 3 items. + Each of these three conditions is required, so the array must contain at least 3 items. + A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + collector that supports it has completed a successful collection; its absence is not a + validation error and does not indicate a failure. This preserves compatibility with an older + status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. diff --git a/etcd/v1alpha1/zz_generated.deepcopy.go b/etcd/v1alpha1/zz_generated.deepcopy.go index 39f6e07ae93..95e6c92d3de 100644 --- a/etcd/v1alpha1/zz_generated.deepcopy.go +++ b/etcd/v1alpha1/zz_generated.deepcopy.go @@ -60,29 +60,6 @@ func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAl return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PacemakerClusterAlertAgentStatus) DeepCopyInto(out *PacemakerClusterAlertAgentStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentStatus. -func (in *PacemakerClusterAlertAgentStatus) DeepCopy() *PacemakerClusterAlertAgentStatus { - if in == nil { - return nil - } - out := new(PacemakerClusterAlertAgentStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -233,13 +210,6 @@ func (in *PacemakerClusterStatus) DeepCopyInto(out *PacemakerClusterStatus) { } } } - if in.AlertAgents != nil { - in, out := &in.AlertAgents, &out.AlertAgents - *out = make([]PacemakerClusterAlertAgentStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } return } diff --git a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index ef0c5a7d523..7ac949a6fcc 100644 --- a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -52,116 +52,6 @@ spec: This field is optional on creation - the status collector populates it immediately after creating the resource via the status subresource. properties: - alertAgents: - description: |- - alertAgents contains the cluster-wide registration status of pacemaker alert - agents used for auto-tainting nodes after fencing events. - This field is optional and is omitted when alert agent status has not yet been - collected by the status collector (including by a collector version that - predates this field) or when no alert agents are configured. - When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentStatus represents the cluster-wide registration status - of a pacemaker alert agent. - properties: - conditions: - description: |- - conditions represent the observations of the alert agent's current state. - Known condition types are "Healthy" (aggregate) and "Configured" (registered - in the CIB with the expected script path and event filter). - If this alert agent's state has not yet been observed by the status collector, - publish these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type Configured - rule: self.exists(c, c.type == 'Configured') - name: - description: |- - name is the name of the pacemaker alert agent. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the pacemaker cluster's current state. @@ -169,7 +59,11 @@ spec: The "Healthy" condition is an aggregate that tracks the overall health of the cluster. The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. - Each of these conditions is required, so the array must contain at least 3 items. + Each of these three conditions is required, so the array must contain at least 3 items. + A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status + collector that supports it has completed a successful collection; its absence is not a + validation error and does not indicate a failure. This preserves compatibility with an older + status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. diff --git a/etcd/v1alpha1/zz_generated.model_name.go b/etcd/v1alpha1/zz_generated.model_name.go index f83b15bf405..ff47b599dd2 100644 --- a/etcd/v1alpha1/zz_generated.model_name.go +++ b/etcd/v1alpha1/zz_generated.model_name.go @@ -15,11 +15,6 @@ func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus" } -// OpenAPIModelName returns the OpenAPI model name for this type. -func (in PacemakerClusterAlertAgentStatus) OpenAPIModelName() string { - return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus" -} - // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go index f8ca49c326d..a49f73f5298 100644 --- a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go @@ -31,16 +31,6 @@ func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { return map_PacemakerClusterAlertAgentScriptStatus } -var map_PacemakerClusterAlertAgentStatus = map[string]string{ - "": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "conditions": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "name": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", -} - -func (PacemakerClusterAlertAgentStatus) SwaggerDoc() map[string]string { - return map_PacemakerClusterAlertAgentStatus -} - var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -88,10 +78,9 @@ func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterStatus = map[string]string{ "": "PacemakerClusterStatus contains the actual pacemaker cluster status information. As part of validating the status object, we need to ensure that the lastUpdated timestamp may not be set to an earlier timestamp than the current value. The validation rule checks if oldSelf has lastUpdated before comparing, to handle the initial status creation case.", - "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", - "alertAgents": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", } func (PacemakerClusterStatus) SwaggerDoc() map[string]string { diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 884aa2854dc..2422c354df6 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -667,7 +667,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA consolev1.NamespaceDashboardSpec{}.OpenAPIModelName(): schema_openshift_api_console_v1_NamespaceDashboardSpec(ref), etcdv1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerCluster(ref), etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref), - etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref), etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref), etcdv1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterList(ref), etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref), @@ -676,7 +675,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerNodeAddress(ref), etcdv1alpha1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerCluster(ref), etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(ref), - etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref), etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref), etcdv1alpha1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterList(ref), etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref), @@ -30144,52 +30142,6 @@ func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref com } } -func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(metav1.Condition{}.OpenAPIModelName()), - }, - }, - }, - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, - }, - }, - }, - Required: []string{"conditions", "name"}, - }, - }, - Dependencies: []string{ - metav1.Condition{}.OpenAPIModelName()}, - } -} - func schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -30487,7 +30439,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30527,34 +30479,12 @@ func schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref common.ReferenceCal }, }, }, - "alertAgents": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "name", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName()), - }, - }, - }, - }, - }, }, Required: []string{"conditions", "lastUpdated", "nodes"}, }, }, Dependencies: []string{ - etcdv1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, + etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, } } @@ -30677,52 +30607,6 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(r } } -func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(metav1.Condition{}.OpenAPIModelName()), - }, - }, - }, - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, - }, - }, - }, - Required: []string{"conditions", "name"}, - }, - }, - Dependencies: []string{ - metav1.Condition{}.OpenAPIModelName()}, - } -} - func schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -31020,7 +30904,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterStatus(ref common.Refere }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -31060,34 +30944,12 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterStatus(ref common.Refere }, }, }, - "alertAgents": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "name", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName()), - }, - }, - }, - }, - }, }, Required: []string{"conditions", "lastUpdated", "nodes"}, }, }, Dependencies: []string{ - etcdv1alpha1.PacemakerClusterAlertAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, + etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName(), metav1.Time{}.OpenAPIModelName()}, } } diff --git a/openapi/openapi.json b/openapi/openapi.json index 932b5eb131e..6a4fb3e1275 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -16788,36 +16788,6 @@ } } }, - "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus": { - "description": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "type": "object", - "required": [ - "conditions", - "name" - ], - "properties": { - "conditions": { - "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" - }, - "x-kubernetes-list-map-keys": [ - "type" - ], - "x-kubernetes-list-type": "map" - }, - "name": { - "description": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - "type": "string", - "enum": [ - "Taint Alert Agent", - "Untaint Alert Agent" - ] - } - } - }, "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -16996,20 +16966,8 @@ "nodes" ], "properties": { - "alertAgents": { - "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentStatus" - }, - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, "conditions": { - "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", "type": "array", "items": { "default": {}, @@ -17116,36 +17074,6 @@ } } }, - "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus": { - "description": "PacemakerClusterAlertAgentStatus represents the cluster-wide registration status of a pacemaker alert agent.", - "type": "object", - "required": [ - "conditions", - "name" - ], - "properties": { - "conditions": { - "description": "conditions represent the observations of the alert agent's current state. Known condition types are \"Healthy\" (aggregate) and \"Configured\" (registered in the CIB with the expected script path and event filter). If this alert agent's state has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" - }, - "x-kubernetes-list-map-keys": [ - "type" - ], - "x-kubernetes-list-type": "map" - }, - "name": { - "description": "name is the name of the pacemaker alert agent. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - "type": "string", - "enum": [ - "Taint Alert Agent", - "Untaint Alert Agent" - ] - } - } - }, "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -17324,20 +17252,8 @@ "nodes" ], "properties": { - "alertAgents": { - "description": "alertAgents contains the cluster-wide registration status of pacemaker alert agents used for auto-tainting nodes after fencing events. This field is optional and is omitted when alert agent status has not yet been collected by the status collector (including by a collector version that predates this field) or when no alert agents are configured. When present, this array contains at most 8 entries. Names must be unique within this array.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentStatus" - }, - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, "conditions": { - "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these conditions is required, so the array must contain at least 3 items.", + "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", "type": "array", "items": { "default": {}, From 84bf3326d5715da82faf28de45b6bc0d015d1328 Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Tue, 22 Sep 2026 12:00:59 +0200 Subject: [PATCH 4/7] Fold alert-agent status into existing resource conditions --- etcd/README.md | 89 +- .../DualReplica.yaml | 1476 ++--------------- etcd/v1/types_pacemakercluster.go | 232 +-- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 181 +- etcd/v1/zz_generated.deepcopy.go | 30 - .../DualReplica.yaml | 181 +- etcd/v1/zz_generated.model_name.go | 5 - etcd/v1/zz_generated.swagger_doc_generated.go | 31 +- .../DualReplica.yaml | 1476 ++--------------- etcd/v1alpha1/types_pacemakercluster.go | 232 +-- ...0000_25_etcd_01_pacemakerclusters.crd.yaml | 181 +- etcd/v1alpha1/zz_generated.deepcopy.go | 30 - .../DualReplica.yaml | 181 +- etcd/v1alpha1/zz_generated.model_name.go | 5 - .../zz_generated.swagger_doc_generated.go | 31 +- .../generated_openapi/zz_generated.openapi.go | 166 +- openapi/openapi.json | 112 +- 17 files changed, 572 insertions(+), 4067 deletions(-) diff --git a/etcd/README.md b/etcd/README.md index 4b434d65da4..6d65722324a 100644 --- a/etcd/README.md +++ b/etcd/README.md @@ -40,10 +40,11 @@ The brief window where status is empty is acceptable since the healthcheck contr A **pacemaker resource** is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. -For Two Node OpenShift with Fencing, we manage three resource types: +For Two Node OpenShift with Fencing, the node's `resources` array tracks: - **Kubelet**: The Kubernetes node agent and a prerequisite for etcd - **Etcd**: The distributed key-value store - **FencingAgent**: Used to isolate failed nodes during a quorum loss event (tracked separately) +- **TaintAlertAgent** / **UntaintAlertAgent**: Alert agents whose CIB configuration and per-node script presence are tracked as optional entries ### Status Structure @@ -53,7 +54,6 @@ status: # Optional on creation, populated via status subresou - type: Healthy - type: InService - type: NodeCountAsExpected - - type: AlertAgentsConfigured # Optional 4th condition: cluster-wide alert agent CIB registration lastUpdated: # Required when status present, cannot decrease nodes: # Control-plane nodes (0-5, expects 2 for TNF) - nodeName: # RFC 1123 subdomain name @@ -70,7 +70,7 @@ status: # Optional on creation, populated via status subresou - type: Member - type: FencingAvailable - type: FencingHealthy - resources: # Required: Pacemaker resources on this node (min 2) + resources: # Required: Pacemaker resources on this node (min 2: Kubelet + Etcd) - name: Kubelet # Both Kubelet and Etcd must be present conditions: # Required: Resource-level conditions (min 8 items) - type: Healthy @@ -83,15 +83,17 @@ status: # Optional on creation, populated via status subresou - type: Schedulable - name: Etcd conditions: [...] # Same 8 conditions as Kubelet (abbreviated) + - name: TaintAlertAgent # Optional: alert-agent entry + conditions: # Required: 3 conditions for alert-agent entries + - type: Healthy + - type: Enabled # reason: ScriptConfigured (agent registered in CIB) + - type: Operational # reason: ScriptPresent (script present on this node) + - name: UntaintAlertAgent # Optional + conditions: [...] # Same 3 conditions as TaintAlertAgent (abbreviated) fencingAgents: # Required: Fencing agents for THIS node (1-8) - name: # e.g., "master-0_redfish" (unique, max 300 chars) method: # Fencing method: "Redfish" or "IPMI" conditions: [...] # Same 8 conditions as resources (abbreviated) - alertAgentScripts: # Optional: per-node alert agent script presence (0-8 items) - - name: # "Taint Alert Agent" or "Untaint Alert Agent" - conditions: # Required: Alert agent script-level conditions (min 2 items) - - type: Healthy - - type: ScriptPresent ``` ### Fencing Agents @@ -113,27 +115,31 @@ Unlike regular pacemaker resources (Kubelet, Etcd), fencing agents are tracked s ### Alert Agents Alert agents are pacemaker alert handlers used to automatically taint a node after it is fenced, and remove -that taint once the node rejoins the cluster. There are two known alert agents: "Taint Alert Agent" and -"Untaint Alert Agent". Unlike resources and fencing agents, alert agents are registered cluster-wide (a single -CIB object shared by all nodes via Pacemaker's CIB replication), so their registration status is tracked once, -as the aggregate `AlertAgentsConfigured` condition on `status.conditions`. +that taint once the node rejoins the cluster. There are two known alert agents: `TaintAlertAgent` and +`UntaintAlertAgent`. An alert agent is registered in the CIB (a single object shared by all nodes via +Pacemaker's CIB replication), and the script it invokes must exist locally on whichever node the triggering +event occurs on, since Pacemaker executes it there. Script delivery is handled independently per node by MCO. + +Both aspects are tracked as optional entries in each node's `resources` array, reusing the `PacemakerClusterResourceStatus` type. An alert agent is not a +pacemaker-managed resource, so only a subset of the resource conditions applies to it: +- `Enabled` (reason `ScriptConfigured`) - the alert agent is registered in the CIB as expected +- `Operational` (reason `ScriptPresent`) - the alert agent's script is present and executable on this node +- `Healthy` - aggregate of the two conditions above -The script each alert agent invokes, however, must exist locally on whichever node the triggering event -occurs on, since Pacemaker executes it there. Script delivery is handled independently per node by MCO, so -presence is tracked per node in `status.nodes[].alertAgentScripts` to catch delivery gaps between nodes. +The name-gated validation on `PacemakerClusterResourceStatus` requires all eight conditions only for the `Kubelet` and `Etcd` resources, so alert-agent entries carry just these three. -The `AlertAgentsConfigured` condition and `alertAgentScripts` are both optional. They are omitted, or reported -`Unknown`/`Pending`, when this status has not yet been collected by the status collector, including by a -collector version that predates them. +Alert-agent health is deliberately **not** folded into the node or cluster `Healthy` aggregates, since a missing or misconfigured alert agent doesn't reflect etcd/kubelet state. It is surfaced by the cluster-etcd-operator as an error that degrades the operator: a broken alert agent means post-fencing taint/untaint automation is broken, which is actionable on its own. + +The alert-agent resource entries are optional. They are omitted, or reported `Unknown`/`Pending`, when this +status has not yet been collected by the status collector, including by a collector version that predates them. ### Cluster-Level Conditions -| Condition | True | False | Unknown | -|-----------|------|-------|---------| -| `Healthy` | Cluster is healthy (`ClusterHealthy`) | Cluster has issues (`ClusterUnhealthy`) | n/a | -| `InService` | In service (`InService`) | In maintenance (`InMaintenance`) | n/a | -| `NodeCountAsExpected` | Node count is as expected (`AsExpected`) | Wrong count (`InsufficientNodes`, `ExcessiveNodes`) | n/a | -| `AlertAgentsConfigured` (optional) | All known alert agents registered in the CIB as expected (`Configured`) | At least one agent not registered (`Missing`) or misconfigured (`Misconfigured`) | Not yet observed this run (`Pending`) | +| Condition | True | False | +|-----------|------|-------| +| `Healthy` | Cluster is healthy (`ClusterHealthy`) | Cluster has issues (`ClusterUnhealthy`) | +| `InService` | In service (`InService`) | In maintenance (`InMaintenance`) | +| `NodeCountAsExpected` | Node count is as expected (`AsExpected`) | Wrong count (`InsufficientNodes`, `ExcessiveNodes`) | ### Node-Level Conditions @@ -151,7 +157,8 @@ collector version that predates them. ### Resource-Level Conditions -Each resource in the `resources` array and each fencing agent in the `fencingAgents` array has its own conditions. +Each pacemaker-managed resource (`Kubelet`, `Etcd`) in the `resources` array and each fencing agent in the +`fencingAgents` array has all eight of the following conditions. | Condition | True | False | |-----------|------|-------| @@ -164,14 +171,14 @@ Each resource in the `resources` array and each fencing agent in the `fencingAge | `Started` | Resource is started (`Started`) | Resource is stopped (`Stopped`) | | `Schedulable` | Resource is schedulable (`Schedulable`) | Resource is not schedulable (`Unschedulable`) | -### Alert Agent Script Conditions - -Each entry in a node's `alertAgentScripts` array has its own conditions. +Alert-agent entries (`TaintAlertAgent`, `UntaintAlertAgent`) reuse this type but populate only `Healthy`, +`Enabled`, and `Operational`, with alert-agent-specific reasons: | Condition | True | False | Unknown | |-----------|------|-------|---------| -| `Healthy` | Alert agent script is healthy (`AlertAgentScriptHealthy`) | Alert agent script has issues (`AlertAgentScriptUnhealthy`) | Not yet observed (`Pending`) | -| `ScriptPresent` | Script is present and executable on this node (`Present`) | Script is missing from this node (`Missing`) | Not yet observed (`Pending`) | +| `Healthy` | Alert agent entry is healthy (`ResourceHealthy`) | Alert agent entry has issues (`ResourceUnhealthy`) | Not yet observed (`Pending`) | +| `Enabled` | Alert agent registered in the CIB as expected (`ScriptConfigured`) | Not registered or misconfigured (descriptive reason) | Not yet observed (`Pending`) | +| `Operational` | Alert agent script present on this node (`ScriptPresent`) | Script missing from this node (descriptive reason) | Not yet observed (`Pending`) | ### Validation Rules @@ -203,7 +210,7 @@ Each entry in a node's `alertAgentScripts` array has its own conditions. **Status fields:** - `status` - Optional on creation (pointer type), populated via status subresource - When status is present, `conditions`, `lastUpdated`, and `nodes` are required: - - `conditions` - Required array of cluster conditions (min 3 items: Healthy, InService, NodeCountAsExpected); the optional 4th `AlertAgentsConfigured` condition may also be present + - `conditions` - Required array of cluster conditions (min 3 items: Healthy, InService, NodeCountAsExpected) - `lastUpdated` - Required timestamp for staleness detection - `nodes` - Required array of control-plane node statuses (min 0, max 5; empty allowed for catastrophic failures) @@ -211,26 +218,22 @@ Each entry in a node's `alertAgentScripts` array has its own conditions. - `nodeName` - Required, RFC 1123 subdomain - `addresses` - Required (min 1, max 8 items) - `conditions` - Required (min 9 items with specific types enforced via XValidation) -- `resources` - Required (min 2 items: Kubelet and Etcd) +- `resources` - Required (min 2 items: Kubelet and Etcd; may also contain optional TaintAlertAgent / UntaintAlertAgent entries) - `fencingAgents` - Required (min 1, max 8 items) -- `alertAgentScripts` - Optional (min 0, max 8 items); omitted when not yet collected by the status collector **Conditions validation:** -- Cluster-level: MinItems=3 (Healthy, InService, NodeCountAsExpected); the optional `AlertAgentsConfigured` condition is not required by XValidation +- Cluster-level: MinItems=3 (Healthy, InService, NodeCountAsExpected) - Node-level: MinItems=9 (Healthy, Online, InService, Active, Ready, Clean, Member, FencingAvailable, FencingHealthy) -- Resource-level: MinItems=8 (Healthy, InService, Managed, Enabled, Operational, Active, Started, Schedulable) -- Fencing agent-level: MinItems=8 (same conditions as resources) -- Alert agent script-level: MinItems=2, MaxItems=8 (Healthy, ScriptPresent) +- Resource-level: MinItems=3, MaxItems=16. Healthy, Enabled, and Operational are always required. For Kubelet and Etcd, name-gated XValidation additionally requires InService, Managed, Active, Started, and Schedulable (8 total). Alert-agent entries (TaintAlertAgent, UntaintAlertAgent) require only the three always-required conditions. +- Fencing agent-level: MinItems=8 (Healthy, InService, Managed, Enabled, Operational, Active, Started, Schedulable) All condition arrays have XValidation rules to ensure specific condition types are present. -**Alert agent names:** -- Valid values are: `Taint Alert Agent`, `Untaint Alert Agent` -- Names must be unique within the `alertAgentScripts` array (enforced via XValidation); the array does not require both names to be present - **Resource names:** -- Valid values are: `Kubelet`, `Etcd` -- Both resources must be present in each node's `resources` array +- Valid values are: `Kubelet`, `Etcd`, `TaintAlertAgent`, `UntaintAlertAgent` +- `Kubelet` and `Etcd` must be present in each node's `resources` array +- `TaintAlertAgent` and `UntaintAlertAgent` are optional; when present, neither is required to appear +- Names must be unique within the `resources` array (enforced via the `name` list-map key) **Fencing agent fields:** - `name`: Unique identifier for the fencing agent (e.g., "master-0_redfish") diff --git a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 0c7714ed191..49f6687e462 100644 --- a/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1934,7 +1934,7 @@ tests: message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" - - name: Should accept cluster status with AlertAgentsConfigured Unknown pending observation + - name: Should accept alert-agent resources with only the conditions required for alert agents initial: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster @@ -1962,11 +1962,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Alert agent registration has not yet been observed by the status collector" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2104,6 +2099,40 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" + - name: UntaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2170,11 +2199,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Alert agent registration has not yet been observed by the status collector" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2312,6 +2336,40 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" + - name: UntaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2356,7 +2414,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - - name: Should accept cluster status with AlertAgentsConfigured False Missing + - name: Should reject an alert-agent resource missing the Operational condition initial: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster @@ -2384,11 +2442,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "False" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Missing - message: "tnf-untaint-alert is not registered in the CIB" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2526,6 +2579,23 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2570,7 +2640,14 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expected: | + expectedStatusError: "conditions must contain a condition of type Operational" + - name: Should reject a Kubelet resource missing the conditions required for pacemaker-managed resources + initial: | + apiVersion: etcd.openshift.io/v1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | apiVersion: etcd.openshift.io/v1 kind: PacemakerCluster metadata: @@ -2592,11 +2669,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "False" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Missing - message: "tnf-untaint-alert is not registered in the CIB" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2657,16 +2729,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: ResourceHealthy message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" @@ -2677,21 +2739,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Operational message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - name: Etcd conditions: - type: Healthy @@ -2778,1335 +2825,4 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - - name: Should accept a node with alertAgentScripts entirely absent - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts fully populated - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - expected: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Should reject node alertAgentScripts missing the ScriptPresent condition - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: Extra - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Extra - message: "Placeholder" - expectedStatusError: "conditions must contain a condition of type ScriptPresent" - - name: Should reject node alertAgentScripts with duplicate names - initial: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Present" - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Present" - expectedStatusError: "alert agent names must be unique" + expectedStatusError: "conditions must contain InService, Managed, Active, Started, and Schedulable for Kubelet and Etcd resources" diff --git a/etcd/v1/types_pacemakercluster.go b/etcd/v1/types_pacemakercluster.go index c02f6351b7f..abf53710511 100644 --- a/etcd/v1/types_pacemakercluster.go +++ b/etcd/v1/types_pacemakercluster.go @@ -15,7 +15,6 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) - // - ClusterAlertAgentsConfiguredConditionType (when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -31,42 +30,6 @@ const ( // When True, the expected number of nodes are present with reason "AsExpected". // When False, the node count is incorrect with reason "InsufficientNodes" or "ExcessiveNodes". ClusterNodeCountAsExpectedConditionType = "NodeCountAsExpected" - - // ClusterAlertAgentsConfiguredConditionType tracks whether all known pacemaker alert agents - // (tnf-taint-alert, tnf-untaint-alert) are registered in the CIB with the expected script path - // and event filter. Alert agents are cluster-wide CIB objects: a single registration is shared - // by all nodes via Pacemaker's CIB replication, unlike fencing agents and resources which are - // node-scoped, so this is a single aggregate condition. - // When True, all known alert agents are registered as expected with reason "Configured". - // When False, at least one alert agent is not registered with reason "Missing", or all are - // registered but at least one has an unexpected script path or event filter with reason - // "Misconfigured" (Missing takes priority over Misconfigured when both problems exist across - // different agents). The message names the specific agent(s) affected. - // When Unknown, alert agent registration has not yet been observed this run by the status - // collector with reason "Pending". This is expected to be temporary, e.g. immediately after - // upgrade or before the first successful CIB collection completes. - ClusterAlertAgentsConfiguredConditionType = "AlertAgentsConfigured" -) - -// ClusterAlertAgentsConfigured condition reasons -const ( - // ClusterAlertAgentsConfiguredReasonConfigured means all known alert agents are registered in - // the CIB with the expected script path and event filter. This is the normal operating state. - ClusterAlertAgentsConfiguredReasonConfigured = "Configured" - - // ClusterAlertAgentsConfiguredReasonMissing means at least one known alert agent is not - // registered in the CIB at all. This is an unexpected state and takes priority over - // Misconfigured when both problems exist across different agents. - ClusterAlertAgentsConfiguredReasonMissing = "Missing" - - // ClusterAlertAgentsConfiguredReasonMisconfigured means every known alert agent is registered, - // but at least one has an unexpected script path or event filter. This is an unexpected state. - ClusterAlertAgentsConfiguredReasonMisconfigured = "Misconfigured" - - // ClusterAlertAgentsConfiguredReasonPending means alert agent registration has not yet been - // observed this run by the status collector. Used only with status "Unknown". This is expected - // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. - ClusterAlertAgentsConfiguredReasonPending = "Pending" ) // ClusterHealthy condition reasons @@ -123,7 +86,6 @@ const ( // - NodeFencingAvailableConditionType // - NodeFencingHealthyConditionType // - ResourceHealthyConditionType (for each resource in the node's resources list) - // - AlertAgentScriptHealthyConditionType (for each entry in the node's alertAgentScripts list) // When True, the node is healthy with reason "NodeHealthy". // When False, the node is unhealthy with reason "NodeUnhealthy". NodeHealthyConditionType = "Healthy" @@ -315,12 +277,22 @@ const ( // In Two Node OpenShift with Fencing, we do not expect any resources to be disabled. // When True, the resource is enabled with reason "Enabled". This is the normal operating state. // When False, the resource is disabled with reason "Disabled". This is an unexpected state. + // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), an alert agent cannot be + // disabled, so this condition instead tracks whether the alert agent is registered in the CIB with + // the expected script path and event filter. When True, the agent is configured with reason + // "ScriptConfigured". When False, the agent is not registered or is misconfigured. When Unknown, + // registration has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceEnabledConditionType = "Enabled" // ResourceOperationalConditionType tracks whether a resource is operational (not failed). // A failed resource is one that is not able to start or is in an error state. // When True, the resource is operational with reason "Operational". This is the normal operating state. // When False, the resource has failed with reason "Failed". This is an unexpected state. + // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), this condition instead + // tracks whether the alert agent's script file is present and executable on this node, since the + // script is delivered independently to each node by MCO. When True, the script is present with + // reason "ScriptPresent". When False, the script is missing from this node. When Unknown, presence + // has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceOperationalConditionType = "Operational" // ResourceActiveConditionType tracks whether a resource is active. @@ -388,6 +360,16 @@ const ( // Resources that are disabled are stopped and not automatically managed or started by the cluster. // This is an unexpected state. ResourceEnabledReasonDisabled = "Disabled" + + // ResourceEnabledReasonScriptConfigured means an alert-agent script resource is registered in the + // CIB with the expected script path and event filter. This is the normal operating state for an + // alert-agent resource and is used in place of "Enabled". + ResourceEnabledReasonScriptConfigured = "ScriptConfigured" + + // ResourceEnabledReasonPending means an alert-agent script resource's CIB registration has not yet + // been observed this run by the status collector. Used only with status "Unknown". This is expected + // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. + ResourceEnabledReasonPending = "Pending" ) // ResourceOperational condition reasons @@ -399,6 +381,16 @@ const ( // ResourceOperationalReasonFailed means the resource has failed. // A failed resource is one that is not able to start or is in an error state. This is an unexpected state. ResourceOperationalReasonFailed = "Failed" + + // ResourceOperationalReasonScriptPresent means an alert-agent script resource's script file is + // present and executable on this node. This is the normal operating state for an alert-agent + // resource and is used in place of "Operational". + ResourceOperationalReasonScriptPresent = "ScriptPresent" + + // ResourceOperationalReasonPending means an alert-agent script resource's presence on this node has + // not yet been observed this run by the status collector. Used only with status "Unknown". This is + // expected to be temporary, e.g. before MCO has delivered the script or before the first collection. + ResourceOperationalReasonPending = "Pending" ) // ResourceActive condition reasons @@ -436,55 +428,6 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) -// Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions -const ( - // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. - // This is an aggregate condition that reflects the health of all alert agent script-level conditions. - // Specifically, it aggregates the following conditions: - // - AlertAgentScriptPresentConditionType - // When True, the alert agent script is healthy with reason "AlertAgentScriptHealthy". - // When False, the alert agent script is unhealthy with reason "AlertAgentScriptUnhealthy". - // When Unknown, the script's presence has not yet been observed by the status collector with - // reason "Pending". This is expected to be temporary. - AlertAgentScriptHealthyConditionType = "Healthy" - - // AlertAgentScriptPresentConditionType tracks whether the alert agent's script file is present - // and executable on this node. - // When True, the script is present and executable with reason "Present". - // When False, the script is missing from this node with reason "Missing". This is an unexpected state. - // When Unknown, presence has not yet been observed by the status collector with reason "Pending". - // This is expected to be temporary. - AlertAgentScriptPresentConditionType = "ScriptPresent" -) - -// AlertAgentScriptHealthy condition reasons -const ( - // AlertAgentScriptHealthyReasonHealthy means the alert agent script is healthy and operating normally. - AlertAgentScriptHealthyReasonHealthy = "AlertAgentScriptHealthy" - - // AlertAgentScriptHealthyReasonUnhealthy means the alert agent script has issues that need investigation. - AlertAgentScriptHealthyReasonUnhealthy = "AlertAgentScriptUnhealthy" - - // AlertAgentScriptHealthyReasonPending means the alert agent script's health has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentScriptHealthyReasonPending = "Pending" -) - -// AlertAgentScriptPresent condition reasons -const ( - // AlertAgentScriptPresentReasonPresent means the alert agent script is present and executable on this node. - // This is the normal operating state. - AlertAgentScriptPresentReasonPresent = "Present" - - // AlertAgentScriptPresentReasonMissing means the alert agent script is missing from this node. - // This is an unexpected state that can occur when MCO has not yet delivered the script to this node. - AlertAgentScriptPresentReasonMissing = "Missing" - - // AlertAgentScriptPresentReasonPending means the script's presence on this node has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentScriptPresentReasonPending = "Pending" -) - // PacemakerNodeAddressType represents the type of a node address. // Currently only InternalIP is supported. // +kubebuilder:validation:Enum=InternalIP @@ -518,8 +461,10 @@ type PacemakerNodeAddress struct { } // PacemakerClusterResourceName represents the name of a pacemaker resource. +// This includes both pacemaker-managed resources (Kubelet, Etcd) and pacemaker +// alert agents whose scripts are tracked per node (e.g. TaintAlertAgent, UntaintAlertAgent). // Fencing agents are tracked separately in the fencingAgents field. -// +kubebuilder:validation:Enum=Kubelet;Etcd +// +kubebuilder:validation:Enum=Kubelet;Etcd;TaintAlertAgent;UntaintAlertAgent // +enum type PacemakerClusterResourceName string @@ -532,20 +477,16 @@ const ( // PacemakerClusterResourceNameEtcd is the etcd pacemaker resource. // The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. PacemakerClusterResourceNameEtcd PacemakerClusterResourceName = "Etcd" -) -// PacemakerClusterAlertAgentName represents the name of a pacemaker alert agent. -// +kubebuilder:validation:Enum=Taint Alert Agent;Untaint Alert Agent -// +enum -type PacemakerClusterAlertAgentName string + // PacemakerClusterResourceNameTaintAlertAgent is the alert agent that taints a node after it is fenced. + // Its entry tracks the alert agent's configuration in the CIB + // and the presence of its script on this node. + PacemakerClusterResourceNameTaintAlertAgent PacemakerClusterResourceName = "TaintAlertAgent" -// PacemakerClusterAlertAgentName values -const ( - // PacemakerClusterAlertAgentNameTaint is the alert agent that taints a node after it is fenced. - PacemakerClusterAlertAgentNameTaint PacemakerClusterAlertAgentName = "Taint Alert Agent" - - // PacemakerClusterAlertAgentNameUntaint is the alert agent that removes a node's taint once it rejoins the cluster. - PacemakerClusterAlertAgentNameUntaint PacemakerClusterAlertAgentName = "Untaint Alert Agent" + // PacemakerClusterResourceNameUntaintAlertAgent is the alert agent that removes a node's taint once + // it rejoins the cluster. Its entry tracks the alert agent's + // configuration in the CIB and the presence of its script on this node. + PacemakerClusterResourceNameUntaintAlertAgent PacemakerClusterResourceName = "UntaintAlertAgent" ) // FencingMethod represents the method used by a fencing agent to isolate failed nodes. @@ -608,10 +549,6 @@ type PacemakerClusterStatus struct { // The "InService" condition tracks whether the cluster is in service (not in maintenance mode). // The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. // Each of these three conditions is required, so the array must contain at least 3 items. - // A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - // collector that supports it has completed a successful collection; its absence is not a - // validation error and does not indicate a failure. This preserves compatibility with an older - // status collector that didn't support alert agents. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=3 @@ -694,11 +631,15 @@ type PacemakerClusterNodeStatus struct { // +required Addresses []PacemakerNodeAddress `json:"addresses,omitempty"` - // resources contains the status of pacemaker resources scheduled on this node. + // resources contains the status of pacemaker resources tracked on this node. // Each resource entry includes the resource name and its health conditions. - // For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - // Both resources are required to be present, so the array must contain at least 2 items. - // Valid resource names are "Kubelet" and "Etcd". + // For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + // per node. Both are required to be present, so the array must contain at least 2 items. + // The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + // "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + // and whether its script is present on this node. Alert-agent entries are + // optional and are omitted when a status collector version that predates them has not reported them. + // Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". // Fencing agents are tracked separately in the fencingAgents field. // +listType=map // +listMapKey=name @@ -724,22 +665,6 @@ type PacemakerClusterNodeStatus struct { // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="fencing agent names must be unique" // +required FencingAgents []PacemakerClusterFencingAgentStatus `json:"fencingAgents,omitempty"` - - // alertAgentScripts contains the presence status of each alert agent's script on - // this node. Alert agents are registered cluster-wide in the CIB, - // but their scripts are delivered independently to each node by MCO, so presence - // is tracked per node to catch delivery gaps between nodes. - // This field is optional and is omitted when script-presence status has not yet - // been collected by the status collector (including by a collector version that - // predates this field). When present, this array contains at most 8 entries. - // Names must be unique within this array. - // +listType=map - // +listMapKey=name - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" - // +optional - AlertAgentScripts []PacemakerClusterAlertAgentScriptStatus `json:"alertAgentScripts,omitempty"` } // PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. @@ -793,15 +718,20 @@ type PacemakerClusterFencingAgentStatus struct { Method FencingMethod `json:"method,omitempty"` } -// PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. +// PacemakerClusterResourceStatus represents the status of a resource tracked on a node. // A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or // applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. -// For Two Node OpenShift with Fencing, we track two resources per node: +// For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: // - Kubelet (the Kubernetes node agent and a prerequisite for etcd) // - Etcd (the distributed key-value store) // +// The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert +// agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies +// to it: the required conditions are enforced conditionally based on the resource name. +// // Fencing agents are tracked separately in the fencingAgents field because they are mapped to // their target node (the node they can fence), not the node where monitoring operations are scheduled. +// +kubebuilder:validation:XValidation:rule="!(self.name == 'Kubelet' || self.name == 'Etcd') || ['InService','Managed','Active','Started','Schedulable'].all(t, self.conditions.exists(c, c.type == t))",message="conditions must contain InService, Managed, Active, Started, and Schedulable for Kubelet and Etcd resources" type PacemakerClusterResourceStatus struct { // conditions represent the observations of the resource's current state. // Known condition types are: "Healthy", "InService", "Managed", "Enabled", "Operational", @@ -814,58 +744,36 @@ type PacemakerClusterResourceStatus struct { // The "Active" condition tracks whether the resource is active (available to be used). // The "Started" condition tracks whether the resource is started. // The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - // Each of these conditions is required, so the array must contain at least 8 items. + // Which conditions are required depends on the resource name: + // - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + // above are required, so the array must contain at least 8 items. + // - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + // "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + // required, so the array must contain at least 3 items. The remaining condition types do not + // apply to an alert agent and may be omitted. + // The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + // are enforced by name-gated validation rules on this type. // +listType=map // +listMapKey=type - // +kubebuilder:validation:MinItems=8 + // +kubebuilder:validation:MinItems=3 // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'InService')",message="conditions must contain a condition of type InService" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Managed')",message="conditions must contain a condition of type Managed" // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Enabled')",message="conditions must contain a condition of type Enabled" // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Operational')",message="conditions must contain a condition of type Operational" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Active')",message="conditions must contain a condition of type Active" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Started')",message="conditions must contain a condition of type Started" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Schedulable')",message="conditions must contain a condition of type Schedulable" // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker resource. - // Valid values are "Kubelet" and "Etcd". + // name is the name of the resource. + // Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". // The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. // The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + // The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + // script presence rather than a pacemaker-managed resource. // Fencing agents are tracked separately in the node's fencingAgents field. // +required Name PacemakerClusterResourceName `json:"name,omitempty"` } -// PacemakerClusterAlertAgentScriptStatus represents the presence of an alert -// agent's script on a specific node. Alert agent registration is cluster-wide, -// but the script it invokes must exist locally on whichever node the triggering -// event occurs on, since Pacemaker executes it there — this is tracked per node -type PacemakerClusterAlertAgentScriptStatus struct { - // conditions represent the observations of the alert agent script's state on this node. - // Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - // file exists and is executable on this node). - // If this script's presence has not yet been observed by the status collector, publish - // these conditions with status "Unknown" and reason "Pending". - // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - // +listType=map - // +listMapKey=type - // +kubebuilder:validation:MinItems=2 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'ScriptPresent')",message="conditions must contain a condition of type ScriptPresent" - // +required - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // name is the name of the pacemaker alert agent this script belongs to. This field is required. - // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - // +required - Name PacemakerClusterAlertAgentName `json:"name,omitempty"` -} - // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PacemakerClusterList contains a list of PacemakerCluster objects. PacemakerCluster is a cluster-scoped singleton // resource; only one instance named "cluster" may exist. This list type exists only to satisfy Kubernetes API diff --git a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 0cad2322cef..b79bd64ee97 100644 --- a/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -59,10 +59,6 @@ spec: The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. - A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - collector that supports it has completed a successful collection; its absence is not a - validation error and does not indicate a failure. This preserves compatibility with an older - status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -190,122 +186,6 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic - alertAgentScripts: - description: |- - alertAgentScripts contains the presence status of each alert agent's script on - this node. Alert agents are registered cluster-wide in the CIB, - but their scripts are delivered independently to each node by MCO, so presence - is tracked per node to catch delivery gaps between nodes. - This field is optional and is omitted when script-presence status has not yet - been collected by the status collector (including by a collector version that - predates this field). When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentScriptStatus represents the presence of an alert - agent's script on a specific node. Alert agent registration is cluster-wide, - but the script it invokes must exist locally on whichever node the triggering - event occurs on, since Pacemaker executes it there — this is tracked per node - properties: - conditions: - description: |- - conditions represent the observations of the alert agent script's state on this node. - Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - file exists and is executable on this node). - If this script's presence has not yet been observed by the status collector, publish - these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect - of the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, - False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in - foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type - Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - ScriptPresent - rule: self.exists(c, c.type == 'ScriptPresent') - name: - description: |- - name is the name of the pacemaker alert agent this script belongs to. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. @@ -572,21 +452,29 @@ spec: rule: '!format.dns1123Subdomain().validate(self).hasValue()' resources: description: |- - resources contains the status of pacemaker resources scheduled on this node. + resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. - For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - Both resources are required to be present, so the array must contain at least 2 items. - Valid resource names are "Kubelet" and "Etcd". + For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + per node. Both are required to be present, so the array must contain at least 2 items. + The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + and whether its script is present on this node. Alert-agent entries are + optional and are omitted when a status collector version that predates them has not reported them. + Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". Fencing agents are tracked separately in the fencingAgents field. items: description: |- - PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. + PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. - For Two Node OpenShift with Fencing, we track two resources per node: + For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: - Kubelet (the Kubernetes node agent and a prerequisite for etcd) - Etcd (the distributed key-value store) + The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert + agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies + to it: the required conditions are enforced conditionally based on the resource name. + Fencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled. properties: @@ -603,7 +491,15 @@ spec: The "Active" condition tracks whether the resource is active (available to be used). The "Started" condition tracks whether the resource is started. The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - Each of these conditions is required, so the array must contain at least 8 items. + Which conditions are required depends on the resource name: + - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + above are required, so the array must contain at least 8 items. + - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + required, so the array must contain at least 3 items. The remaining condition types do not + apply to an alert agent and may be omitted. + The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + are enforced by name-gated validation rules on this type. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -661,7 +557,7 @@ spec: - type type: object maxItems: 16 - minItems: 8 + minItems: 3 type: array x-kubernetes-list-map-keys: - type @@ -670,42 +566,37 @@ spec: - message: conditions must contain a condition of type Healthy rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - InService - rule: self.exists(c, c.type == 'InService') - - message: conditions must contain a condition of type - Managed - rule: self.exists(c, c.type == 'Managed') - message: conditions must contain a condition of type Enabled rule: self.exists(c, c.type == 'Enabled') - message: conditions must contain a condition of type Operational rule: self.exists(c, c.type == 'Operational') - - message: conditions must contain a condition of type - Active - rule: self.exists(c, c.type == 'Active') - - message: conditions must contain a condition of type - Started - rule: self.exists(c, c.type == 'Started') - - message: conditions must contain a condition of type - Schedulable - rule: self.exists(c, c.type == 'Schedulable') name: description: |- - name is the name of the pacemaker resource. - Valid values are "Kubelet" and "Etcd". + name is the name of the resource. + Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field. enum: - Kubelet - Etcd + - TaintAlertAgent + - UntaintAlertAgent type: string required: - conditions - name type: object + x-kubernetes-validations: + - message: conditions must contain InService, Managed, Active, + Started, and Schedulable for Kubelet and Etcd resources + rule: '!(self.name == ''Kubelet'' || self.name == ''Etcd'') + || [''InService'',''Managed'',''Active'',''Started'',''Schedulable''].all(t, + self.conditions.exists(c, c.type == t))' maxItems: 8 minItems: 2 type: array diff --git a/etcd/v1/zz_generated.deepcopy.go b/etcd/v1/zz_generated.deepcopy.go index acaedbcfe33..c529240e40c 100644 --- a/etcd/v1/zz_generated.deepcopy.go +++ b/etcd/v1/zz_generated.deepcopy.go @@ -37,29 +37,6 @@ func (in *PacemakerCluster) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopyInto(out *PacemakerClusterAlertAgentScriptStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]metav1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentScriptStatus. -func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAlertAgentScriptStatus { - if in == nil { - return nil - } - out := new(PacemakerClusterAlertAgentScriptStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -145,13 +122,6 @@ func (in *PacemakerClusterNodeStatus) DeepCopyInto(out *PacemakerClusterNodeStat (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.AlertAgentScripts != nil { - in, out := &in.AlertAgentScripts, &out.AlertAgentScripts - *out = make([]PacemakerClusterAlertAgentScriptStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } return } diff --git a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index ee1fe45ec9c..85f91f76971 100644 --- a/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -60,10 +60,6 @@ spec: The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. - A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - collector that supports it has completed a successful collection; its absence is not a - validation error and does not indicate a failure. This preserves compatibility with an older - status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -191,122 +187,6 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic - alertAgentScripts: - description: |- - alertAgentScripts contains the presence status of each alert agent's script on - this node. Alert agents are registered cluster-wide in the CIB, - but their scripts are delivered independently to each node by MCO, so presence - is tracked per node to catch delivery gaps between nodes. - This field is optional and is omitted when script-presence status has not yet - been collected by the status collector (including by a collector version that - predates this field). When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentScriptStatus represents the presence of an alert - agent's script on a specific node. Alert agent registration is cluster-wide, - but the script it invokes must exist locally on whichever node the triggering - event occurs on, since Pacemaker executes it there — this is tracked per node - properties: - conditions: - description: |- - conditions represent the observations of the alert agent script's state on this node. - Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - file exists and is executable on this node). - If this script's presence has not yet been observed by the status collector, publish - these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect - of the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, - False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in - foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type - Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - ScriptPresent - rule: self.exists(c, c.type == 'ScriptPresent') - name: - description: |- - name is the name of the pacemaker alert agent this script belongs to. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. @@ -573,21 +453,29 @@ spec: rule: '!format.dns1123Subdomain().validate(self).hasValue()' resources: description: |- - resources contains the status of pacemaker resources scheduled on this node. + resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. - For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - Both resources are required to be present, so the array must contain at least 2 items. - Valid resource names are "Kubelet" and "Etcd". + For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + per node. Both are required to be present, so the array must contain at least 2 items. + The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + and whether its script is present on this node. Alert-agent entries are + optional and are omitted when a status collector version that predates them has not reported them. + Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". Fencing agents are tracked separately in the fencingAgents field. items: description: |- - PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. + PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. - For Two Node OpenShift with Fencing, we track two resources per node: + For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: - Kubelet (the Kubernetes node agent and a prerequisite for etcd) - Etcd (the distributed key-value store) + The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert + agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies + to it: the required conditions are enforced conditionally based on the resource name. + Fencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled. properties: @@ -604,7 +492,15 @@ spec: The "Active" condition tracks whether the resource is active (available to be used). The "Started" condition tracks whether the resource is started. The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - Each of these conditions is required, so the array must contain at least 8 items. + Which conditions are required depends on the resource name: + - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + above are required, so the array must contain at least 8 items. + - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + required, so the array must contain at least 3 items. The remaining condition types do not + apply to an alert agent and may be omitted. + The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + are enforced by name-gated validation rules on this type. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -662,7 +558,7 @@ spec: - type type: object maxItems: 16 - minItems: 8 + minItems: 3 type: array x-kubernetes-list-map-keys: - type @@ -671,42 +567,37 @@ spec: - message: conditions must contain a condition of type Healthy rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - InService - rule: self.exists(c, c.type == 'InService') - - message: conditions must contain a condition of type - Managed - rule: self.exists(c, c.type == 'Managed') - message: conditions must contain a condition of type Enabled rule: self.exists(c, c.type == 'Enabled') - message: conditions must contain a condition of type Operational rule: self.exists(c, c.type == 'Operational') - - message: conditions must contain a condition of type - Active - rule: self.exists(c, c.type == 'Active') - - message: conditions must contain a condition of type - Started - rule: self.exists(c, c.type == 'Started') - - message: conditions must contain a condition of type - Schedulable - rule: self.exists(c, c.type == 'Schedulable') name: description: |- - name is the name of the pacemaker resource. - Valid values are "Kubelet" and "Etcd". + name is the name of the resource. + Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field. enum: - Kubelet - Etcd + - TaintAlertAgent + - UntaintAlertAgent type: string required: - conditions - name type: object + x-kubernetes-validations: + - message: conditions must contain InService, Managed, Active, + Started, and Schedulable for Kubelet and Etcd resources + rule: '!(self.name == ''Kubelet'' || self.name == ''Etcd'') + || [''InService'',''Managed'',''Active'',''Started'',''Schedulable''].all(t, + self.conditions.exists(c, c.type == t))' maxItems: 8 minItems: 2 type: array diff --git a/etcd/v1/zz_generated.model_name.go b/etcd/v1/zz_generated.model_name.go index 9e7b6e26bb0..9e13a7167e4 100644 --- a/etcd/v1/zz_generated.model_name.go +++ b/etcd/v1/zz_generated.model_name.go @@ -10,11 +10,6 @@ func (in PacemakerCluster) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerCluster" } -// OpenAPIModelName returns the OpenAPI model name for this type. -func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { - return "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus" -} - // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1/zz_generated.swagger_doc_generated.go b/etcd/v1/zz_generated.swagger_doc_generated.go index 15d8600389b..f22b825fd6f 100644 --- a/etcd/v1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1/zz_generated.swagger_doc_generated.go @@ -21,16 +21,6 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { return map_PacemakerCluster } -var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ - "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "name": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", -} - -func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { - return map_PacemakerClusterAlertAgentScriptStatus -} - var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -53,13 +43,12 @@ func (PacemakerClusterList) SwaggerDoc() map[string]string { } var map_PacemakerClusterNodeStatus = map[string]string{ - "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", - "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", - "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", - "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", - "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", - "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", - "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", + "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", + "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", + "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", + "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", + "resources": "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", + "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -67,9 +56,9 @@ func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { } var map_PacemakerClusterResourceStatus = map[string]string{ - "": "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", - "conditions": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", - "name": "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.", + "": "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + "conditions": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", + "name": "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.", } func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { @@ -78,7 +67,7 @@ func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterStatus = map[string]string{ "": "PacemakerClusterStatus contains the actual pacemaker cluster status information. As part of validating the status object, we need to ensure that the lastUpdated timestamp may not be set to an earlier timestamp than the current value. The validation rule checks if oldSelf has lastUpdated before comparing, to handle the initial status creation case.", - "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", } diff --git a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 450facd300f..70720b5b6da 100644 --- a/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/tests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -1934,7 +1934,7 @@ tests: message: "Schedulable" expectedStatusError: "must be a valid global unicast IPv4 or IPv6 address in canonical form" - - name: Should accept cluster status with AlertAgentsConfigured Unknown pending observation + - name: Should accept alert-agent resources with only the conditions required for alert agents initial: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster @@ -1962,11 +1962,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Alert agent registration has not yet been observed by the status collector" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2104,6 +2099,40 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" + - name: UntaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2170,11 +2199,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "Unknown" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Pending - message: "Alert agent registration has not yet been observed by the status collector" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2312,6 +2336,40 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" + - name: UntaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Operational + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptPresent + message: "Script present" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2356,7 +2414,7 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - - name: Should accept cluster status with AlertAgentsConfigured False Missing + - name: Should reject an alert-agent resource missing the Operational condition initial: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster @@ -2384,11 +2442,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "False" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Missing - message: "tnf-untaint-alert is not registered in the CIB" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2526,6 +2579,23 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" + - name: TaintAlertAgent + conditions: + - type: Healthy + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ResourceHealthy + message: "Healthy" + - type: Enabled + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: ScriptConfigured + message: "Alert agent registered in the CIB" + - type: Extra + status: "True" + lastTransitionTime: "2024-01-01T00:00:00Z" + reason: Extra + message: "Placeholder" fencingAgents: - name: master-0.example.com_redfish method: Redfish @@ -2570,7 +2640,14 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - expected: | + expectedStatusError: "conditions must contain a condition of type Operational" + - name: Should reject a Kubelet resource missing the conditions required for pacemaker-managed resources + initial: | + apiVersion: etcd.openshift.io/v1alpha1 + kind: PacemakerCluster + metadata: + name: cluster + updated: | apiVersion: etcd.openshift.io/v1alpha1 kind: PacemakerCluster metadata: @@ -2592,11 +2669,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: AsExpected message: "Expected nodes present" - - type: AlertAgentsConfigured - status: "False" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Missing - message: "tnf-untaint-alert is not registered in the CIB" lastUpdated: "2024-01-01T00:00:01Z" nodes: - nodeName: master-0.example.com @@ -2657,16 +2729,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: ResourceHealthy message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - type: Enabled status: "True" lastTransitionTime: "2024-01-01T00:00:00Z" @@ -2677,21 +2739,6 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Operational message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - name: Etcd conditions: - type: Healthy @@ -2778,1335 +2825,4 @@ tests: lastTransitionTime: "2024-01-01T00:00:00Z" reason: Schedulable message: "Schedulable" - - name: Should accept a node with alertAgentScripts entirely absent - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Should accept a node with alertAgentScripts fully populated - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - expected: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Untaint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Script present" - - name: Should reject node alertAgentScripts missing the ScriptPresent condition - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: Extra - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Extra - message: "Placeholder" - expectedStatusError: "conditions must contain a condition of type ScriptPresent" - - name: Should reject node alertAgentScripts with duplicate names - initial: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - updated: | - apiVersion: etcd.openshift.io/v1alpha1 - kind: PacemakerCluster - metadata: - name: cluster - status: - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ClusterHealthy - message: "Cluster is healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: NodeCountAsExpected - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AsExpected - message: "Expected nodes present" - lastUpdated: "2024-01-01T00:00:01Z" - nodes: - - nodeName: master-0.example.com - addresses: - - type: InternalIP - address: "192.168.1.1" - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: NodeHealthy - message: "Node healthy" - - type: Online - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Online - message: "Online" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Ready - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Ready - message: "Ready" - - type: Clean - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Clean - message: "Clean" - - type: Member - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Member - message: "Member" - - type: FencingAvailable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingAvailable - message: "Fencing available" - - type: FencingHealthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: FencingHealthy - message: "All fencing agents healthy" - resources: - - name: Kubelet - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - - name: Etcd - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - fencingAgents: - - name: master-0.example.com_redfish - method: Redfish - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: ResourceHealthy - message: "Healthy" - - type: InService - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: InService - message: "In service" - - type: Managed - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Managed - message: "Managed" - - type: Enabled - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Enabled - message: "Enabled" - - type: Operational - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Operational - message: "Operational" - - type: Active - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Active - message: "Active" - - type: Started - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Started - message: "Started" - - type: Schedulable - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Schedulable - message: "Schedulable" - alertAgentScripts: - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Present" - - name: Taint Alert Agent - conditions: - - type: Healthy - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: AlertAgentScriptHealthy - message: "Healthy" - - type: ScriptPresent - status: "True" - lastTransitionTime: "2024-01-01T00:00:00Z" - reason: Present - message: "Present" - expectedStatusError: "alert agent names must be unique" + expectedStatusError: "conditions must contain InService, Managed, Active, Started, and Schedulable for Kubelet and Etcd resources" diff --git a/etcd/v1alpha1/types_pacemakercluster.go b/etcd/v1alpha1/types_pacemakercluster.go index 3e5c2e7b404..1bff376fdfa 100644 --- a/etcd/v1alpha1/types_pacemakercluster.go +++ b/etcd/v1alpha1/types_pacemakercluster.go @@ -15,7 +15,6 @@ const ( // - ClusterInServiceConditionType // - ClusterNodeCountAsExpectedConditionType // - NodeHealthyConditionType (for each node) - // - ClusterAlertAgentsConfiguredConditionType (when populated) // When True, the cluster is healthy with reason "ClusterHealthy". // When False, the cluster is unhealthy with reason "ClusterUnhealthy". ClusterHealthyConditionType = "Healthy" @@ -31,42 +30,6 @@ const ( // When True, the expected number of nodes are present with reason "AsExpected". // When False, the node count is incorrect with reason "InsufficientNodes" or "ExcessiveNodes". ClusterNodeCountAsExpectedConditionType = "NodeCountAsExpected" - - // ClusterAlertAgentsConfiguredConditionType tracks whether all known pacemaker alert agents - // (tnf-taint-alert, tnf-untaint-alert) are registered in the CIB with the expected script path - // and event filter. Alert agents are cluster-wide CIB objects: a single registration is shared - // by all nodes via Pacemaker's CIB replication, unlike fencing agents and resources which are - // node-scoped, so this is a single aggregate condition. - // When True, all known alert agents are registered as expected with reason "Configured". - // When False, at least one alert agent is not registered with reason "Missing", or all are - // registered but at least one has an unexpected script path or event filter with reason - // "Misconfigured" (Missing takes priority over Misconfigured when both problems exist across - // different agents). The message names the specific agent(s) affected. - // When Unknown, alert agent registration has not yet been observed this run by the status - // collector with reason "Pending". This is expected to be temporary, e.g. immediately after - // upgrade or before the first successful CIB collection completes. - ClusterAlertAgentsConfiguredConditionType = "AlertAgentsConfigured" -) - -// ClusterAlertAgentsConfigured condition reasons -const ( - // ClusterAlertAgentsConfiguredReasonConfigured means all known alert agents are registered in - // the CIB with the expected script path and event filter. This is the normal operating state. - ClusterAlertAgentsConfiguredReasonConfigured = "Configured" - - // ClusterAlertAgentsConfiguredReasonMissing means at least one known alert agent is not - // registered in the CIB at all. This is an unexpected state and takes priority over - // Misconfigured when both problems exist across different agents. - ClusterAlertAgentsConfiguredReasonMissing = "Missing" - - // ClusterAlertAgentsConfiguredReasonMisconfigured means every known alert agent is registered, - // but at least one has an unexpected script path or event filter. This is an unexpected state. - ClusterAlertAgentsConfiguredReasonMisconfigured = "Misconfigured" - - // ClusterAlertAgentsConfiguredReasonPending means alert agent registration has not yet been - // observed this run by the status collector. Used only with status "Unknown". This is expected - // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. - ClusterAlertAgentsConfiguredReasonPending = "Pending" ) // ClusterHealthy condition reasons @@ -123,7 +86,6 @@ const ( // - NodeFencingAvailableConditionType // - NodeFencingHealthyConditionType // - ResourceHealthyConditionType (for each resource in the node's resources list) - // - AlertAgentScriptHealthyConditionType (for each entry in the node's alertAgentScripts list) // When True, the node is healthy with reason "NodeHealthy". // When False, the node is unhealthy with reason "NodeUnhealthy". NodeHealthyConditionType = "Healthy" @@ -315,12 +277,22 @@ const ( // In Two Node OpenShift with Fencing, we do not expect any resources to be disabled. // When True, the resource is enabled with reason "Enabled". This is the normal operating state. // When False, the resource is disabled with reason "Disabled". This is an unexpected state. + // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), an alert agent cannot be + // disabled, so this condition instead tracks whether the alert agent is registered in the CIB with + // the expected script path and event filter. When True, the agent is configured with reason + // "ScriptConfigured". When False, the agent is not registered or is misconfigured. When Unknown, + // registration has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceEnabledConditionType = "Enabled" // ResourceOperationalConditionType tracks whether a resource is operational (not failed). // A failed resource is one that is not able to start or is in an error state. // When True, the resource is operational with reason "Operational". This is the normal operating state. // When False, the resource has failed with reason "Failed". This is an unexpected state. + // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), this condition instead + // tracks whether the alert agent's script file is present and executable on this node, since the + // script is delivered independently to each node by MCO. When True, the script is present with + // reason "ScriptPresent". When False, the script is missing from this node. When Unknown, presence + // has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceOperationalConditionType = "Operational" // ResourceActiveConditionType tracks whether a resource is active. @@ -388,6 +360,16 @@ const ( // Resources that are disabled are stopped and not automatically managed or started by the cluster. // This is an unexpected state. ResourceEnabledReasonDisabled = "Disabled" + + // ResourceEnabledReasonScriptConfigured means an alert-agent script resource is registered in the + // CIB with the expected script path and event filter. This is the normal operating state for an + // alert-agent resource and is used in place of "Enabled". + ResourceEnabledReasonScriptConfigured = "ScriptConfigured" + + // ResourceEnabledReasonPending means an alert-agent script resource's CIB registration has not yet + // been observed this run by the status collector. Used only with status "Unknown". This is expected + // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. + ResourceEnabledReasonPending = "Pending" ) // ResourceOperational condition reasons @@ -399,6 +381,16 @@ const ( // ResourceOperationalReasonFailed means the resource has failed. // A failed resource is one that is not able to start or is in an error state. This is an unexpected state. ResourceOperationalReasonFailed = "Failed" + + // ResourceOperationalReasonScriptPresent means an alert-agent script resource's script file is + // present and executable on this node. This is the normal operating state for an alert-agent + // resource and is used in place of "Operational". + ResourceOperationalReasonScriptPresent = "ScriptPresent" + + // ResourceOperationalReasonPending means an alert-agent script resource's presence on this node has + // not yet been observed this run by the status collector. Used only with status "Unknown". This is + // expected to be temporary, e.g. before MCO has delivered the script or before the first collection. + ResourceOperationalReasonPending = "Pending" ) // ResourceActive condition reasons @@ -436,55 +428,6 @@ const ( ResourceSchedulableReasonUnschedulable = "Unschedulable" ) -// Node-level condition types for PacemakerCluster.status.nodes[].alertAgentScripts[].conditions -const ( - // AlertAgentScriptHealthyConditionType tracks the overall health of an alert agent's script on this node. - // This is an aggregate condition that reflects the health of all alert agent script-level conditions. - // Specifically, it aggregates the following conditions: - // - AlertAgentScriptPresentConditionType - // When True, the alert agent script is healthy with reason "AlertAgentScriptHealthy". - // When False, the alert agent script is unhealthy with reason "AlertAgentScriptUnhealthy". - // When Unknown, the script's presence has not yet been observed by the status collector with - // reason "Pending". This is expected to be temporary. - AlertAgentScriptHealthyConditionType = "Healthy" - - // AlertAgentScriptPresentConditionType tracks whether the alert agent's script file is present - // and executable on this node. - // When True, the script is present and executable with reason "Present". - // When False, the script is missing from this node with reason "Missing". This is an unexpected state. - // When Unknown, presence has not yet been observed by the status collector with reason "Pending". - // This is expected to be temporary. - AlertAgentScriptPresentConditionType = "ScriptPresent" -) - -// AlertAgentScriptHealthy condition reasons -const ( - // AlertAgentScriptHealthyReasonHealthy means the alert agent script is healthy and operating normally. - AlertAgentScriptHealthyReasonHealthy = "AlertAgentScriptHealthy" - - // AlertAgentScriptHealthyReasonUnhealthy means the alert agent script has issues that need investigation. - AlertAgentScriptHealthyReasonUnhealthy = "AlertAgentScriptUnhealthy" - - // AlertAgentScriptHealthyReasonPending means the alert agent script's health has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentScriptHealthyReasonPending = "Pending" -) - -// AlertAgentScriptPresent condition reasons -const ( - // AlertAgentScriptPresentReasonPresent means the alert agent script is present and executable on this node. - // This is the normal operating state. - AlertAgentScriptPresentReasonPresent = "Present" - - // AlertAgentScriptPresentReasonMissing means the alert agent script is missing from this node. - // This is an unexpected state that can occur when MCO has not yet delivered the script to this node. - AlertAgentScriptPresentReasonMissing = "Missing" - - // AlertAgentScriptPresentReasonPending means the script's presence on this node has not yet been - // observed by the status collector. This is expected to be temporary. - AlertAgentScriptPresentReasonPending = "Pending" -) - // PacemakerNodeAddressType represents the type of a node address. // Currently only InternalIP is supported. // +kubebuilder:validation:Enum=InternalIP @@ -518,8 +461,10 @@ type PacemakerNodeAddress struct { } // PacemakerClusterResourceName represents the name of a pacemaker resource. +// This includes both pacemaker-managed resources (Kubelet, Etcd) and pacemaker +// alert agents whose scripts are tracked per node (e.g. TaintAlertAgent, UntaintAlertAgent). // Fencing agents are tracked separately in the fencingAgents field. -// +kubebuilder:validation:Enum=Kubelet;Etcd +// +kubebuilder:validation:Enum=Kubelet;Etcd;TaintAlertAgent;UntaintAlertAgent // +enum type PacemakerClusterResourceName string @@ -532,20 +477,16 @@ const ( // PacemakerClusterResourceNameEtcd is the etcd pacemaker resource. // The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. PacemakerClusterResourceNameEtcd PacemakerClusterResourceName = "Etcd" -) -// PacemakerClusterAlertAgentName represents the name of a pacemaker alert agent. -// +kubebuilder:validation:Enum=Taint Alert Agent;Untaint Alert Agent -// +enum -type PacemakerClusterAlertAgentName string + // PacemakerClusterResourceNameTaintAlertAgent is the alert agent that taints a node after it is fenced. + // Its entry tracks the alert agent's configuration in the CIB + // and the presence of its script on this node. + PacemakerClusterResourceNameTaintAlertAgent PacemakerClusterResourceName = "TaintAlertAgent" -// PacemakerClusterAlertAgentName values -const ( - // PacemakerClusterAlertAgentNameTaint is the alert agent that taints a node after it is fenced. - PacemakerClusterAlertAgentNameTaint PacemakerClusterAlertAgentName = "Taint Alert Agent" - - // PacemakerClusterAlertAgentNameUntaint is the alert agent that removes a node's taint once it rejoins the cluster. - PacemakerClusterAlertAgentNameUntaint PacemakerClusterAlertAgentName = "Untaint Alert Agent" + // PacemakerClusterResourceNameUntaintAlertAgent is the alert agent that removes a node's taint once + // it rejoins the cluster. Its entry tracks the alert agent's + // configuration in the CIB and the presence of its script on this node. + PacemakerClusterResourceNameUntaintAlertAgent PacemakerClusterResourceName = "UntaintAlertAgent" ) // FencingMethod represents the method used by a fencing agent to isolate failed nodes. @@ -608,10 +549,6 @@ type PacemakerClusterStatus struct { // The "InService" condition tracks whether the cluster is in service (not in maintenance mode). // The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. // Each of these three conditions is required, so the array must contain at least 3 items. - // A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - // collector that supports it has completed a successful collection; its absence is not a - // validation error and does not indicate a failure. This preserves compatibility with an older - // status collector that didn't support alert agents. // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=3 @@ -694,11 +631,15 @@ type PacemakerClusterNodeStatus struct { // +required Addresses []PacemakerNodeAddress `json:"addresses,omitempty"` - // resources contains the status of pacemaker resources scheduled on this node. + // resources contains the status of pacemaker resources tracked on this node. // Each resource entry includes the resource name and its health conditions. - // For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - // Both resources are required to be present, so the array must contain at least 2 items. - // Valid resource names are "Kubelet" and "Etcd". + // For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + // per node. Both are required to be present, so the array must contain at least 2 items. + // The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + // "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + // and whether its script is present on this node. Alert-agent entries are + // optional and are omitted when a status collector version that predates them has not reported them. + // Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". // Fencing agents are tracked separately in the fencingAgents field. // +listType=map // +listMapKey=name @@ -724,22 +665,6 @@ type PacemakerClusterNodeStatus struct { // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="fencing agent names must be unique" // +required FencingAgents []PacemakerClusterFencingAgentStatus `json:"fencingAgents,omitempty"` - - // alertAgentScripts contains the presence status of each alert agent's script on - // this node. Alert agents are registered cluster-wide in the CIB, - // but their scripts are delivered independently to each node by MCO, so presence - // is tracked per node to catch delivery gaps between nodes. - // This field is optional and is omitted when script-presence status has not yet - // been collected by the status collector (including by a collector version that - // predates this field). When present, this array contains at most 8 entries. - // Names must be unique within this array. - // +listType=map - // +listMapKey=name - // +kubebuilder:validation:MinItems=0 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.name == y.name))",message="alert agent names must be unique" - // +optional - AlertAgentScripts []PacemakerClusterAlertAgentScriptStatus `json:"alertAgentScripts,omitempty"` } // PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. @@ -793,15 +718,20 @@ type PacemakerClusterFencingAgentStatus struct { Method FencingMethod `json:"method,omitempty"` } -// PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. +// PacemakerClusterResourceStatus represents the status of a resource tracked on a node. // A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or // applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. -// For Two Node OpenShift with Fencing, we track two resources per node: +// For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: // - Kubelet (the Kubernetes node agent and a prerequisite for etcd) // - Etcd (the distributed key-value store) // +// The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert +// agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies +// to it: the required conditions are enforced conditionally based on the resource name. +// // Fencing agents are tracked separately in the fencingAgents field because they are mapped to // their target node (the node they can fence), not the node where monitoring operations are scheduled. +// +kubebuilder:validation:XValidation:rule="!(self.name == 'Kubelet' || self.name == 'Etcd') || ['InService','Managed','Active','Started','Schedulable'].all(t, self.conditions.exists(c, c.type == t))",message="conditions must contain InService, Managed, Active, Started, and Schedulable for Kubelet and Etcd resources" type PacemakerClusterResourceStatus struct { // conditions represent the observations of the resource's current state. // Known condition types are: "Healthy", "InService", "Managed", "Enabled", "Operational", @@ -814,58 +744,36 @@ type PacemakerClusterResourceStatus struct { // The "Active" condition tracks whether the resource is active (available to be used). // The "Started" condition tracks whether the resource is started. // The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - // Each of these conditions is required, so the array must contain at least 8 items. + // Which conditions are required depends on the resource name: + // - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + // above are required, so the array must contain at least 8 items. + // - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + // "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + // required, so the array must contain at least 3 items. The remaining condition types do not + // apply to an alert agent and may be omitted. + // The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + // are enforced by name-gated validation rules on this type. // +listType=map // +listMapKey=type - // +kubebuilder:validation:MinItems=8 + // +kubebuilder:validation:MinItems=3 // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'InService')",message="conditions must contain a condition of type InService" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Managed')",message="conditions must contain a condition of type Managed" // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Enabled')",message="conditions must contain a condition of type Enabled" // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Operational')",message="conditions must contain a condition of type Operational" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Active')",message="conditions must contain a condition of type Active" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Started')",message="conditions must contain a condition of type Started" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Schedulable')",message="conditions must contain a condition of type Schedulable" // +required Conditions []metav1.Condition `json:"conditions,omitempty"` - // name is the name of the pacemaker resource. - // Valid values are "Kubelet" and "Etcd". + // name is the name of the resource. + // Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". // The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. // The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + // The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + // script presence rather than a pacemaker-managed resource. // Fencing agents are tracked separately in the node's fencingAgents field. // +required Name PacemakerClusterResourceName `json:"name,omitempty"` } -// PacemakerClusterAlertAgentScriptStatus represents the presence of an alert -// agent's script on a specific node. Alert agent registration is cluster-wide, -// but the script it invokes must exist locally on whichever node the triggering -// event occurs on, since Pacemaker executes it there — this is tracked per node -type PacemakerClusterAlertAgentScriptStatus struct { - // conditions represent the observations of the alert agent script's state on this node. - // Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - // file exists and is executable on this node). - // If this script's presence has not yet been observed by the status collector, publish - // these conditions with status "Unknown" and reason "Pending". - // Reserve "False" for an observed failure. - // Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - // +listType=map - // +listMapKey=type - // +kubebuilder:validation:MinItems=2 - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'Healthy')",message="conditions must contain a condition of type Healthy" - // +kubebuilder:validation:XValidation:rule="self.exists(c, c.type == 'ScriptPresent')",message="conditions must contain a condition of type ScriptPresent" - // +required - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // name is the name of the pacemaker alert agent this script belongs to. This field is required. - // Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - // +required - Name PacemakerClusterAlertAgentName `json:"name,omitempty"` -} - // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PacemakerClusterList contains a list of PacemakerCluster objects. PacemakerCluster is a cluster-scoped singleton // resource; only one instance named "cluster" may exist. This list type exists only to satisfy Kubernetes API diff --git a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml index 663cd423ca3..6a02505a27d 100644 --- a/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml +++ b/etcd/v1alpha1/zz_generated.crd-manifests/0000_25_etcd_01_pacemakerclusters.crd.yaml @@ -59,10 +59,6 @@ spec: The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. - A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - collector that supports it has completed a successful collection; its absence is not a - validation error and does not indicate a failure. This preserves compatibility with an older - status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -190,122 +186,6 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic - alertAgentScripts: - description: |- - alertAgentScripts contains the presence status of each alert agent's script on - this node. Alert agents are registered cluster-wide in the CIB, - but their scripts are delivered independently to each node by MCO, so presence - is tracked per node to catch delivery gaps between nodes. - This field is optional and is omitted when script-presence status has not yet - been collected by the status collector (including by a collector version that - predates this field). When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentScriptStatus represents the presence of an alert - agent's script on a specific node. Alert agent registration is cluster-wide, - but the script it invokes must exist locally on whichever node the triggering - event occurs on, since Pacemaker executes it there — this is tracked per node - properties: - conditions: - description: |- - conditions represent the observations of the alert agent script's state on this node. - Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - file exists and is executable on this node). - If this script's presence has not yet been observed by the status collector, publish - these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect - of the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, - False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in - foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type - Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - ScriptPresent - rule: self.exists(c, c.type == 'ScriptPresent') - name: - description: |- - name is the name of the pacemaker alert agent this script belongs to. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. @@ -572,21 +452,29 @@ spec: rule: '!format.dns1123Subdomain().validate(self).hasValue()' resources: description: |- - resources contains the status of pacemaker resources scheduled on this node. + resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. - For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - Both resources are required to be present, so the array must contain at least 2 items. - Valid resource names are "Kubelet" and "Etcd". + For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + per node. Both are required to be present, so the array must contain at least 2 items. + The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + and whether its script is present on this node. Alert-agent entries are + optional and are omitted when a status collector version that predates them has not reported them. + Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". Fencing agents are tracked separately in the fencingAgents field. items: description: |- - PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. + PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. - For Two Node OpenShift with Fencing, we track two resources per node: + For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: - Kubelet (the Kubernetes node agent and a prerequisite for etcd) - Etcd (the distributed key-value store) + The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert + agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies + to it: the required conditions are enforced conditionally based on the resource name. + Fencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled. properties: @@ -603,7 +491,15 @@ spec: The "Active" condition tracks whether the resource is active (available to be used). The "Started" condition tracks whether the resource is started. The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - Each of these conditions is required, so the array must contain at least 8 items. + Which conditions are required depends on the resource name: + - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + above are required, so the array must contain at least 8 items. + - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + required, so the array must contain at least 3 items. The remaining condition types do not + apply to an alert agent and may be omitted. + The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + are enforced by name-gated validation rules on this type. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -661,7 +557,7 @@ spec: - type type: object maxItems: 16 - minItems: 8 + minItems: 3 type: array x-kubernetes-list-map-keys: - type @@ -670,42 +566,37 @@ spec: - message: conditions must contain a condition of type Healthy rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - InService - rule: self.exists(c, c.type == 'InService') - - message: conditions must contain a condition of type - Managed - rule: self.exists(c, c.type == 'Managed') - message: conditions must contain a condition of type Enabled rule: self.exists(c, c.type == 'Enabled') - message: conditions must contain a condition of type Operational rule: self.exists(c, c.type == 'Operational') - - message: conditions must contain a condition of type - Active - rule: self.exists(c, c.type == 'Active') - - message: conditions must contain a condition of type - Started - rule: self.exists(c, c.type == 'Started') - - message: conditions must contain a condition of type - Schedulable - rule: self.exists(c, c.type == 'Schedulable') name: description: |- - name is the name of the pacemaker resource. - Valid values are "Kubelet" and "Etcd". + name is the name of the resource. + Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field. enum: - Kubelet - Etcd + - TaintAlertAgent + - UntaintAlertAgent type: string required: - conditions - name type: object + x-kubernetes-validations: + - message: conditions must contain InService, Managed, Active, + Started, and Schedulable for Kubelet and Etcd resources + rule: '!(self.name == ''Kubelet'' || self.name == ''Etcd'') + || [''InService'',''Managed'',''Active'',''Started'',''Schedulable''].all(t, + self.conditions.exists(c, c.type == t))' maxItems: 8 minItems: 2 type: array diff --git a/etcd/v1alpha1/zz_generated.deepcopy.go b/etcd/v1alpha1/zz_generated.deepcopy.go index 95e6c92d3de..17bf978510d 100644 --- a/etcd/v1alpha1/zz_generated.deepcopy.go +++ b/etcd/v1alpha1/zz_generated.deepcopy.go @@ -37,29 +37,6 @@ func (in *PacemakerCluster) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopyInto(out *PacemakerClusterAlertAgentScriptStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PacemakerClusterAlertAgentScriptStatus. -func (in *PacemakerClusterAlertAgentScriptStatus) DeepCopy() *PacemakerClusterAlertAgentScriptStatus { - if in == nil { - return nil - } - out := new(PacemakerClusterAlertAgentScriptStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PacemakerClusterFencingAgentStatus) DeepCopyInto(out *PacemakerClusterFencingAgentStatus) { *out = *in @@ -145,13 +122,6 @@ func (in *PacemakerClusterNodeStatus) DeepCopyInto(out *PacemakerClusterNodeStat (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.AlertAgentScripts != nil { - in, out := &in.AlertAgentScripts, &out.AlertAgentScripts - *out = make([]PacemakerClusterAlertAgentScriptStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } return } diff --git a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml index 7ac949a6fcc..b87be5507b8 100644 --- a/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml +++ b/etcd/v1alpha1/zz_generated.featuregated-crd-manifests/pacemakerclusters.etcd.openshift.io/DualReplica.yaml @@ -60,10 +60,6 @@ spec: The "InService" condition tracks whether the cluster is in service (not in maintenance mode). The "NodeCountAsExpected" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. - A fourth, optional condition type, "AlertAgentsConfigured", may also be present once a status - collector that supports it has completed a successful collection; its absence is not a - validation error and does not indicate a failure. This preserves compatibility with an older - status collector that didn't support alert agents. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -191,122 +187,6 @@ spec: minItems: 1 type: array x-kubernetes-list-type: atomic - alertAgentScripts: - description: |- - alertAgentScripts contains the presence status of each alert agent's script on - this node. Alert agents are registered cluster-wide in the CIB, - but their scripts are delivered independently to each node by MCO, so presence - is tracked per node to catch delivery gaps between nodes. - This field is optional and is omitted when script-presence status has not yet - been collected by the status collector (including by a collector version that - predates this field). When present, this array contains at most 8 entries. - Names must be unique within this array. - items: - description: |- - PacemakerClusterAlertAgentScriptStatus represents the presence of an alert - agent's script on a specific node. Alert agent registration is cluster-wide, - but the script it invokes must exist locally on whichever node the triggering - event occurs on, since Pacemaker executes it there — this is tracked per node - properties: - conditions: - description: |- - conditions represent the observations of the alert agent script's state on this node. - Known condition types are "Healthy" (aggregate) and "ScriptPresent" (the script - file exists and is executable on this node). - If this script's presence has not yet been observed by the status collector, publish - these conditions with status "Unknown" and reason "Pending". - Reserve "False" for an observed failure. - Each of these conditions is required, so the array must contain at least 2 and at most 8 items. - items: - description: Condition contains details for one aspect - of the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, - False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in - foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 2 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: conditions must contain a condition of type - Healthy - rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - ScriptPresent - rule: self.exists(c, c.type == 'ScriptPresent') - name: - description: |- - name is the name of the pacemaker alert agent this script belongs to. This field is required. - Valid values are "Taint Alert Agent" and "Untaint Alert Agent". - enum: - - Taint Alert Agent - - Untaint Alert Agent - type: string - required: - - conditions - - name - type: object - maxItems: 8 - minItems: 0 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: alert agent names must be unique - rule: self.all(x, self.exists_one(y, x.name == y.name)) conditions: description: |- conditions represent the observations of the node's current state. @@ -573,21 +453,29 @@ spec: rule: '!format.dns1123Subdomain().validate(self).hasValue()' resources: description: |- - resources contains the status of pacemaker resources scheduled on this node. + resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. - For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. - Both resources are required to be present, so the array must contain at least 2 items. - Valid resource names are "Kubelet" and "Etcd". + For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources + per node. Both are required to be present, so the array must contain at least 2 items. + The array may also contain optional alert-agent script entries named "TaintAlertAgent" and + "UntaintAlertAgent". Their entries track whether the alert agent is configured in the CIB + and whether its script is present on this node. Alert-agent entries are + optional and are omitted when a status collector version that predates them has not reported them. + Valid resource names are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". Fencing agents are tracked separately in the fencingAgents field. items: description: |- - PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. + PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. - For Two Node OpenShift with Fencing, we track two resources per node: + For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node: - Kubelet (the Kubernetes node agent and a prerequisite for etcd) - Etcd (the distributed key-value store) + The same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert + agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies + to it: the required conditions are enforced conditionally based on the resource name. + Fencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled. properties: @@ -604,7 +492,15 @@ spec: The "Active" condition tracks whether the resource is active (available to be used). The "Started" condition tracks whether the resource is started. The "Schedulable" condition tracks whether the resource is schedulable (not blocked). - Each of these conditions is required, so the array must contain at least 8 items. + Which conditions are required depends on the resource name: + - For the pacemaker-managed resources "Kubelet" and "Etcd", all eight condition types listed + above are required, so the array must contain at least 8 items. + - For the alert-agent resources "TaintAlertAgent" and "UntaintAlertAgent", only "Healthy", + "Enabled" (reason "ScriptConfigured"), and "Operational" (reason "ScriptPresent") are + required, so the array must contain at least 3 items. The remaining condition types do not + apply to an alert agent and may be omitted. + The array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements + are enforced by name-gated validation rules on this type. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -662,7 +558,7 @@ spec: - type type: object maxItems: 16 - minItems: 8 + minItems: 3 type: array x-kubernetes-list-map-keys: - type @@ -671,42 +567,37 @@ spec: - message: conditions must contain a condition of type Healthy rule: self.exists(c, c.type == 'Healthy') - - message: conditions must contain a condition of type - InService - rule: self.exists(c, c.type == 'InService') - - message: conditions must contain a condition of type - Managed - rule: self.exists(c, c.type == 'Managed') - message: conditions must contain a condition of type Enabled rule: self.exists(c, c.type == 'Enabled') - message: conditions must contain a condition of type Operational rule: self.exists(c, c.type == 'Operational') - - message: conditions must contain a condition of type - Active - rule: self.exists(c, c.type == 'Active') - - message: conditions must contain a condition of type - Started - rule: self.exists(c, c.type == 'Started') - - message: conditions must contain a condition of type - Schedulable - rule: self.exists(c, c.type == 'Schedulable') name: description: |- - name is the name of the pacemaker resource. - Valid values are "Kubelet" and "Etcd". + name is the name of the resource. + Valid values are "Kubelet", "Etcd", "TaintAlertAgent", and "UntaintAlertAgent". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. + The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node + script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field. enum: - Kubelet - Etcd + - TaintAlertAgent + - UntaintAlertAgent type: string required: - conditions - name type: object + x-kubernetes-validations: + - message: conditions must contain InService, Managed, Active, + Started, and Schedulable for Kubelet and Etcd resources + rule: '!(self.name == ''Kubelet'' || self.name == ''Etcd'') + || [''InService'',''Managed'',''Active'',''Started'',''Schedulable''].all(t, + self.conditions.exists(c, c.type == t))' maxItems: 8 minItems: 2 type: array diff --git a/etcd/v1alpha1/zz_generated.model_name.go b/etcd/v1alpha1/zz_generated.model_name.go index ff47b599dd2..11fac8dad4c 100644 --- a/etcd/v1alpha1/zz_generated.model_name.go +++ b/etcd/v1alpha1/zz_generated.model_name.go @@ -10,11 +10,6 @@ func (in PacemakerCluster) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerCluster" } -// OpenAPIModelName returns the OpenAPI model name for this type. -func (in PacemakerClusterAlertAgentScriptStatus) OpenAPIModelName() string { - return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus" -} - // OpenAPIModelName returns the OpenAPI model name for this type. func (in PacemakerClusterFencingAgentStatus) OpenAPIModelName() string { return "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus" diff --git a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go index a49f73f5298..a5b3c737913 100644 --- a/etcd/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/etcd/v1alpha1/zz_generated.swagger_doc_generated.go @@ -21,16 +21,6 @@ func (PacemakerCluster) SwaggerDoc() map[string]string { return map_PacemakerCluster } -var map_PacemakerClusterAlertAgentScriptStatus = map[string]string{ - "": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "conditions": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "name": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".", -} - -func (PacemakerClusterAlertAgentScriptStatus) SwaggerDoc() map[string]string { - return map_PacemakerClusterAlertAgentScriptStatus -} - var map_PacemakerClusterFencingAgentStatus = map[string]string{ "": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "conditions": "conditions represent the observations of the fencing agent's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the fencing agent. The \"InService\" condition tracks whether the fencing agent is in service (not in maintenance mode). The \"Managed\" condition tracks whether the fencing agent is managed by pacemaker. The \"Enabled\" condition tracks whether the fencing agent is enabled. The \"Operational\" condition tracks whether the fencing agent is operational (not failed). The \"Active\" condition tracks whether the fencing agent is active (available to be used). The \"Started\" condition tracks whether the fencing agent is started. The \"Schedulable\" condition tracks whether the fencing agent is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", @@ -53,13 +43,12 @@ func (PacemakerClusterList) SwaggerDoc() map[string]string { } var map_PacemakerClusterNodeStatus = map[string]string{ - "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", - "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", - "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", - "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", - "resources": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", - "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", - "alertAgentScripts": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", + "": "PacemakerClusterNodeStatus represents the status of a single node in the pacemaker cluster including the node's conditions and the health of critical resources running on that node.", + "conditions": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", + "nodeName": "nodeName is the name of the node. This is expected to match the Kubernetes node's name, which must be a lowercase RFC 1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character, and be at most 253 characters in length.", + "addresses": "addresses is a list of IP addresses for the node. Pacemaker allows multiple IP addresses for Corosync communication between nodes. The first address in this list is used for IP-based peer URLs for etcd membership. Each address must be a valid global unicast IPv4 or IPv6 address in canonical form (e.g., \"192.168.1.1\" not \"192.168.001.001\", or \"2001:db8::1\" not \"2001:0db8::1\"). This excludes loopback, link-local, and multicast addresses.", + "resources": "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", + "fencingAgents": "fencingAgents contains the status of fencing agents that can fence this node. Unlike resources (which are scheduled to run on this node), fencing agents are mapped to the node they can fence (their target), not the node where monitoring operations run. Each fencing agent entry includes a unique name, fencing type, target node, and health conditions. A node is considered fence-capable if at least one fencing agent is healthy. A healthy node is expected to have at least 1 fencing agent, but the list may be empty when fencing agent discovery fails. Names must be unique within this array.", } func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { @@ -67,9 +56,9 @@ func (PacemakerClusterNodeStatus) SwaggerDoc() map[string]string { } var map_PacemakerClusterResourceStatus = map[string]string{ - "": "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", - "conditions": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", - "name": "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.", + "": "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + "conditions": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", + "name": "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.", } func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { @@ -78,7 +67,7 @@ func (PacemakerClusterResourceStatus) SwaggerDoc() map[string]string { var map_PacemakerClusterStatus = map[string]string{ "": "PacemakerClusterStatus contains the actual pacemaker cluster status information. As part of validating the status object, we need to ensure that the lastUpdated timestamp may not be set to an earlier timestamp than the current value. The validation rule checks if oldSelf has lastUpdated before comparing, to handle the initial status creation case.", - "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + "conditions": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", "lastUpdated": "lastUpdated is the timestamp when this status was last updated. This is useful for identifying stale status reports. It must be a valid timestamp in RFC3339 format. Once set, this field cannot be removed and cannot be set to an earlier timestamp than the current value.", "nodes": "nodes provides detailed status for each control-plane node in the Pacemaker cluster. While Pacemaker supports up to 32 nodes, the limit is set to 5 (max OpenShift control-plane nodes). For Two Node OpenShift with Fencing, exactly 2 nodes are expected in a healthy cluster. An empty list indicates a catastrophic failure where Pacemaker reports no nodes.", } diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 2422c354df6..43ad530eb65 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -666,7 +666,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA consolev1.Link{}.OpenAPIModelName(): schema_openshift_api_console_v1_Link(ref), consolev1.NamespaceDashboardSpec{}.OpenAPIModelName(): schema_openshift_api_console_v1_NamespaceDashboardSpec(ref), etcdv1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerCluster(ref), - etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref), etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref), etcdv1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterList(ref), etcdv1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref), @@ -674,7 +673,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA etcdv1.PacemakerClusterStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(): schema_openshift_api_etcd_v1_PacemakerNodeAddress(ref), etcdv1alpha1.PacemakerCluster{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerCluster(ref), - etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(ref), etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref), etcdv1alpha1.PacemakerClusterList{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterList(ref), etcdv1alpha1.PacemakerClusterNodeStatus{}.OpenAPIModelName(): schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref), @@ -30096,52 +30094,6 @@ func schema_openshift_api_etcd_v1_PacemakerCluster(ref common.ReferenceCallback) } } -func schema_openshift_api_etcd_v1_PacemakerClusterAlertAgentScriptStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(metav1.Condition{}.OpenAPIModelName()), - }, - }, - }, - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, - }, - }, - }, - Required: []string{"conditions", "name"}, - }, - }, - Dependencies: []string{ - metav1.Condition{}.OpenAPIModelName()}, - } -} - func schema_openshift_api_etcd_v1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -30311,7 +30263,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref common.Referenc }, }, SchemaProps: spec.SchemaProps{ - Description: "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + Description: "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30345,34 +30297,12 @@ func schema_openshift_api_etcd_v1_PacemakerClusterNodeStatus(ref common.Referenc }, }, }, - "alertAgentScripts": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "name", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName()), - }, - }, - }, - }, - }, }, Required: []string{"conditions", "nodeName", "addresses", "resources", "fencingAgents"}, }, }, Dependencies: []string{ - etcdv1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, + etcdv1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, } } @@ -30380,7 +30310,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterResourceStatus(ref common.Refe return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + Description: "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -30393,7 +30323,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterResourceStatus(ref common.Refe }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", + Description: "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30407,10 +30337,10 @@ func schema_openshift_api_etcd_v1_PacemakerClusterResourceStatus(ref common.Refe }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.", + Description: "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.\n - `\"TaintAlertAgent\"` is the alert agent that taints a node after it is fenced. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.\n - `\"UntaintAlertAgent\"` is the alert agent that removes a node's taint once it rejoins the cluster. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Etcd", "Kubelet"}, + Enum: []interface{}{"Etcd", "Kubelet", "TaintAlertAgent", "UntaintAlertAgent"}, }, }, }, @@ -30439,7 +30369,7 @@ func schema_openshift_api_etcd_v1_PacemakerClusterStatus(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30561,52 +30491,6 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerCluster(ref common.ReferenceCal } } -func schema_openshift_api_etcd_v1alpha1_PacemakerClusterAlertAgentScriptStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(metav1.Condition{}.OpenAPIModelName()), - }, - }, - }, - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"Taint Alert Agent", "Untaint Alert Agent"}, - }, - }, - }, - Required: []string{"conditions", "name"}, - }, - }, - Dependencies: []string{ - metav1.Condition{}.OpenAPIModelName()}, - } -} - func schema_openshift_api_etcd_v1alpha1_PacemakerClusterFencingAgentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -30776,7 +30660,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref common.Re }, }, SchemaProps: spec.SchemaProps{ - Description: "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + Description: "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30810,34 +30694,12 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterNodeStatus(ref common.Re }, }, }, - "alertAgentScripts": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "name", - }, - "x-kubernetes-list-type": "map", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref(etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName()), - }, - }, - }, - }, - }, }, Required: []string{"conditions", "nodeName", "addresses", "resources", "fencingAgents"}, }, }, Dependencies: []string{ - etcdv1alpha1.PacemakerClusterAlertAgentScriptStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, + etcdv1alpha1.PacemakerClusterFencingAgentStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerClusterResourceStatus{}.OpenAPIModelName(), etcdv1alpha1.PacemakerNodeAddress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, } } @@ -30845,7 +30707,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterResourceStatus(ref commo return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + Description: "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -30858,7 +30720,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterResourceStatus(ref commo }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", + Description: "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -30872,10 +30734,10 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterResourceStatus(ref commo }, "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.", + Description: "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.\n - `\"TaintAlertAgent\"` is the alert agent that taints a node after it is fenced. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.\n - `\"UntaintAlertAgent\"` is the alert agent that removes a node's taint once it rejoins the cluster. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Etcd", "Kubelet"}, + Enum: []interface{}{"Etcd", "Kubelet", "TaintAlertAgent", "UntaintAlertAgent"}, }, }, }, @@ -30904,7 +30766,7 @@ func schema_openshift_api_etcd_v1alpha1_PacemakerClusterStatus(ref common.Refere }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + Description: "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index 6a4fb3e1275..314cc4a96d7 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -16758,36 +16758,6 @@ } } }, - "com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus": { - "description": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "type": "object", - "required": [ - "conditions", - "name" - ], - "properties": { - "conditions": { - "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" - }, - "x-kubernetes-list-map-keys": [ - "type" - ], - "x-kubernetes-list-type": "map" - }, - "name": { - "description": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - "type": "string", - "enum": [ - "Taint Alert Agent", - "Untaint Alert Agent" - ] - } - } - }, "com.github.openshift.api.etcd.v1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -16873,18 +16843,6 @@ }, "x-kubernetes-list-type": "atomic" }, - "alertAgentScripts": { - "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/com.github.openshift.api.etcd.v1.PacemakerClusterAlertAgentScriptStatus" - }, - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, "conditions": { "description": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", "type": "array", @@ -16914,7 +16872,7 @@ "type": "string" }, "resources": { - "description": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + "description": "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", "type": "array", "items": { "default": {}, @@ -16928,7 +16886,7 @@ } }, "com.github.openshift.api.etcd.v1.PacemakerClusterResourceStatus": { - "description": "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + "description": "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", "type": "object", "required": [ "conditions", @@ -16936,7 +16894,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", + "description": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", "type": "array", "items": { "default": {}, @@ -16948,11 +16906,13 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.", + "description": "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.\n - `\"TaintAlertAgent\"` is the alert agent that taints a node after it is fenced. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.\n - `\"UntaintAlertAgent\"` is the alert agent that removes a node's taint once it rejoins the cluster. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.", "type": "string", "enum": [ "Etcd", - "Kubelet" + "Kubelet", + "TaintAlertAgent", + "UntaintAlertAgent" ] } } @@ -16967,7 +16927,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", "type": "array", "items": { "default": {}, @@ -17044,36 +17004,6 @@ } } }, - "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus": { - "description": "PacemakerClusterAlertAgentScriptStatus represents the presence of an alert agent's script on a specific node. Alert agent registration is cluster-wide, but the script it invokes must exist locally on whichever node the triggering event occurs on, since Pacemaker executes it there — this is tracked per node", - "type": "object", - "required": [ - "conditions", - "name" - ], - "properties": { - "conditions": { - "description": "conditions represent the observations of the alert agent script's state on this node. Known condition types are \"Healthy\" (aggregate) and \"ScriptPresent\" (the script file exists and is executable on this node). If this script's presence has not yet been observed by the status collector, publish these conditions with status \"Unknown\" and reason \"Pending\". Reserve \"False\" for an observed failure. Each of these conditions is required, so the array must contain at least 2 and at most 8 items.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" - }, - "x-kubernetes-list-map-keys": [ - "type" - ], - "x-kubernetes-list-type": "map" - }, - "name": { - "description": "name is the name of the pacemaker alert agent this script belongs to. This field is required. Valid values are \"Taint Alert Agent\" and \"Untaint Alert Agent\".\n\nPossible enum values:\n - `\"Taint Alert Agent\"` is the alert agent that taints a node after it is fenced.\n - `\"Untaint Alert Agent\"` is the alert agent that removes a node's taint once it rejoins the cluster.", - "type": "string", - "enum": [ - "Taint Alert Agent", - "Untaint Alert Agent" - ] - } - } - }, "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterFencingAgentStatus": { "description": "PacemakerClusterFencingAgentStatus represents the status of a fencing agent that can fence a node. Fencing agents are STONITH (Shoot The Other Node In The Head) devices used to isolate failed nodes. Unlike regular pacemaker resources, fencing agents are mapped to their target node (the node they can fence), not the node where their monitoring operations are scheduled.", "type": "object", @@ -17159,18 +17089,6 @@ }, "x-kubernetes-list-type": "atomic" }, - "alertAgentScripts": { - "description": "alertAgentScripts contains the presence status of each alert agent's script on this node. Alert agents are registered cluster-wide in the CIB, but their scripts are delivered independently to each node by MCO, so presence is tracked per node to catch delivery gaps between nodes. This field is optional and is omitted when script-presence status has not yet been collected by the status collector (including by a collector version that predates this field). When present, this array contains at most 8 entries. Names must be unique within this array.", - "type": "array", - "items": { - "default": {}, - "$ref": "#/definitions/com.github.openshift.api.etcd.v1alpha1.PacemakerClusterAlertAgentScriptStatus" - }, - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, "conditions": { "description": "conditions represent the observations of the node's current state. Known condition types are: \"Healthy\", \"Online\", \"InService\", \"Active\", \"Ready\", \"Clean\", \"Member\", \"FencingAvailable\", \"FencingHealthy\". The \"Healthy\" condition is an aggregate that tracks the overall health of the node. The \"Online\" condition tracks whether the node is online. The \"InService\" condition tracks whether the node is in service (not in maintenance mode). The \"Active\" condition tracks whether the node is active (not in standby mode). The \"Ready\" condition tracks whether the node is ready (not in a pending state). The \"Clean\" condition tracks whether the node is in a clean (status known) state. The \"Member\" condition tracks whether the node is a member of the cluster. The \"FencingAvailable\" condition tracks whether this node can be fenced by at least one healthy agent. The \"FencingHealthy\" condition tracks whether all fencing agents for this node are healthy. Each of these conditions is required, so the array must contain at least 9 items.", "type": "array", @@ -17200,7 +17118,7 @@ "type": "string" }, "resources": { - "description": "resources contains the status of pacemaker resources scheduled on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track Kubelet and Etcd resources per node. Both resources are required to be present, so the array must contain at least 2 items. Valid resource names are \"Kubelet\" and \"Etcd\". Fencing agents are tracked separately in the fencingAgents field.", + "description": "resources contains the status of pacemaker resources tracked on this node. Each resource entry includes the resource name and its health conditions. For Two Node OpenShift with Fencing, we track the Kubelet and Etcd pacemaker-managed resources per node. Both are required to be present, so the array must contain at least 2 items. The array may also contain optional alert-agent script entries named \"TaintAlertAgent\" and \"UntaintAlertAgent\". Their entries track whether the alert agent is configured in the CIB and whether its script is present on this node. Alert-agent entries are optional and are omitted when a status collector version that predates them has not reported them. Valid resource names are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". Fencing agents are tracked separately in the fencingAgents field.", "type": "array", "items": { "default": {}, @@ -17214,7 +17132,7 @@ } }, "com.github.openshift.api.etcd.v1alpha1.PacemakerClusterResourceStatus": { - "description": "PacemakerClusterResourceStatus represents the status of a pacemaker resource scheduled on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track two resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", + "description": "PacemakerClusterResourceStatus represents the status of a resource tracked on a node. A pacemaker resource is a unit of work managed by pacemaker. In pacemaker terminology, resources are services or applications that pacemaker monitors, starts, stops, and moves between nodes to maintain high availability. For Two Node OpenShift with Fencing, we track the following pacemaker-managed resources per node:\n - Kubelet (the Kubernetes node agent and a prerequisite for etcd)\n - Etcd (the distributed key-value store)\n\nThe same type is reused to track alert-agent scripts (TaintAlertAgent, UntaintAlertAgent). An alert agent is not a pacemaker-managed resource, so only a subset of the pacemaker condition types applies to it: the required conditions are enforced conditionally based on the resource name.\n\nFencing agents are tracked separately in the fencingAgents field because they are mapped to their target node (the node they can fence), not the node where monitoring operations are scheduled.", "type": "object", "required": [ "conditions", @@ -17222,7 +17140,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Each of these conditions is required, so the array must contain at least 8 items.", + "description": "conditions represent the observations of the resource's current state. Known condition types are: \"Healthy\", \"InService\", \"Managed\", \"Enabled\", \"Operational\", \"Active\", \"Started\", \"Schedulable\". The \"Healthy\" condition is an aggregate that tracks the overall health of the resource. The \"InService\" condition tracks whether the resource is in service (not in maintenance mode). The \"Managed\" condition tracks whether the resource is managed by pacemaker. The \"Enabled\" condition tracks whether the resource is enabled. The \"Operational\" condition tracks whether the resource is operational (not failed). The \"Active\" condition tracks whether the resource is active (available to be used). The \"Started\" condition tracks whether the resource is started. The \"Schedulable\" condition tracks whether the resource is schedulable (not blocked). Which conditions are required depends on the resource name:\n - For the pacemaker-managed resources \"Kubelet\" and \"Etcd\", all eight condition types listed\n above are required, so the array must contain at least 8 items.\n - For the alert-agent resources \"TaintAlertAgent\" and \"UntaintAlertAgent\", only \"Healthy\",\n \"Enabled\" (reason \"ScriptConfigured\"), and \"Operational\" (reason \"ScriptPresent\") are\n required, so the array must contain at least 3 items. The remaining condition types do not\n apply to an alert agent and may be omitted.\nThe array must contain at least 3 items in all cases; the additional Kubelet/Etcd requirements are enforced by name-gated validation rules on this type.", "type": "array", "items": { "default": {}, @@ -17234,11 +17152,13 @@ "x-kubernetes-list-type": "map" }, "name": { - "description": "name is the name of the pacemaker resource. Valid values are \"Kubelet\" and \"Etcd\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.", + "description": "name is the name of the resource. Valid values are \"Kubelet\", \"Etcd\", \"TaintAlertAgent\", and \"UntaintAlertAgent\". The Kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments. The Etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations. The TaintAlertAgent and UntaintAlertAgent entries track alert-agent configuration and per-node script presence rather than a pacemaker-managed resource. Fencing agents are tracked separately in the node's fencingAgents field.\n\nPossible enum values:\n - `\"Etcd\"` is the etcd pacemaker resource. The etcd resource may temporarily transition to stopped during pacemaker quorum-recovery operations.\n - `\"Kubelet\"` is the kubelet pacemaker resource. The kubelet resource is a prerequisite for etcd in Two Node OpenShift with Fencing deployments.\n - `\"TaintAlertAgent\"` is the alert agent that taints a node after it is fenced. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.\n - `\"UntaintAlertAgent\"` is the alert agent that removes a node's taint once it rejoins the cluster. Its entry tracks the alert agent's configuration in the CIB and the presence of its script on this node.", "type": "string", "enum": [ "Etcd", - "Kubelet" + "Kubelet", + "TaintAlertAgent", + "UntaintAlertAgent" ] } } @@ -17253,7 +17173,7 @@ ], "properties": { "conditions": { - "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items. A fourth, optional condition type, \"AlertAgentsConfigured\", may also be present once a status collector that supports it has completed a successful collection; its absence is not a validation error and does not indicate a failure. This preserves compatibility with an older status collector that didn't support alert agents.", + "description": "conditions represent the observations of the pacemaker cluster's current state. Known condition types are: \"Healthy\", \"InService\", \"NodeCountAsExpected\". The \"Healthy\" condition is an aggregate that tracks the overall health of the cluster. The \"InService\" condition tracks whether the cluster is in service (not in maintenance mode). The \"NodeCountAsExpected\" condition tracks whether the expected number of nodes are present. Each of these three conditions is required, so the array must contain at least 3 items.", "type": "array", "items": { "default": {}, From 5a4e16025a96573f5aeb7287c9f60f7f0879f69a Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Tue, 22 Sep 2026 13:20:27 +0200 Subject: [PATCH 5/7] Addressed CR comments and added more consts --- etcd/README.md | 5 +++-- etcd/v1/types_pacemakercluster.go | 20 +++++++++++++++++--- etcd/v1alpha1/types_pacemakercluster.go | 20 +++++++++++++++++--- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/etcd/README.md b/etcd/README.md index 6d65722324a..871c190ecc0 100644 --- a/etcd/README.md +++ b/etcd/README.md @@ -43,9 +43,10 @@ or applications that pacemaker monitors, starts, stops, and moves between nodes For Two Node OpenShift with Fencing, the node's `resources` array tracks: - **Kubelet**: The Kubernetes node agent and a prerequisite for etcd - **Etcd**: The distributed key-value store -- **FencingAgent**: Used to isolate failed nodes during a quorum loss event (tracked separately) - **TaintAlertAgent** / **UntaintAlertAgent**: Alert agents whose CIB configuration and per-node script presence are tracked as optional entries +Fencing agents are tracked separately in each node's `fencingAgents` array, not in `resources`. + ### Status Structure ```yaml @@ -176,7 +177,7 @@ Alert-agent entries (`TaintAlertAgent`, `UntaintAlertAgent`) reuse this type but | Condition | True | False | Unknown | |-----------|------|-------|---------| -| `Healthy` | Alert agent entry is healthy (`ResourceHealthy`) | Alert agent entry has issues (`ResourceUnhealthy`) | Not yet observed (`Pending`) | +| `Healthy` | Alert agent entry is healthy (`ResourceHealthy`) | Alert agent entry has issues (`ResourceUnhealthy`) | Not yet observed | | `Enabled` | Alert agent registered in the CIB as expected (`ScriptConfigured`) | Not registered or misconfigured (descriptive reason) | Not yet observed (`Pending`) | | `Operational` | Alert agent script present on this node (`ScriptPresent`) | Script missing from this node (descriptive reason) | Not yet observed (`Pending`) | diff --git a/etcd/v1/types_pacemakercluster.go b/etcd/v1/types_pacemakercluster.go index abf53710511..f4610f823c9 100644 --- a/etcd/v1/types_pacemakercluster.go +++ b/etcd/v1/types_pacemakercluster.go @@ -280,7 +280,8 @@ const ( // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), an alert agent cannot be // disabled, so this condition instead tracks whether the alert agent is registered in the CIB with // the expected script path and event filter. When True, the agent is configured with reason - // "ScriptConfigured". When False, the agent is not registered or is misconfigured. When Unknown, + // "ScriptConfigured". When False, the agent is not registered with reason "AlertAgentNotRegistered", or is + // registered but misconfigured with reason "ScriptMisconfigured". When Unknown, // registration has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceEnabledConditionType = "Enabled" @@ -291,8 +292,9 @@ const ( // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), this condition instead // tracks whether the alert agent's script file is present and executable on this node, since the // script is delivered independently to each node by MCO. When True, the script is present with - // reason "ScriptPresent". When False, the script is missing from this node. When Unknown, presence - // has not yet been observed this run with reason "Pending"; this is expected to be temporary. + // reason "ScriptPresent". When False, the script is missing from this node with reason + // "ScriptMissing". When Unknown, presence has not yet been observed this run with reason + // "Pending"; this is expected to be temporary. ResourceOperationalConditionType = "Operational" // ResourceActiveConditionType tracks whether a resource is active. @@ -366,6 +368,14 @@ const ( // alert-agent resource and is used in place of "Enabled". ResourceEnabledReasonScriptConfigured = "ScriptConfigured" + // ResourceEnabledReasonAlertAgentNotRegistered means an alert-agent script resource is not registered in + // the CIB at all. This is an unexpected state. + ResourceEnabledReasonAlertAgentNotRegistered = "AlertAgentNotRegistered" + + // ResourceEnabledReasonScriptMisconfigured means an alert-agent script resource is registered in + // the CIB but with an unexpected script path or event filter. This is an unexpected state. + ResourceEnabledReasonScriptMisconfigured = "ScriptMisconfigured" + // ResourceEnabledReasonPending means an alert-agent script resource's CIB registration has not yet // been observed this run by the status collector. Used only with status "Unknown". This is expected // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. @@ -387,6 +397,10 @@ const ( // resource and is used in place of "Operational". ResourceOperationalReasonScriptPresent = "ScriptPresent" + // ResourceOperationalReasonScriptMissing means an alert-agent script resource's script file is + // missing or not executable on this node. This is an unexpected state. + ResourceOperationalReasonScriptMissing = "ScriptMissing" + // ResourceOperationalReasonPending means an alert-agent script resource's presence on this node has // not yet been observed this run by the status collector. Used only with status "Unknown". This is // expected to be temporary, e.g. before MCO has delivered the script or before the first collection. diff --git a/etcd/v1alpha1/types_pacemakercluster.go b/etcd/v1alpha1/types_pacemakercluster.go index 1bff376fdfa..9d84a93908f 100644 --- a/etcd/v1alpha1/types_pacemakercluster.go +++ b/etcd/v1alpha1/types_pacemakercluster.go @@ -280,7 +280,8 @@ const ( // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), an alert agent cannot be // disabled, so this condition instead tracks whether the alert agent is registered in the CIB with // the expected script path and event filter. When True, the agent is configured with reason - // "ScriptConfigured". When False, the agent is not registered or is misconfigured. When Unknown, + // "ScriptConfigured". When False, the agent is not registered with reason "AlertAgentNotRegistered", or is + // registered but misconfigured with reason "ScriptMisconfigured". When Unknown, // registration has not yet been observed this run with reason "Pending"; this is expected to be temporary. ResourceEnabledConditionType = "Enabled" @@ -291,8 +292,9 @@ const ( // For alert-agent script resources (TaintAlertAgent, UntaintAlertAgent), this condition instead // tracks whether the alert agent's script file is present and executable on this node, since the // script is delivered independently to each node by MCO. When True, the script is present with - // reason "ScriptPresent". When False, the script is missing from this node. When Unknown, presence - // has not yet been observed this run with reason "Pending"; this is expected to be temporary. + // reason "ScriptPresent". When False, the script is missing from this node with reason + // "ScriptMissing". When Unknown, presence has not yet been observed this run with reason + // "Pending"; this is expected to be temporary. ResourceOperationalConditionType = "Operational" // ResourceActiveConditionType tracks whether a resource is active. @@ -366,6 +368,14 @@ const ( // alert-agent resource and is used in place of "Enabled". ResourceEnabledReasonScriptConfigured = "ScriptConfigured" + // ResourceEnabledReasonAlertAgentNotRegistered means an alert-agent script resource is not registered in + // the CIB at all. This is an unexpected state. + ResourceEnabledReasonAlertAgentNotRegistered = "AlertAgentNotRegistered" + + // ResourceEnabledReasonScriptMisconfigured means an alert-agent script resource is registered in + // the CIB but with an unexpected script path or event filter. This is an unexpected state. + ResourceEnabledReasonScriptMisconfigured = "ScriptMisconfigured" + // ResourceEnabledReasonPending means an alert-agent script resource's CIB registration has not yet // been observed this run by the status collector. Used only with status "Unknown". This is expected // to be temporary, e.g. immediately after upgrade or before the first successful CIB collection. @@ -387,6 +397,10 @@ const ( // resource and is used in place of "Operational". ResourceOperationalReasonScriptPresent = "ScriptPresent" + // ResourceOperationalReasonScriptMissing means an alert-agent script resource's script file is + // missing or not executable on this node. This is an unexpected state. + ResourceOperationalReasonScriptMissing = "ScriptMissing" + // ResourceOperationalReasonPending means an alert-agent script resource's presence on this node has // not yet been observed this run by the status collector. Used only with status "Unknown". This is // expected to be temporary, e.g. before MCO has delivered the script or before the first collection. From 10f3d53e64b7e2f7ec0b311ff71503c84fe40645 Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Tue, 22 Sep 2026 13:57:05 +0200 Subject: [PATCH 6/7] updated .golangci.yaml --- .golangci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 45fbb8408ec..3a511610dcc 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -120,7 +120,7 @@ linters: # PacemakerCluster intentionally marks Conditions as required with XValidation rules # to enforce specific condition types are always present. path: etcd/v1/types_pacemakercluster.go|etcd/v1alpha1/types_pacemakercluster.go - text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus|PacemakerClusterAlertAgentScriptStatus) is missing the following markers: optional" + text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus) is missing the following markers: optional" - linters: - kubeapilinter path: features|payload-command/ From 2bb28c779ebe5f41ef862f7a55e18acb5e49849c Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Tue, 22 Sep 2026 13:59:13 +0200 Subject: [PATCH 7/7] restored original .golangci.yaml --- .golangci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 3a511610dcc..1b8472410f5 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -119,7 +119,7 @@ linters: - kubeapilinter # PacemakerCluster intentionally marks Conditions as required with XValidation rules # to enforce specific condition types are always present. - path: etcd/v1/types_pacemakercluster.go|etcd/v1alpha1/types_pacemakercluster.go + path: etcd/v1/types_pacemakercluster.go text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus) is missing the following markers: optional" - linters: - kubeapilinter