Skip to content

Commit 28c40db

Browse files
committed
nfd-master: Add status for NodeFeatureRule CRD
Signed-off-by: Oleg Zhurakivskyy <[email protected]>
1 parent 0beafc6 commit 28c40db

File tree

8 files changed

+253
-5
lines changed

8 files changed

+253
-5
lines changed

api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/nfd/v1alpha1/types.go

+25
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ type NodeFeatureRuleList struct {
122122
// customization of node objects, such as node labeling.
123123
// +kubebuilder:object:root=true
124124
// +kubebuilder:resource:scope=Cluster,shortName=nfr
125+
// +kubebuilder:subresource:status
125126
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
126127
// +genclient
127128
// +genclient:nonNamespaced
@@ -131,6 +132,8 @@ type NodeFeatureRule struct {
131132

132133
// Spec defines the rules to be evaluated.
133134
Spec NodeFeatureRuleSpec `json:"spec"`
135+
// +optional
136+
Status NodeFeatureRuleStatus `json:"status,omitempty"`
134137
}
135138

136139
// NodeFeatureRuleSpec describes a NodeFeatureRule.
@@ -139,6 +142,28 @@ type NodeFeatureRuleSpec struct {
139142
Rules []Rule `json:"rules"`
140143
}
141144

145+
// NodeFeatureRuleStatus represents the status of a NodeFeatureRule
146+
type NodeFeatureRuleStatus struct {
147+
// +optional
148+
Rules []RuleStatus `json:"rules,omitempty"`
149+
}
150+
151+
// RuleStatus contains information on matched rules and nodes
152+
type RuleStatus struct {
153+
Name string `json:"name"`
154+
MatchedNodes []string `json:"matchedNodes"`
155+
}
156+
157+
// NodeFeatureRuleStatusList contains a list of NodeFeatureRuleStatus objects.
158+
// +kubebuilder:object:root=true
159+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
160+
type NodeFeatureRuleStatusList struct {
161+
metav1.TypeMeta `json:",inline"`
162+
metav1.ListMeta `json:"metadata"`
163+
164+
Items []NodeFeatureRuleStatus `json:"items"`
165+
}
166+
142167
// NodeFeatureGroup resource holds Node pools by featureGroup
143168
// +kubebuilder:object:root=true
144169
// +kubebuilder:resource:scope=Namespaced,shortName=nfg

api/nfd/v1alpha1/zz_generated.deepcopy.go

+78
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deployment/base/nfd-crds/nfd-api-crds.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,30 @@ spec:
703703
required:
704704
- rules
705705
type: object
706+
status:
707+
description: NodeFeatureRuleStatus represents the status of a NodeFeatureRule
708+
properties:
709+
rules:
710+
items:
711+
description: RuleStatus contains information on matched rules and
712+
nodes
713+
properties:
714+
matchedNodes:
715+
items:
716+
type: string
717+
type: array
718+
name:
719+
type: string
720+
required:
721+
- matchedNodes
722+
- name
723+
type: object
724+
type: array
725+
type: object
706726
required:
707727
- spec
708728
type: object
709729
served: true
710730
storage: true
731+
subresources:
732+
status: {}

deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,30 @@ spec:
703703
required:
704704
- rules
705705
type: object
706+
status:
707+
description: NodeFeatureRuleStatus represents the status of a NodeFeatureRule
708+
properties:
709+
rules:
710+
items:
711+
description: RuleStatus contains information on matched rules and
712+
nodes
713+
properties:
714+
matchedNodes:
715+
items:
716+
type: string
717+
type: array
718+
name:
719+
type: string
720+
required:
721+
- matchedNodes
722+
- name
723+
type: object
724+
type: array
725+
type: object
706726
required:
707727
- spec
708728
type: object
709729
served: true
710730
storage: true
731+
subresources:
732+
status: {}

pkg/apis/nfd/nodefeaturerule/rule.go

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type RuleOutput struct {
3939
Annotations map[string]string
4040
Vars map[string]string
4141
Taints []corev1.Taint
42+
Matched bool
4243
}
4344

4445
// Execute the rule against a set of input features.
@@ -103,6 +104,7 @@ func Execute(r *nfdv1alpha1.Rule, features *nfdv1alpha1.Features) (RuleOutput, e
103104
Annotations: maps.Clone(r.Annotations),
104105
ExtendedResources: maps.Clone(r.ExtendedResources),
105106
Taints: slices.Clone(r.Taints),
107+
Matched: true,
106108
}
107109
klog.V(2).InfoS("rule matched", "ruleName", r.Name, "ruleOutput", utils.DelayedDumper(ret))
108110
return ret, nil

pkg/nfd-master/nfd-master.go

+90-5
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,12 @@ func (m *nfdMaster) nfdAPIUpdateAllNodes() error {
634634
m.updaterPool.addNode(node.Name)
635635
}
636636

637+
err = m.updateRuleStatus()
638+
if err != nil {
639+
klog.ErrorS(err, "failed to update rule status")
640+
return err
641+
}
642+
637643
return nil
638644
}
639645

@@ -878,7 +884,7 @@ func (m *nfdMaster) refreshNodeFeatures(cli k8sclient.Interface, node *corev1.No
878884
labels = make(map[string]string)
879885
}
880886

