Skip to content

Commit 2f89354

Browse files
committed
Add nodereadinessrulereport CRD and controller
1 parent 6e6329d commit 2f89354

16 files changed

+1414
-8
lines changed

PROJECT

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,11 @@ resources:
2222
kind: Node
2323
path: k8s.io/api/core/v1
2424
version: v1
25+
- api:
26+
crdVersion: v1
27+
controller: true
28+
domain: readiness.node.x-k8s.io
29+
kind: NodeReadinessRuleReport
30+
path: sigs.k8s.io/node-readiness-controller/api/v1alpha1
31+
version: v1alpha1
2532
version: "3"
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// RuleStatus defines the result of evaluating a NodeReadinessRule's criteria against a Node.
8+
// +kubebuilder:validation:Enum=Matched;Unmatched;Error
9+
type RuleStatus string
10+
11+
const (
12+
// RuleStatusMatched indicates that the Node successfully met all criteria
13+
// (both NodeSelector and Conditions) defined in the NodeReadinessRule.
14+
// When in this state, the controller should ensure the corresponding Taint is applied.
15+
RuleStatusMatched RuleStatus = "Matched"
16+
17+
// RuleStatusUnmatched indicates that the Node did not meet the criteria
18+
// defined in the NodeReadinessRule (e.g., label mismatch or condition not satisfied).
19+
// When in this state, the controller should ensure the corresponding Taint is absent.
20+
RuleStatusUnmatched RuleStatus = "Unmatched"
21+
22+
// RuleStatusError indicates that a programmatic or configuration error occurred
23+
// during the evaluation process (e.g., an invalid or unparseable NodeSelector).
24+
// The controller cannot safely determine if the taint should be present or absent.
25+
RuleStatusError RuleStatus = "Error"
26+
)
27+
28+
// +kubebuilder:object:root=true
29+
// +kubebuilder:subresource:status
30+
// +kubebuilder:resource:scope=Cluster,shortName=nrrp
31+
// +kubebuilder:printcolumn:name="Node",type=string,JSONPath=`.spec.nodeName`,description="The Node this report belongs to."
32+
// +kubebuilder:printcolumn:name="Matched Rules",type=integer,JSONPath=`.status.summary.matchedRules`,description="Number of rules matching this node."
33+
// +kubebuilder:printcolumn:name="UnMatched Rules",type=integer,JSONPath=`.status.summary.unMatchedRules`,description="Number of rules not matching this node."
34+
// +kubebuilder:printcolumn:name="Applied Taints",type=integer,JSONPath=`.status.summary.appliedTaints`,description="Number of taints currently applied."
35+
// +kubebuilder:printcolumn:name="Errors",type=integer,JSONPath=`.status.summary.errors`,description="Number of evaluation errors."
36+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
37+
38+
// NodeReadinessRuleReport is the Schema for the nodereadinessrulereports API.
39+
type NodeReadinessRuleReport struct {
40+
metav1.TypeMeta `json:",inline"`
41+
42+
// metadata is a standard object metadata
43+
// +optional
44+
metav1.ObjectMeta `json:"metadata,omitzero"`
45+
46+
// spec defines the desired state of NodeReadinessRuleReport
47+
// +required
48+
Spec NodeReadinessRuleReportSpec `json:"spec,omitzero"`
49+
50+
// status defines the observed state of NodeReadinessRuleReport
51+
// +optional
52+
Status NodeReadinessRuleReportStatus `json:"status,omitzero"`
53+
}
54+
55+
// NodeReadinessRuleReportSpec defines the desired state of NodeReadinessRuleReport.
56+
type NodeReadinessRuleReportSpec struct {
57+
// nodeName specifies the exact name of the target Kubernetes Node.
58+
// This object establishes a strict 1:1 relationship with the specified node,
59+
// acting as the single source of truth for all rules and statuses applied to it.
60+
// Because it binds this resource to a specific physical or virtual machine, it cannot be changed once set.
61+
//
62+
// The validation constraints enforce standard Kubernetes resource naming
63+
// (RFC 1123 DNS Subdomain format), as defined in upstream apimachinery:
64+
// https://github.com/kubernetes/apimachinery/blob/master/pkg/util/validation/validation.go#L198
65+
//
66+
// +required
67+
// +kubebuilder:validation:MinLength=1
68+
// +kubebuilder:validation:MaxLength=253
69+
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
70+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="nodeName is immutable and cannot be changed once set"
71+
NodeName string `json:"nodeName,omitempty"`
72+
}
73+
74+
// NodeReadinessRuleReportStatus defines the observed state of NodeReadinessRuleReport.
75+
// +kubebuilder:validation:MinProperties=1
76+
type NodeReadinessRuleReportStatus struct {
77+
// readinessReports provides detailed insight into the rule's assessment for individual Nodes.
78+
// This is primarily used for auditing and debugging why specific Nodes were or
79+
// were not targeted by the rule.
80+
//
81+
// +optional
82+
// +listType=map
83+
// +listMapKey=ruleName
84+
// +kubebuilder:validation:MaxItems=100
85+
ReadinessReports []ReadinessReport `json:"readinessReports,omitempty"`
86+
87+
// summary provides a quick overview of the rules applied to this node.
88+
//
89+
// +optional
90+
Summary ReportSummary `json:"summary,omitempty,omitzero"`
91+
}
92+
93+
// ReadinessReport defines the outcome of evaluating a single NodeReadinessRule against a specific Node.
94+
type ReadinessReport struct {
95+
// ruleName is the name of the NodeReadinessRule being evaluated.
96+
// It acts as a direct reference to the NodeReadinessRule that generated this report entry.
97+
//
98+
// +required
99+
// +kubebuilder:validation:MinLength=1
100+
// +kubebuilder:validation:MaxLength=253
101+
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
102+
RuleName string `json:"ruleName,omitempty"`
103+
104+
// reason contains a concise, machine-readable string detailing the primary outcome
105+
// of the evaluation (e.g., "SelectorMismatch", "CriteriaMet", "ConditionNotFound").
106+
//
107+
// +optional
108+
// +kubebuilder:validation:MinLength=1
109+
// +kubebuilder:validation:MaxLength=256
110+
Reason string `json:"reason,omitempty"`
111+
112+
// message is a comprehensive, human-readable explanation providing further
113+
// context about the evaluation result or any specific errors encountered.
114+
//
115+
// +optional
116+
// +kubebuilder:validation:MinLength=1
117+
// +kubebuilder:validation:MaxLength=10240
118+
Message string `json:"message,omitempty"`
119+
120+
// ruleStatus indicates the overall outcome of the rule's criteria against the Node.
121+
// This reflects whether the Node successfully matched the rule's NodeSelector and Conditions.
122+
//
123+
// +required
124+
RuleStatus RuleStatus `json:"ruleStatus,omitempty"`
125+
126+
// taintStatus reflects the observed state of the rule's specified taint on the Node.
127+
// It indicates whether the taint is currently Present or Absent.
128+
//
129+
// +required
130+
TaintStatus TaintStatus `json:"taintStatus,omitempty"`
131+
132+
// lastEvaluationTime records the exact moment the controller most recently
133+
// assessed this rule against the Node. This helps identify stale reports.
134+
//
135+
// +required
136+
LastEvaluationTime metav1.Time `json:"lastEvaluationTime,omitempty,omitzero"`
137+
}
138+
139+
// ReportSummary aggregates the results to provide a high-level overview.
140+
// +kubebuilder:validation:MinProperties=1
141+
type ReportSummary struct {
142+
// matchedRules is the total number of rules currently matching this node.
143+
//
144+
// +optional
145+
// +kubebuilder:validation:Minimum=0
146+
MatchedRules *int32 `json:"matchedRules,omitempty"`
147+
148+
// unMatchedRules is the total number of rules currently not matching this node.
149+
//
150+
// +optional
151+
// +kubebuilder:validation:Minimum=0
152+
UnMatchedRules *int32 `json:"unMatchedRules,omitempty"`
153+
154+
// appliedTaints is the total number of taints successfully applied by the controller.
155+
//
156+
// +optional
157+
// +kubebuilder:validation:Minimum=0
158+
AppliedTaints *int32 `json:"appliedTaints,omitempty"`
159+
160+
// errors is the total number of rules that failed to evaluate properly.
161+
//
162+
// +optional
163+
// +kubebuilder:validation:Minimum=0
164+
Errors *int32 `json:"errors,omitempty"`
165+
}
166+
167+
// +kubebuilder:object:root=true
168+
169+
// NodeReadinessRuleReportList contains a list of NodeReadinessRuleReport.
170+
type NodeReadinessRuleReportList struct {
171+
metav1.TypeMeta `json:",inline"`
172+
metav1.ListMeta `json:"metadata,omitzero"`
173+
Items []NodeReadinessRuleReport `json:"items"`
174+
}
175+
176+
func init() {
177+
objectTypes = append(objectTypes, &NodeReadinessRuleReport{}, &NodeReadinessRuleReportList{})
178+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 148 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)