diff --git a/test/e2e/node_feature_discovery.go b/test/e2e/node_feature_discovery.go index 39c50ccad3..e19144916a 100644 --- a/test/e2e/node_feature_discovery.go +++ b/test/e2e/node_feature_discovery.go @@ -390,7 +390,7 @@ var _ = SIGDescribe("Node Feature Discovery", func() { Context("and nfd-worker and NodeFeatureRules objects deployed", func() { var extClient *extclient.Clientset var nfdClient *nfdclient.Clientset - var crd *apiextensionsv1.CustomResourceDefinition + var crds []*apiextensionsv1.CustomResourceDefinition BeforeEach(func() { // Create clients for apiextensions and our CRD api @@ -398,15 +398,17 @@ var _ = SIGDescribe("Node Feature Discovery", func() { nfdClient = nfdclient.NewForConfigOrDie(f.ClientConfig()) // Create CRDs - By("Creating NodeFeatureRule CRD") + By("Creating NFD CRDs") var err error - crd, err = testutils.CreateNodeFeatureRulesCRD(extClient) + crds, err = testutils.CreateNfdCRDs(extClient) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { - err := extClient.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}) - Expect(err).NotTo(HaveOccurred()) + for _, crd := range crds { + err := extClient.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + } }) It("custom labels from the NodeFeatureRule rules should be created", func() { @@ -438,13 +440,13 @@ core: "feature.node.kubernetes.io/e2e-instance-test-1": "true"} By("Creating NodeFeatureRules #1") - Expect(testutils.CreateNodeFeatureRuleFromFile(nfdClient, "nodefeaturerule-1.yaml")).NotTo(HaveOccurred()) + Expect(testutils.CreateNodeFeatureRulesFromFile(nfdClient, "nodefeaturerule-1.yaml")).NotTo(HaveOccurred()) By("Verifying node labels from NodeFeatureRules #1") Expect(waitForNfdNodeLabels(f.ClientSet, expected)).NotTo(HaveOccurred()) By("Creating NodeFeatureRules #2") - Expect(testutils.CreateNodeFeatureRuleFromFile(nfdClient, "nodefeaturerule-2.yaml")).NotTo(HaveOccurred()) + Expect(testutils.CreateNodeFeatureRulesFromFile(nfdClient, "nodefeaturerule-2.yaml")).NotTo(HaveOccurred()) // Add features from NodeFeatureRule #2 expected["feature.node.kubernetes.io/e2e-matchany-test-1"] = "true" diff --git a/test/e2e/utils/crd.go b/test/e2e/utils/crd.go index 5a45e642db..76ea53c00d 100644 --- a/test/e2e/utils/crd.go +++ b/test/e2e/utils/crd.go @@ -17,6 +17,7 @@ limitations under the License. package utils import ( + "bytes" "context" "fmt" "os" @@ -36,69 +37,104 @@ import ( var packagePath string -// CreateNodeFeatureRulesCRD creates the NodeFeatureRule CRD in the API server. -func CreateNodeFeatureRulesCRD(cli extclient.Interface) (*apiextensionsv1.CustomResourceDefinition, error) { - crd, err := crdFromFile(filepath.Join(packagePath, "..", "..", "..", "deployment", "base", "nfd-crds", "nodefeaturerule-crd.yaml")) +// CreateNfdCRDs creates the NodeFeatureRule CRD in the API server. +func CreateNfdCRDs(cli extclient.Interface) ([]*apiextensionsv1.CustomResourceDefinition, error) { + crds, err := crdsFromFile(filepath.Join(packagePath, "..", "..", "..", "deployment", "base", "nfd-crds", "nfd-api-crds.yaml")) if err != nil { return nil, err } - // Delete existing CRD (if any) with this we also get rid of stale objects - err = cli.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}) - if err != nil && !errors.IsNotFound(err) { - return nil, fmt.Errorf("failed to delete NodeFeatureRule CRD: %w", err) + newCRDs := make([]*apiextensionsv1.CustomResourceDefinition, len(crds)) + for i, crd := range crds { + // Delete existing CRD (if any) with this we also get rid of stale objects + err = cli.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}) + if err != nil && !errors.IsNotFound(err) { + return nil, fmt.Errorf("failed to delete NodeFeatureRule CRD: %w", err) + } + newCRDs[i], err = cli.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) + if err != nil { + return nil, err + } } - - return cli.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) + return newCRDs, nil } // CreateNodeFeatureRuleFromFile creates a NodeFeatureRule object from a given file located under test data directory. -func CreateNodeFeatureRuleFromFile(cli nfdclientset.Interface, filename string) error { - obj, err := nodeFeatureRuleFromFile(filepath.Join(packagePath, "..", "data", filename)) +func CreateNodeFeatureRulesFromFile(cli nfdclientset.Interface, filename string) error { + objs, err := nodeFeatureRulesFromFile(filepath.Join(packagePath, "..", "data", filename)) if err != nil { return err } - _, err = cli.NfdV1alpha1().NodeFeatureRules().Create(context.TODO(), obj, metav1.CreateOptions{}) - return err + + for _, obj := range objs { + if _, err = cli.NfdV1alpha1().NodeFeatureRules().Create(context.TODO(), obj, metav1.CreateOptions{}); err != nil { + return err + } + } + return nil } -func apiObjFromFile(path string, decoder apiruntime.Decoder) (apiruntime.Object, error) { +func apiObjsFromFile(path string, decoder apiruntime.Decoder) ([]apiruntime.Object, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } - obj, _, err := decoder.Decode(data, nil, nil) - return obj, err + // TODO: find out a nicer way to decode multiple api objects from a single + // file (K8s must have that somewhere) + split := bytes.Split(data, []byte("---")) + objs := []apiruntime.Object{} + + for _, slice := range split { + if len(slice) == 0 { + continue + } + obj, _, err := decoder.Decode(slice, nil, nil) + if err != nil { + return nil, err + } + objs = append(objs, obj) + } + return objs, err } -// crdFromFile creates a CustomResourceDefinition API object from a file. -func crdFromFile(path string) (*apiextensionsv1.CustomResourceDefinition, error) { - obj, err := apiObjFromFile(path, scheme.Codecs.UniversalDeserializer()) +// crdsFromFile creates a CustomResourceDefinition API object from a file. +func crdsFromFile(path string) ([]*apiextensionsv1.CustomResourceDefinition, error) { + objs, err := apiObjsFromFile(path, scheme.Codecs.UniversalDeserializer()) if err != nil { return nil, err } - crd, ok := obj.(*apiextensionsv1.CustomResourceDefinition) - if !ok { - return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path) + crds := make([]*apiextensionsv1.CustomResourceDefinition, len(objs)) + + for i, obj := range objs { + var ok bool + crds[i], ok = obj.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + return nil, fmt.Errorf("unexpected type %T when reading %q", obj, path) + } } - return crd, nil + return crds, nil } -func nodeFeatureRuleFromFile(path string) (*nfdv1alpha1.NodeFeatureRule, error) { - obj, err := apiObjFromFile(path, nfdscheme.Codecs.UniversalDeserializer()) +func nodeFeatureRulesFromFile(path string) ([]*nfdv1alpha1.NodeFeatureRule, error) { + objs, err := apiObjsFromFile(path, nfdscheme.Codecs.UniversalDeserializer()) if err != nil { return nil, err } - crd, ok := obj.(*nfdv1alpha1.NodeFeatureRule) - if !ok { - return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path) + crs := make([]*nfdv1alpha1.NodeFeatureRule, len(objs)) + + for i, obj := range objs { + var ok bool + crs[i], ok = obj.(*nfdv1alpha1.NodeFeatureRule) + if !ok { + return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path) + } } - return crd, nil + return crs, nil } func init() {