881-
crLabels, crAnnotations, crExtendedResources, crTaints := m.processNodeFeatureRule(node.Name, features)
887+
crLabels, crAnnotations, crExtendedResources, crTaints, _ := m.processNodeFeatureRule(node.Name, features)
882888

883889
// Labels
884890
maps.Copy(labels, crLabels)
@@ -989,9 +995,9 @@ func (m *nfdMaster) setTaints(cli k8sclient.Interface, taints []corev1.Taint, no
989995
return nil
990996
}
991997

992-
func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha1.Features) (Labels, Annotations, ExtendedResources, []corev1.Taint) {
998+
func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha1.Features) (Labels, Annotations, ExtendedResources, []corev1.Taint, []*nfdv1alpha1.NodeFeatureRule) {
993999
if m.nfdController == nil {
994-
return nil, nil, nil, nil
1000+
return nil, nil, nil, nil, nil
9951001
}
9961002

9971003
extendedResources := ExtendedResources{}
@@ -1005,12 +1011,13 @@ func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha
10051011

10061012
if err != nil {
10071013
klog.ErrorS(err, "failed to list NodeFeatureRule resources")
1008-
return nil, nil, nil, nil
1014+
return nil, nil, nil, nil, nil
10091015
}
10101016

10111017
// Process all rule CRs
10121018
processStart := time.Now()
10131019
for _, spec := range ruleSpecs {
1020+
spec.Status.Rules = []nfdv1alpha1.RuleStatus{}
10141021
t := time.Now()
10151022
switch {
10161023
case klog.V(3).Enabled():
@@ -1042,13 +1049,91 @@ func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha
10421049
// Feed back rule output to features map for subsequent rules to match
10431050
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
10441051
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
1052+
1053+
if ruleOut.Matched {
1054+
r := nfdv1alpha1.RuleStatus{
1055+
Name: rule.Name,
1056+
MatchedNodes: []string{
1057+
nodeName,
1058+
},
1059+
}
1060+
spec.Status.Rules = append(spec.Status.Rules, r)
1061+
}
10451062
}
10461063
nfrProcessingTime.WithLabelValues(spec.Name, nodeName).Observe(time.Since(t).Seconds())
10471064
}
10481065
processingTime := time.Since(processStart)
10491066
klog.V(2).InfoS("processed NodeFeatureRule objects", "nodeName", nodeName, "objectCount", len(ruleSpecs), "duration", processingTime)
10501067

1051-
return labels, annotations, extendedResources, taints
1068+
return labels, annotations, extendedResources, taints, ruleSpecs
1069+
}
1070+
1071+
func findRuleByName(ruleSpecs []*nfdv1alpha1.NodeFeatureRule, name string) *nfdv1alpha1.NodeFeatureRule {
1072+
var spec *nfdv1alpha1.NodeFeatureRule
1073+
for _, r := range ruleSpecs {
1074+
if r.Name == name {
1075+
spec = r
1076+
break
1077+
}
1078+
}
1079+
return spec
1080+
}
1081+
1082+
func findStatusRuleByName(status *[]nfdv1alpha1.RuleStatus, name string) *nfdv1alpha1.RuleStatus {
1083+
var rule *nfdv1alpha1.RuleStatus
1084+
for _, r := range *status {
1085+
if r.Name == name {
1086+
rule = &r
1087+
break
1088+
}
1089+
}
1090+
return rule
1091+
}
1092+
1093+
func (m *nfdMaster) updateRuleStatus() error {
1094+
nodes, err := getNodes(m.k8sClient)
1095+
if err != nil {
1096+
return err
1097+
}
1098+
1099+
var ruleSpecs []*nfdv1alpha1.NodeFeatureRule
1100+
var outSpecs []*nfdv1alpha1.NodeFeatureRule
1101+
1102+
for _, node := range nodes.Items {
1103+
nodeFeatures, err := m.getAndMergeNodeFeatures(node.Name)
1104+
if err != nil {
1105+
return fmt.Errorf("failed to merge NodeFeature objects for node %q: %w", node.Name, err)
1106+
}
1107+
1108+
_, _, _, _, ruleSpecs = m.processNodeFeatureRule(node.Name, &nodeFeatures.Spec.Features)
1109+
}
1110+
1111+
for _, spec := range ruleSpecs {
1112+
if len(spec.Status.Rules) > 0 {
1113+
s := findRuleByName(outSpecs, spec.Name)
1114+
if s != nil {
1115+
for _, r := range spec.Status.Rules {
1116+
s.Status.Rules = append(s.Status.Rules, r)
1117+
1118+
sr := findStatusRuleByName(&s.Status.Rules, r.Name)
1119+
if sr != nil {
1120+
sr.MatchedNodes = append(sr.MatchedNodes, r.MatchedNodes...)
1121+
}
1122+
}
1123+
} else {
1124+
outSpecs = append(outSpecs, spec)
1125+
}
1126+
}
1127+
}
1128+
1129+
for _, spec := range outSpecs {
1130+
_, err = m.nfdClient.NfdV1alpha1().NodeFeatureRules().Update(context.TODO(), spec, metav1.UpdateOptions{})
1131+
if err != nil {
1132+
klog.ErrorS(err, "failed to update rule status", "nodefeaturerule", klog.KObj(spec))
1133+
}
1134+
}
1135+
1136+
return nil
10521137
}
10531138

10541139
// updateNodeObject ensures the Kubernetes node object is up to date,

0 commit comments

Comments
 (0)