mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-14 20:56:42 +00:00
nfd-master: handle multiple NodeFeature objects
Implement handling of multiple NodeFeature objects by merging all objects (targeting a certain node) into one before processing the data. This patch implements MergeInto() methods for all required data types. With support for multiple NodeFeature objects per node, The "nfd api workflow" can be easily demonstrated and tested from the command line. Creating the folloiwing object (assuming node-n exists in the cluster): apiVersion: nfd.k8s-sigs.io/v1alpha1 kind: NodeFeature metadata: labels: nfd.node.kubernetes.io/node-name: node-n name: my-features-for-node-n spec: # Features for NodeFeatureRule matching features: flags: vendor.domain-a: elements: feature-x: {} attributes: vendor.domain-b: elements: feature-y: "foo" feature-z: "123" instances: vendor.domain-c: elements: - attributes: name: "elem-1" vendor: "acme" - attributes: name: "elem-2" vendor: "acme" # Labels to be created labels: vendor-feature.enabled: "true" vendor-setting.value: "100" will create two feature labes: feature.node.kubernetes.io/vendor-feature.enabled: "true" feature.node.kubernetes.io/vendor-setting.value: "100" In addition it will advertise hidden/raw features that can be used for custom rules in NodeFeatureRule objects. Now, creating a NodeFeatureRule object: apiVersion: nfd.k8s-sigs.io/v1alpha1 kind: NodeFeatureRule metadata: name: my-rule spec: rules: - name: "my feature rule" labels: "my-feature": "true" matchFeatures: - feature: vendor.domain-a matchExpressions: feature-x: {op: Exists} - feature: vendor.domain-c matchExpressions: vendor: {op: In, value: ["acme"]} will match the features in the NodeFeature object above and cause one more label to be created: feature.node.kubernetes.io/my-feature: "true"
This commit is contained in:
parent
ee0807da66
commit
79ed747be8
2 changed files with 95 additions and 7 deletions
|
@ -82,3 +82,89 @@ func (f *Features) Exists(name string) string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// MergeInto merges two FeatureSpecs into one. Data in the input object takes
|
||||
// precedence (overwrite) over data of the existing object we're merging into.
|
||||
func (in *NodeFeatureSpec) MergeInto(out *NodeFeatureSpec) {
|
||||
in.Features.MergeInto(&out.Features)
|
||||
if in.Labels != nil {
|
||||
if out.Labels == nil {
|
||||
out.Labels = make(map[string]string, len(in.Labels))
|
||||
}
|
||||
for key, val := range in.Labels {
|
||||
out.Labels[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MergeInto merges two sets of features into one. Features from the input set
|
||||
// take precedence (overwrite) features from the existing features of the set
|
||||
// we're merging into.
|
||||
func (in *Features) MergeInto(out *Features) {
|
||||
if in.Flags != nil {
|
||||
if out.Flags == nil {
|
||||
out.Flags = make(map[string]FlagFeatureSet, len(in.Flags))
|
||||
}
|
||||
for key, val := range in.Flags {
|
||||
outVal := out.Flags[key]
|
||||
val.MergeInto(&outVal)
|
||||
out.Flags[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.Attributes != nil {
|
||||
if out.Attributes == nil {
|
||||
out.Attributes = make(map[string]AttributeFeatureSet, len(in.Attributes))
|
||||
}
|
||||
for key, val := range in.Attributes {
|
||||
outVal := out.Attributes[key]
|
||||
val.MergeInto(&outVal)
|
||||
out.Attributes[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.Instances != nil {
|
||||
if out.Instances == nil {
|
||||
out.Instances = make(map[string]InstanceFeatureSet, len(in.Instances))
|
||||
}
|
||||
for key, val := range in.Instances {
|
||||
outVal := out.Instances[key]
|
||||
val.MergeInto(&outVal)
|
||||
out.Instances[key] = outVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MergeInto merges two sets of flag featues.
|
||||
func (in *FlagFeatureSet) MergeInto(out *FlagFeatureSet) {
|
||||
if in.Elements != nil {
|
||||
if out.Elements == nil {
|
||||
out.Elements = make(map[string]Nil, len(in.Elements))
|
||||
}
|
||||
for key, val := range in.Elements {
|
||||
out.Elements[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MergeInto merges two sets of attribute featues.
|
||||
func (in *AttributeFeatureSet) MergeInto(out *AttributeFeatureSet) {
|
||||
if in.Elements != nil {
|
||||
if out.Elements == nil {
|
||||
out.Elements = make(map[string]string, len(in.Elements))
|
||||
}
|
||||
for key, val := range in.Elements {
|
||||
out.Elements[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MergeInto merges two sets of instance featues.
|
||||
func (in *InstanceFeatureSet) MergeInto(out *InstanceFeatureSet) {
|
||||
if in.Elements != nil {
|
||||
if out.Elements == nil {
|
||||
out.Elements = make([]InstanceFeature, 0, len(in.Elements))
|
||||
}
|
||||
for _, e := range in.Elements {
|
||||
out.Elements = append(out.Elements, *e.DeepCopy())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -516,12 +516,14 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(nodeName string) error {
|
|||
|
||||
// Merge in features
|
||||
//
|
||||
// TODO: support multiple NodeFeature objects. There are two obvious options to implement this:
|
||||
// 1. Merge features of all objects into one joint object
|
||||
// 2. Change the rule api to support handle multiple objects
|
||||
// Of these #2 would probably perform better with lot less data to copy. We
|
||||
// could probably even get rid of the DeepCopy in this scenario.
|
||||
features := objs[0].DeepCopy()
|
||||
// NOTE: changing the rule api to support handle multiple objects instead
|
||||
// of merging would probably perform better with lot less data to copy.
|
||||
features := objs[0].Spec.DeepCopy()
|
||||
for _, o := range objs[1:] {
|
||||
o.Spec.MergeInto(features)
|
||||
}
|
||||
|
||||
utils.KlogDump(4, "Composite NodeFeatureSpec after merge:", " ", features)
|
||||
|
||||
annotations := Annotations{}
|
||||
if objs[0].Namespace == m.namespace && objs[0].Name == nodeName {
|
||||
|
@ -536,7 +538,7 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(nodeName string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := m.refreshNodeFeatures(cli, nodeName, annotations, features.Spec.Labels, &features.Spec.Features); err != nil {
|
||||
if err := m.refreshNodeFeatures(cli, nodeName, annotations, features.Labels, &features.Features); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue