mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
3434557d7c
Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
195 lines
5.3 KiB
Go
195 lines
5.3 KiB
Go
/*
|
|
Copyright 2023 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package kubectlnfd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"sigs.k8s.io/yaml"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
|
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/nodefeaturerule"
|
|
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/validate"
|
|
)
|
|
|
|
func DryRun(nodefeaturerulepath, nodefeaturepath string) []error {
|
|
var errs []error
|
|
nfr := nfdv1alpha1.NodeFeatureRule{}
|
|
nf := nfdv1alpha1.NodeFeature{}
|
|
|
|
nfrFile, err := os.ReadFile(nodefeaturerulepath)
|
|
if err != nil {
|
|
return []error{fmt.Errorf("error reading NodeFeatureRule file: %w", err)}
|
|
}
|
|
|
|
err = yaml.Unmarshal(nfrFile, &nfr)
|
|
if err != nil {
|
|
return []error{fmt.Errorf("error parsing NodeFeatureRule: %w", err)}
|
|
}
|
|
|
|
nfFile, err := os.ReadFile(nodefeaturepath)
|
|
if err != nil {
|
|
return []error{fmt.Errorf("error reading NodeFeatureRule file: %w", err)}
|
|
}
|
|
|
|
err = yaml.Unmarshal(nfFile, &nf)
|
|
if err != nil {
|
|
return []error{fmt.Errorf("error parsing NodeFeatureRule: %w", err)}
|
|
}
|
|
|
|
errs = append(errs, processNodeFeatureRule(nfr, nf.Spec)...)
|
|
|
|
return errs
|
|
}
|
|
|
|
func processNodeFeatureRule(nodeFeatureRule nfdv1alpha1.NodeFeatureRule, nodeFeature nfdv1alpha1.NodeFeatureSpec) []error {
|
|
var errs []error
|
|
var taints []corev1.Taint
|
|
|
|
extendedResources := make(map[string]string)
|
|
labels := make(map[string]string)
|
|
annotations := make(map[string]string)
|
|
|
|
for _, rule := range nodeFeatureRule.Spec.Rules {
|
|
fmt.Println("Processing rule: ", rule.Name)
|
|
ruleOut, err := nodefeaturerule.Execute(&rule, &nodeFeature.Features)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("failed to process rule: %q - %w", rule.Name, err))
|
|
continue
|
|
}
|
|
// taints
|
|
taints = append(taints, ruleOut.Taints...)
|
|
// labels
|
|
for k, v := range ruleOut.Labels {
|
|
// Dynamic Value
|
|
if strings.HasPrefix(v, "@") {
|
|
dvalue, err := getDynamicValue(v, &nodeFeature.Features)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("failed to get dynamic value for label %q: %w", k, err))
|
|
continue
|
|
}
|
|
labels[k] = dvalue
|
|
continue
|
|
}
|
|
labels[k] = v
|
|
}
|
|
// extended resources
|
|
for k, v := range ruleOut.ExtendedResources {
|
|
// Dynamic Value
|
|
if strings.HasPrefix(v, "@") {
|
|
dvalue, err := getDynamicValue(v, &nodeFeature.Features)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("failed to get dynamic value for extendedResource %q: %w", k, err))
|
|
continue
|
|
}
|
|
extendedResources[k] = dvalue
|
|
continue
|
|
}
|
|
extendedResources[k] = v
|
|
}
|
|
// annotations
|
|
for k, v := range ruleOut.Annotations {
|
|
annotations[k] = v
|
|
}
|
|
}
|
|
|
|
if len(taints) > 0 {
|
|
taintValidation := validate.Taints(taints)
|
|
fmt.Println("***\tTaints\t***")
|
|
for _, taint := range taints {
|
|
fmt.Println(taint)
|
|
}
|
|
if len(taintValidation) > 0 {
|
|
fmt.Println("\t-Validation errors-")
|
|
for _, err := range taintValidation {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(labels) > 0 {
|
|
labelValidation := validate.Labels(labels)
|
|
fmt.Println("***\tLabels\t***")
|
|
for k, v := range labels {
|
|
fmt.Printf("%s=%s\n", k, v)
|
|
}
|
|
if len(labelValidation) > 0 {
|
|
fmt.Println("\t-Validation errors-")
|
|
for _, err := range labelValidation {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(extendedResources) > 0 {
|
|
resourceValidation := processExtendedResources(extendedResources, nodeFeature)
|
|
fmt.Println("***\tExtended Resources\t***")
|
|
for k, v := range extendedResources {
|
|
fmt.Printf("%s=%s\n", k, v)
|
|
}
|
|
if len(resourceValidation) > 0 {
|
|
fmt.Println("\t-Validation errors-")
|
|
for _, err := range resourceValidation {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(annotations) > 0 {
|
|
annotationsValidation := validate.Annotations(annotations)
|
|
fmt.Println("***\tAnnotations\t***")
|
|
for k, v := range annotations {
|
|
fmt.Printf("%s=%s\n", k, v)
|
|
}
|
|
if len(annotationsValidation) > 0 {
|
|
fmt.Println("\t-Validation errors-")
|
|
for _, err := range annotationsValidation {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
func processExtendedResources(extendedResources map[string]string, nodeFeature nfdv1alpha1.NodeFeatureSpec) []error {
|
|
var errs []error
|
|
return append(errs, validate.ExtendedResources(extendedResources)...)
|
|
}
|
|
|
|
func getDynamicValue(value string, features *nfdv1alpha1.Features) (string, error) {
|
|
// value is a string in the form of attribute.featureset.elements
|
|
split := strings.SplitN(value[1:], ".", 3)
|
|
if len(split) != 3 {
|
|
return "", fmt.Errorf("value %s is not in the form of '@domain.feature.element'", value)
|
|
}
|
|
featureName := split[0] + "." + split[1]
|
|
elementName := split[2]
|
|
attrFeatureSet, ok := features.Attributes[featureName]
|
|
if !ok {
|
|
return "", fmt.Errorf("feature %s not found", featureName)
|
|
}
|
|
element, ok := attrFeatureSet.Elements[elementName]
|
|
if !ok {
|
|
return "", fmt.Errorf("element %s not found on feature %s", elementName, featureName)
|
|
}
|
|
return element, nil
|
|
}
|