mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
nfd-master: Add status for NodeFeatureRule CRD
Signed-off-by: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
This commit is contained in:
parent
0beafc6aa7
commit
28c40db0a6
8 changed files with 253 additions and 5 deletions
|
@ -99,6 +99,18 @@ func (c *FakeNodeFeatureRules) Update(ctx context.Context, nodeFeatureRule *v1al
|
|||
return obj.(*v1alpha1.NodeFeatureRule), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeNodeFeatureRules) UpdateStatus(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureRule, err error) {
|
||||
emptyResult := &v1alpha1.NodeFeatureRule{}
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceActionWithOptions(nodefeaturerulesResource, "status", nodeFeatureRule, opts), emptyResult)
|
||||
if obj == nil {
|
||||
return emptyResult, err
|
||||
}
|
||||
return obj.(*v1alpha1.NodeFeatureRule), err
|
||||
}
|
||||
|
||||
// Delete takes name of the nodeFeatureRule and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeNodeFeatureRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
|
|
|
@ -39,6 +39,8 @@ type NodeFeatureRulesGetter interface {
|
|||
type NodeFeatureRuleInterface interface {
|
||||
Create(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.CreateOptions) (*v1alpha1.NodeFeatureRule, error)
|
||||
Update(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureRule, error)
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
UpdateStatus(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureRule, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeFeatureRule, error)
|
||||
|
|
|
@ -122,6 +122,7 @@ type NodeFeatureRuleList struct {
|
|||
// customization of node objects, such as node labeling.
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:scope=Cluster,shortName=nfr
|
||||
// +kubebuilder:subresource:status
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
|
@ -131,6 +132,8 @@ type NodeFeatureRule struct {
|
|||
|
||||
// Spec defines the rules to be evaluated.
|
||||
Spec NodeFeatureRuleSpec `json:"spec"`
|
||||
// +optional
|
||||
Status NodeFeatureRuleStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// NodeFeatureRuleSpec describes a NodeFeatureRule.
|
||||
|
@ -139,6 +142,28 @@ type NodeFeatureRuleSpec struct {
|
|||
Rules []Rule `json:"rules"`
|
||||
}
|
||||
|
||||
// NodeFeatureRuleStatus represents the status of a NodeFeatureRule
|
||||
type NodeFeatureRuleStatus struct {
|
||||
// +optional
|
||||
Rules []RuleStatus `json:"rules,omitempty"`
|
||||
}
|
||||
|
||||
// RuleStatus contains information on matched rules and nodes
|
||||
type RuleStatus struct {
|
||||
Name string `json:"name"`
|
||||
MatchedNodes []string `json:"matchedNodes"`
|
||||
}
|
||||
|
||||
// NodeFeatureRuleStatusList contains a list of NodeFeatureRuleStatus objects.
|
||||
// +kubebuilder:object:root=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type NodeFeatureRuleStatusList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []NodeFeatureRuleStatus `json:"items"`
|
||||
}
|
||||
|
||||
// NodeFeatureGroup resource holds Node pools by featureGroup
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:scope=Namespaced,shortName=nfg
|
||||
|
|
|
@ -544,6 +544,7 @@ func (in *NodeFeatureRule) DeepCopyInto(out *NodeFeatureRule) {
|
|||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -621,6 +622,62 @@ func (in *NodeFeatureRuleSpec) DeepCopy() *NodeFeatureRuleSpec {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeFeatureRuleStatus) DeepCopyInto(out *NodeFeatureRuleStatus) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]RuleStatus, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureRuleStatus.
|
||||
func (in *NodeFeatureRuleStatus) DeepCopy() *NodeFeatureRuleStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeFeatureRuleStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeFeatureRuleStatusList) DeepCopyInto(out *NodeFeatureRuleStatusList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]NodeFeatureRuleStatus, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureRuleStatusList.
|
||||
func (in *NodeFeatureRuleStatusList) DeepCopy() *NodeFeatureRuleStatusList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeFeatureRuleStatusList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *NodeFeatureRuleStatusList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeFeatureSpec) DeepCopyInto(out *NodeFeatureSpec) {
|
||||
*out = *in
|
||||
|
@ -709,3 +766,24 @@ func (in *Rule) DeepCopy() *Rule {
|
|||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RuleStatus) DeepCopyInto(out *RuleStatus) {
|
||||
*out = *in
|
||||
if in.MatchedNodes != nil {
|
||||
in, out := &in.MatchedNodes, &out.MatchedNodes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleStatus.
|
||||
func (in *RuleStatus) DeepCopy() *RuleStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RuleStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -703,8 +703,30 @@ spec:
|
|||
required:
|
||||
- rules
|
||||
type: object
|
||||
status:
|
||||
description: NodeFeatureRuleStatus represents the status of a NodeFeatureRule
|
||||
properties:
|
||||
rules:
|
||||
items:
|
||||
description: RuleStatus contains information on matched rules and
|
||||
nodes
|
||||
properties:
|
||||
matchedNodes:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- matchedNodes
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
|
|
@ -703,8 +703,30 @@ spec:
|
|||
required:
|
||||
- rules
|
||||
type: object
|
||||
status:
|
||||
description: NodeFeatureRuleStatus represents the status of a NodeFeatureRule
|
||||
properties:
|
||||
rules:
|
||||
items:
|
||||
description: RuleStatus contains information on matched rules and
|
||||
nodes
|
||||
properties:
|
||||
matchedNodes:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- matchedNodes
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
|
|
@ -39,6 +39,7 @@ type RuleOutput struct {
|
|||
Annotations map[string]string
|
||||
Vars map[string]string
|
||||
Taints []corev1.Taint
|
||||
Matched bool
|
||||
}
|
||||
|
||||
// Execute the rule against a set of input features.
|
||||
|
@ -103,6 +104,7 @@ func Execute(r *nfdv1alpha1.Rule, features *nfdv1alpha1.Features) (RuleOutput, e
|
|||
Annotations: maps.Clone(r.Annotations),
|
||||
ExtendedResources: maps.Clone(r.ExtendedResources),
|
||||
Taints: slices.Clone(r.Taints),
|
||||
Matched: true,
|
||||
}
|
||||
klog.V(2).InfoS("rule matched", "ruleName", r.Name, "ruleOutput", utils.DelayedDumper(ret))
|
||||
return ret, nil
|
||||
|
|
|
@ -634,6 +634,12 @@ func (m *nfdMaster) nfdAPIUpdateAllNodes() error {
|
|||
m.updaterPool.addNode(node.Name)
|
||||
}
|
||||
|
||||
err = m.updateRuleStatus()
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to update rule status")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -878,7 +884,7 @@ func (m *nfdMaster) refreshNodeFeatures(cli k8sclient.Interface, node *corev1.No
|
|||
labels = make(map[string]string)
|
||||
}
|
||||
|
||||
crLabels, crAnnotations, crExtendedResources, crTaints := m.processNodeFeatureRule(node.Name, features)
|
||||
crLabels, crAnnotations, crExtendedResources, crTaints, _ := m.processNodeFeatureRule(node.Name, features)
|
||||
|
||||
// Labels
|
||||
maps.Copy(labels, crLabels)
|
||||
|
@ -989,9 +995,9 @@ func (m *nfdMaster) setTaints(cli k8sclient.Interface, taints []corev1.Taint, no
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha1.Features) (Labels, Annotations, ExtendedResources, []corev1.Taint) {
|
||||
func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha1.Features) (Labels, Annotations, ExtendedResources, []corev1.Taint, []*nfdv1alpha1.NodeFeatureRule) {
|
||||
if m.nfdController == nil {
|
||||
return nil, nil, nil, nil
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
extendedResources := ExtendedResources{}
|
||||
|
@ -1005,12 +1011,13 @@ func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha
|
|||
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to list NodeFeatureRule resources")
|
||||
return nil, nil, nil, nil
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Process all rule CRs
|
||||
processStart := time.Now()
|
||||
for _, spec := range ruleSpecs {
|
||||
spec.Status.Rules = []nfdv1alpha1.RuleStatus{}
|
||||
t := time.Now()
|
||||
switch {
|
||||
case klog.V(3).Enabled():
|
||||
|
@ -1042,13 +1049,91 @@ func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha
|
|||
// Feed back rule output to features map for subsequent rules to match
|
||||
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
|
||||
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
|
||||
|
||||
if ruleOut.Matched {
|
||||
r := nfdv1alpha1.RuleStatus{
|
||||
Name: rule.Name,
|
||||
MatchedNodes: []string{
|
||||
nodeName,
|
||||
},
|
||||
}
|
||||
spec.Status.Rules = append(spec.Status.Rules, r)
|
||||
}
|
||||
}
|
||||
nfrProcessingTime.WithLabelValues(spec.Name, nodeName).Observe(time.Since(t).Seconds())
|
||||
}
|
||||
processingTime := time.Since(processStart)
|
||||
klog.V(2).InfoS("processed NodeFeatureRule objects", "nodeName", nodeName, "objectCount", len(ruleSpecs), "duration", processingTime)
|
||||
|
||||
return labels, annotations, extendedResources, taints
|
||||
return labels, annotations, extendedResources, taints, ruleSpecs
|
||||
}
|
||||
|
||||
func findRuleByName(ruleSpecs []*nfdv1alpha1.NodeFeatureRule, name string) *nfdv1alpha1.NodeFeatureRule {
|
||||
var spec *nfdv1alpha1.NodeFeatureRule
|
||||
for _, r := range ruleSpecs {
|
||||
if r.Name == name {
|
||||
spec = r
|
||||
break
|
||||
}
|
||||
}
|
||||
return spec
|
||||
}
|
||||
|
||||
func findStatusRuleByName(status *[]nfdv1alpha1.RuleStatus, name string) *nfdv1alpha1.RuleStatus {
|
||||
var rule *nfdv1alpha1.RuleStatus
|
||||
for _, r := range *status {
|
||||
if r.Name == name {
|
||||
rule = &r
|
||||
break
|
||||
}
|
||||
}
|
||||
return rule
|
||||
}
|
||||
|
||||
func (m *nfdMaster) updateRuleStatus() error {
|
||||
nodes, err := getNodes(m.k8sClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ruleSpecs []*nfdv1alpha1.NodeFeatureRule
|
||||
var outSpecs []*nfdv1alpha1.NodeFeatureRule
|
||||
|
||||
for _, node := range nodes.Items {
|
||||
nodeFeatures, err := m.getAndMergeNodeFeatures(node.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge NodeFeature objects for node %q: %w", node.Name, err)
|
||||
}
|
||||
|
||||
_, _, _, _, ruleSpecs = m.processNodeFeatureRule(node.Name, &nodeFeatures.Spec.Features)
|
||||
}
|
||||
|
||||
for _, spec := range ruleSpecs {
|
||||
if len(spec.Status.Rules) > 0 {
|
||||
s := findRuleByName(outSpecs, spec.Name)
|
||||
if s != nil {
|
||||
for _, r := range spec.Status.Rules {
|
||||
s.Status.Rules = append(s.Status.Rules, r)
|
||||
|
||||
sr := findStatusRuleByName(&s.Status.Rules, r.Name)
|
||||
if sr != nil {
|
||||
sr.MatchedNodes = append(sr.MatchedNodes, r.MatchedNodes...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outSpecs = append(outSpecs, spec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, spec := range outSpecs {
|
||||
_, err = m.nfdClient.NfdV1alpha1().NodeFeatureRules().Update(context.TODO(), spec, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to update rule status", "nodefeaturerule", klog.KObj(spec))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateNodeObject ensures the Kubernetes node object is up to date,
|
||||
|
|
Loading…
Reference in a new issue