1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-06 08:47:04 +00:00

Merge pull request #2010 from mfranczy/image-compatibility-nfr

Bugfixes for image compatibility feature
This commit is contained in:
Kubernetes Prow Robot 2025-01-09 23:58:31 -08:00 committed by GitHub
commit feea0e328e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 52 additions and 3 deletions

View file

@ -269,7 +269,11 @@ func evaluateFeatureMatcher(m *nfdv1alpha1.FeatureMatcher, features *nfdv1alpha1
fI, okI := features.Instances[featureName]
if !okF && !okA && !okI {
klog.V(2).InfoS("feature not available", "featureName", featureName)
return false, nil, nil
if failFast {
return false, nil, nil
}
isMatch = false
continue
}
if term.MatchExpressions != nil {

View file

@ -22,6 +22,8 @@ import (
"context"
"encoding/json"
"fmt"
"slices"
"time"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
oras "oras.land/oras-go/v2"
@ -34,6 +36,10 @@ import (
compatv1alpha1 "sigs.k8s.io/node-feature-discovery/api/image-compatibility/v1alpha1"
)
const (
ArtifactCreationTimestampKey = "org.opencontainers.image.created"
)
// ArtifactClient interface contain set of functions to manipulate compatibility artfact.
type ArtifactClient interface {
// FetchCompatibilitySpec downloads the compatibility specifcation associated with the image.
@ -90,6 +96,14 @@ func (c *Client) FetchCompatibilitySpec(ctx context.Context) (*compatv1alpha1.Sp
} else if len(descs) < 1 {
return nil, fmt.Errorf("compatibility artifact not found")
}
// Sort the artifacts in desc order.
// If the artifact does not have creation timestamp it will be moved to the top of the slice.
slices.SortFunc(descs, func(i, j ocispec.Descriptor) int {
it, _ := time.Parse(time.RFC3339, i.Annotations[ArtifactCreationTimestampKey])
jt, _ := time.Parse(time.RFC3339, j.Annotations[ArtifactCreationTimestampKey])
return it.Compare(jt)
})
artifactDesc := descs[len(descs)-1]
_, content, err := oras.FetchBytes(ctx, repo.Manifests(), artifactDesc.Digest.String(), oras.DefaultFetchBytesOptions)

View file

@ -97,6 +97,7 @@ func (nv *nodeValidator) Execute(ctx context.Context) ([]*CompatibilityStatus, e
}
func evaluateRuleStatus(rule *nfdv1alpha1.Rule, matchStatus *nodefeaturerule.MatchStatus) ProcessedRuleStatus {
var matchedFeatureTerms nfdv1alpha1.FeatureMatcher
out := ProcessedRuleStatus{Name: rule.Name, IsMatch: matchStatus.IsMatch}
evaluateFeatureMatcher := func(featureMatcher, matchedFeatureTerms nfdv1alpha1.FeatureMatcher) []MatchedExpression {
@ -163,11 +164,17 @@ func evaluateRuleStatus(rule *nfdv1alpha1.Rule, matchStatus *nodefeaturerule.Mat
}
if matchFeatures := rule.MatchFeatures; matchFeatures != nil {
out.MatchedExpressions = evaluateFeatureMatcher(matchFeatures, matchStatus.MatchedFeaturesTerms)
if matchStatus.MatchFeatureStatus != nil {
matchedFeatureTerms = matchStatus.MatchFeatureStatus.MatchedFeaturesTerms
}
out.MatchedExpressions = evaluateFeatureMatcher(matchFeatures, matchedFeatureTerms)
}
for i, matchAnyElem := range rule.MatchAny {
matchedExpressions := evaluateFeatureMatcher(matchAnyElem.MatchFeatures, matchStatus.MatchAny[i].MatchedFeaturesTerms)
if matchStatus.MatchAny[i].MatchedFeaturesTerms != nil {
matchedFeatureTerms = matchStatus.MatchAny[i].MatchedFeaturesTerms
}
matchedExpressions := evaluateFeatureMatcher(matchAnyElem.MatchFeatures, matchedFeatureTerms)
out.MatchedAny = append(out.MatchedAny, MatchAnyElem{MatchedExpressions: matchedExpressions})
}

View file

@ -114,6 +114,17 @@ func TestNodeValidator(t *testing.T) {
},
},
},
{
Name: "fake_5",
MatchFeatures: v1alpha1.FeatureMatcher{
{
Feature: "unknown.unknown",
MatchExpressions: &v1alpha1.MatchExpressionSet{
"name": &v1alpha1.MatchExpression{Op: v1alpha1.MatchIn, Value: v1alpha1.MatchValue{"instance_1"}},
},
},
},
},
},
},
},
@ -219,6 +230,19 @@ func TestNodeValidator(t *testing.T) {
},
},
},
{
Name: "fake_5",
IsMatch: false,
MatchedExpressions: []MatchedExpression{
{
Feature: "unknown.unknown",
Name: "name",
Expression: &v1alpha1.MatchExpression{Op: v1alpha1.MatchIn, Value: v1alpha1.MatchValue{"instance_1"}},
MatcherType: MatchExpressionType,
IsMatch: false,
},
},
},
},
},
}