...

Source file src/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_test.go

Documentation: sigs.k8s.io/controller-runtime/pkg/envtest

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package envtest
    18  
    19  import (
    20  	"context"
    21  	"path/filepath"
    22  	"time"
    23  
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    27  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/types"
    30  	"k8s.io/client-go/kubernetes/scheme"
    31  
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  )
    34  
    35  var _ = Describe("Test", func() {
    36  	var crds []*apiextensionsv1.CustomResourceDefinition
    37  	var err error
    38  	var s *runtime.Scheme
    39  	var c client.Client
    40  
    41  	var validDirectory = filepath.Join(".", "testdata")
    42  	var invalidDirectory = "fake"
    43  
    44  	var teardownTimeoutSeconds float64 = 10
    45  
    46  	// Initialize the client
    47  	BeforeEach(func() {
    48  		crds = []*apiextensionsv1.CustomResourceDefinition{}
    49  		s = scheme.Scheme
    50  		err = apiextensionsv1.AddToScheme(s)
    51  		Expect(err).NotTo(HaveOccurred())
    52  
    53  		c, err = client.New(env.Config, client.Options{Scheme: s})
    54  		Expect(err).NotTo(HaveOccurred())
    55  	})
    56  
    57  	// Cleanup CRDs
    58  	AfterEach(func() {
    59  		for _, crd := range crds {
    60  			crd := crd
    61  			// Delete only if CRD exists.
    62  			crdObjectKey := client.ObjectKey{
    63  				Name: crd.GetName(),
    64  			}
    65  			var placeholder apiextensionsv1.CustomResourceDefinition
    66  			if err = c.Get(context.TODO(), crdObjectKey, &placeholder); err != nil &&
    67  				apierrors.IsNotFound(err) {
    68  				// CRD doesn't need to be deleted.
    69  				continue
    70  			}
    71  			Expect(err).NotTo(HaveOccurred())
    72  			Expect(c.Delete(context.TODO(), crd)).To(Succeed())
    73  			Eventually(func() bool {
    74  				err := c.Get(context.TODO(), crdObjectKey, &placeholder)
    75  				return apierrors.IsNotFound(err)
    76  			}, 5*time.Second).Should(BeTrue())
    77  		}
    78  	}, teardownTimeoutSeconds)
    79  
    80  	Describe("InstallCRDs", func() {
    81  		It("should install the unserved CRDs into the cluster", func() {
    82  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
    83  				Paths: []string{filepath.Join(".", "testdata", "crds", "examplecrd_unserved.yaml")},
    84  			})
    85  			Expect(err).NotTo(HaveOccurred())
    86  
    87  			// Expect to find the CRDs
    88  
    89  			crd := &apiextensionsv1.CustomResourceDefinition{}
    90  			err = c.Get(context.TODO(), types.NamespacedName{Name: "frigates.ship.example.com"}, crd)
    91  			Expect(err).NotTo(HaveOccurred())
    92  			Expect(crd.Spec.Names.Kind).To(Equal("Frigate"))
    93  
    94  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
    95  				{
    96  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
    97  						Group: "ship.example.com",
    98  						Names: apiextensionsv1.CustomResourceDefinitionNames{
    99  							Plural: "frigates",
   100  						},
   101  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   102  							{
   103  								Name:    "v1",
   104  								Storage: true,
   105  								Served:  false,
   106  							},
   107  							{
   108  								Name:    "v1beta1",
   109  								Storage: false,
   110  								Served:  false,
   111  							},
   112  						}},
   113  				},
   114  			},
   115  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   116  			)
   117  			Expect(err).NotTo(HaveOccurred())
   118  		})
   119  		It("should install the CRDs into the cluster using directory", func() {
   120  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   121  				Paths: []string{validDirectory},
   122  			})
   123  			Expect(err).NotTo(HaveOccurred())
   124  
   125  			// Expect to find the CRDs
   126  
   127  			crd := &apiextensionsv1.CustomResourceDefinition{}
   128  			err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
   129  			Expect(err).NotTo(HaveOccurred())
   130  			Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
   131  
   132  			crd = &apiextensionsv1.CustomResourceDefinition{}
   133  			err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
   134  			Expect(err).NotTo(HaveOccurred())
   135  			Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
   136  
   137  			crd = &apiextensionsv1.CustomResourceDefinition{}
   138  			err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
   139  			Expect(err).NotTo(HaveOccurred())
   140  			Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
   141  
   142  			crd = &apiextensionsv1.CustomResourceDefinition{}
   143  			err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
   144  			Expect(err).NotTo(HaveOccurred())
   145  			Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
   146  
   147  			crd = &apiextensionsv1.CustomResourceDefinition{}
   148  			err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   149  			Expect(err).NotTo(HaveOccurred())
   150  			Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   151  
   152  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   153  				{
   154  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   155  						Group: "bar.example.com",
   156  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   157  							{
   158  								Name:    "v1",
   159  								Storage: true,
   160  								Served:  true,
   161  								Schema: &apiextensionsv1.CustomResourceValidation{
   162  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   163  										Type: "object",
   164  									},
   165  								},
   166  							},
   167  						},
   168  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   169  							Plural: "foos",
   170  						}},
   171  				},
   172  				{
   173  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   174  						Group: "qux.example.com",
   175  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   176  							{
   177  								Name:    "v1beta1",
   178  								Storage: true,
   179  								Served:  true,
   180  								Schema: &apiextensionsv1.CustomResourceValidation{
   181  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   182  								},
   183  							},
   184  						},
   185  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   186  							Plural: "bazs",
   187  						}},
   188  				},
   189  				{
   190  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   191  						Group: "crew.example.com",
   192  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   193  							{
   194  								Name:    "v1beta1",
   195  								Storage: true,
   196  								Served:  true,
   197  								Schema: &apiextensionsv1.CustomResourceValidation{
   198  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   199  								},
   200  							},
   201  						},
   202  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   203  							Plural: "captains",
   204  						}},
   205  				},
   206  				{
   207  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   208  						Group: "crew.example.com",
   209  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   210  							{
   211  								Name:    "v1beta1",
   212  								Storage: true,
   213  								Served:  true,
   214  								Schema: &apiextensionsv1.CustomResourceValidation{
   215  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   216  								},
   217  							},
   218  						},
   219  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   220  							Plural: "firstmates",
   221  						}},
   222  				},
   223  				{
   224  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   225  						Group: "crew.example.com",
   226  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   227  							Plural: "drivers",
   228  						},
   229  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   230  							{
   231  								Name:    "v1",
   232  								Storage: true,
   233  								Served:  true,
   234  							},
   235  							{
   236  								Name:    "v2",
   237  								Storage: false,
   238  								Served:  true,
   239  							},
   240  						}},
   241  				},
   242  			},
   243  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   244  			)
   245  			Expect(err).NotTo(HaveOccurred())
   246  		})
   247  
   248  		It("should install the CRDs into the cluster using file", func() {
   249  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   250  				Paths: []string{filepath.Join(".", "testdata", "crds", "examplecrd3.yaml")},
   251  			})
   252  			Expect(err).NotTo(HaveOccurred())
   253  
   254  			crd := &apiextensionsv1.CustomResourceDefinition{}
   255  			err = c.Get(context.TODO(), types.NamespacedName{Name: "configs.foo.example.com"}, crd)
   256  			Expect(err).NotTo(HaveOccurred())
   257  			Expect(crd.Spec.Names.Kind).To(Equal("Config"))
   258  
   259  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   260  				{
   261  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   262  						Group: "foo.example.com",
   263  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   264  							{
   265  								Name:    "v1beta1",
   266  								Storage: true,
   267  								Served:  true,
   268  								Schema: &apiextensionsv1.CustomResourceValidation{
   269  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   270  								},
   271  							},
   272  						},
   273  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   274  							Plural: "configs",
   275  						}},
   276  				},
   277  			},
   278  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   279  			)
   280  			Expect(err).NotTo(HaveOccurred())
   281  		})
   282  
   283  		It("should be able to install CRDs using multiple files", func() {
   284  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   285  				Paths: []string{
   286  					filepath.Join(".", "testdata", "examplecrd.yaml"),
   287  					filepath.Join(".", "testdata", "examplecrd_v1.yaml"),
   288  				},
   289  			})
   290  			Expect(err).NotTo(HaveOccurred())
   291  			Expect(crds).To(HaveLen(2))
   292  		})
   293  
   294  		It("should filter out already existent CRD", func() {
   295  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   296  				Paths: []string{
   297  					filepath.Join(".", "testdata"),
   298  					filepath.Join(".", "testdata", "examplecrd1.yaml"),
   299  				},
   300  			})
   301  			Expect(err).NotTo(HaveOccurred())
   302  
   303  			crd := &apiextensionsv1.CustomResourceDefinition{}
   304  			err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
   305  			Expect(err).NotTo(HaveOccurred())
   306  			Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
   307  
   308  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   309  				{
   310  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   311  						Group: "bar.example.com",
   312  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   313  							{
   314  								Name:    "v1",
   315  								Storage: true,
   316  								Served:  true,
   317  								Schema: &apiextensionsv1.CustomResourceValidation{
   318  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   319  										Type: "object",
   320  									},
   321  								},
   322  							},
   323  						},
   324  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   325  							Plural: "foos",
   326  						}},
   327  				},
   328  			},
   329  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   330  			)
   331  			Expect(err).NotTo(HaveOccurred())
   332  		})
   333  
   334  		It("should not return an not error if the directory doesn't exist", func() {
   335  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{Paths: []string{invalidDirectory}})
   336  			Expect(err).NotTo(HaveOccurred())
   337  		})
   338  
   339  		It("should return an error if the directory doesn't exist", func() {
   340  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   341  				Paths: []string{invalidDirectory}, ErrorIfPathMissing: true,
   342  			})
   343  			Expect(err).To(HaveOccurred())
   344  		})
   345  
   346  		It("should return an error if the file doesn't exist", func() {
   347  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{Paths: []string{
   348  				filepath.Join(".", "testdata", "fake.yaml")}, ErrorIfPathMissing: true,
   349  			})
   350  			Expect(err).To(HaveOccurred())
   351  		})
   352  
   353  		It("should return an error if the resource group version isn't found", func() {
   354  			// Wait for a CRD where the Group and Version don't exist
   355  			err := WaitForCRDs(env.Config,
   356  				[]*apiextensionsv1.CustomResourceDefinition{
   357  					{
   358  						Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   359  							Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   360  								{
   361  									Name:    "v1",
   362  									Storage: true,
   363  									Served:  true,
   364  									Schema: &apiextensionsv1.CustomResourceValidation{
   365  										OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   366  									},
   367  								},
   368  							},
   369  							Names: apiextensionsv1.CustomResourceDefinitionNames{
   370  								Plural: "notfound",
   371  							}},
   372  					},
   373  				},
   374  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   375  			)
   376  			Expect(err).To(HaveOccurred())
   377  		})
   378  
   379  		It("should return an error if the resource isn't found in the group version", func() {
   380  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   381  				Paths: []string{"."},
   382  			})
   383  			Expect(err).NotTo(HaveOccurred())
   384  
   385  			// Wait for a CRD that doesn't exist, but the Group and Version do
   386  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   387  				{
   388  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   389  						Group: "qux.example.com",
   390  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   391  							{
   392  								Name:    "v1beta1",
   393  								Storage: true,
   394  								Served:  true,
   395  								Schema: &apiextensionsv1.CustomResourceValidation{
   396  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   397  								},
   398  							},
   399  						},
   400  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   401  							Plural: "bazs",
   402  						}},
   403  				},
   404  				{
   405  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   406  						Group: "bar.example.com",
   407  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   408  							{
   409  								Name:    "v1beta1",
   410  								Storage: true,
   411  								Served:  true,
   412  								Schema: &apiextensionsv1.CustomResourceValidation{
   413  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   414  								},
   415  							},
   416  						},
   417  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   418  							Plural: "fake",
   419  						}},
   420  				}},
   421  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   422  			)
   423  			Expect(err).To(HaveOccurred())
   424  		})
   425  
   426  		It("should reinstall the CRDs if already present in the cluster", func() {
   427  
   428  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   429  				Paths: []string{filepath.Join(".", "testdata")},
   430  			})
   431  			Expect(err).NotTo(HaveOccurred())
   432  
   433  			// Expect to find the CRDs
   434  
   435  			crd := &apiextensionsv1.CustomResourceDefinition{}
   436  			err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
   437  			Expect(err).NotTo(HaveOccurred())
   438  			Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
   439  
   440  			crd = &apiextensionsv1.CustomResourceDefinition{}
   441  			err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
   442  			Expect(err).NotTo(HaveOccurred())
   443  			Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
   444  
   445  			crd = &apiextensionsv1.CustomResourceDefinition{}
   446  			err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
   447  			Expect(err).NotTo(HaveOccurred())
   448  			Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
   449  
   450  			crd = &apiextensionsv1.CustomResourceDefinition{}
   451  			err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
   452  			Expect(err).NotTo(HaveOccurred())
   453  			Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
   454  
   455  			crd = &apiextensionsv1.CustomResourceDefinition{}
   456  			err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   457  			Expect(err).NotTo(HaveOccurred())
   458  			Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   459  
   460  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   461  				{
   462  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   463  						Group: "bar.example.com",
   464  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   465  							{
   466  								Name:    "v1",
   467  								Storage: true,
   468  								Served:  true,
   469  								Schema: &apiextensionsv1.CustomResourceValidation{
   470  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   471  										Type: "object",
   472  									},
   473  								},
   474  							},
   475  						},
   476  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   477  							Plural: "foos",
   478  						}},
   479  				},
   480  				{
   481  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   482  						Group: "qux.example.com",
   483  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   484  							{
   485  								Name:    "v1beta1",
   486  								Storage: true,
   487  								Served:  true,
   488  								Schema: &apiextensionsv1.CustomResourceValidation{
   489  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   490  								},
   491  							},
   492  						},
   493  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   494  							Plural: "bazs",
   495  						}},
   496  				},
   497  				{
   498  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   499  						Group: "crew.example.com",
   500  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   501  							{
   502  								Name:    "v1beta1",
   503  								Storage: true,
   504  								Served:  true,
   505  								Schema: &apiextensionsv1.CustomResourceValidation{
   506  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   507  								},
   508  							},
   509  						},
   510  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   511  							Plural: "captains",
   512  						}},
   513  				},
   514  				{
   515  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   516  						Group: "crew.example.com",
   517  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   518  							{
   519  								Name:    "v1beta1",
   520  								Storage: true,
   521  								Served:  true,
   522  								Schema: &apiextensionsv1.CustomResourceValidation{
   523  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   524  								},
   525  							},
   526  						},
   527  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   528  							Plural: "firstmates",
   529  						}},
   530  				},
   531  				{
   532  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   533  						Group: "crew.example.com",
   534  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   535  							Plural: "drivers",
   536  						},
   537  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   538  							{
   539  								Name:    "v1",
   540  								Storage: true,
   541  								Served:  true,
   542  							},
   543  							{
   544  								Name:    "v2",
   545  								Storage: false,
   546  								Served:  true,
   547  							},
   548  						}},
   549  				},
   550  			},
   551  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   552  			)
   553  			Expect(err).NotTo(HaveOccurred())
   554  
   555  			// Try to re-install the CRDs
   556  
   557  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   558  				Paths: []string{filepath.Join(".", "testdata")},
   559  			})
   560  			Expect(err).NotTo(HaveOccurred())
   561  
   562  			// Expect to find the CRDs
   563  
   564  			crd = &apiextensionsv1.CustomResourceDefinition{}
   565  			err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
   566  			Expect(err).NotTo(HaveOccurred())
   567  			Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
   568  
   569  			crd = &apiextensionsv1.CustomResourceDefinition{}
   570  			err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
   571  			Expect(err).NotTo(HaveOccurred())
   572  			Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
   573  
   574  			crd = &apiextensionsv1.CustomResourceDefinition{}
   575  			err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
   576  			Expect(err).NotTo(HaveOccurred())
   577  			Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
   578  
   579  			crd = &apiextensionsv1.CustomResourceDefinition{}
   580  			err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
   581  			Expect(err).NotTo(HaveOccurred())
   582  			Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
   583  
   584  			crd = &apiextensionsv1.CustomResourceDefinition{}
   585  			err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   586  			Expect(err).NotTo(HaveOccurred())
   587  			Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   588  
   589  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   590  				{
   591  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   592  						Group: "bar.example.com",
   593  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   594  							{
   595  								Name:    "v1",
   596  								Storage: true,
   597  								Served:  true,
   598  								Schema: &apiextensionsv1.CustomResourceValidation{
   599  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   600  										Type: "object",
   601  									},
   602  								},
   603  							},
   604  						},
   605  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   606  							Plural: "foos",
   607  						}},
   608  				},
   609  				{
   610  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   611  						Group: "qux.example.com",
   612  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   613  							{
   614  								Name:    "v1beta1",
   615  								Storage: true,
   616  								Served:  true,
   617  								Schema: &apiextensionsv1.CustomResourceValidation{
   618  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   619  								},
   620  							},
   621  						},
   622  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   623  							Plural: "bazs",
   624  						}},
   625  				},
   626  				{
   627  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   628  						Group: "crew.example.com",
   629  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   630  							{
   631  								Name:    "v1beta1",
   632  								Storage: true,
   633  								Served:  true,
   634  								Schema: &apiextensionsv1.CustomResourceValidation{
   635  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   636  								},
   637  							},
   638  						},
   639  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   640  							Plural: "captains",
   641  						}},
   642  				},
   643  				{
   644  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   645  						Group: "crew.example.com",
   646  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   647  							{
   648  								Name:    "v1beta1",
   649  								Storage: true,
   650  								Served:  true,
   651  								Schema: &apiextensionsv1.CustomResourceValidation{
   652  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   653  								},
   654  							},
   655  						},
   656  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   657  							Plural: "firstmates",
   658  						}},
   659  				},
   660  				{
   661  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   662  						Group: "crew.example.com",
   663  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   664  							Plural: "drivers",
   665  						},
   666  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   667  							{
   668  								Name:    "v1",
   669  								Storage: true,
   670  								Served:  true,
   671  							},
   672  							{
   673  								Name:    "v2",
   674  								Storage: false,
   675  								Served:  true,
   676  							},
   677  						}},
   678  				},
   679  			},
   680  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   681  			)
   682  			Expect(err).NotTo(HaveOccurred())
   683  		})
   684  	})
   685  
   686  	It("should update CRDs if already present in the cluster", func() {
   687  
   688  		// Install only the CRDv1 multi-version example
   689  		crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   690  			Paths: []string{filepath.Join(".", "testdata")},
   691  		})
   692  		Expect(err).NotTo(HaveOccurred())
   693  
   694  		// Expect to find the CRDs
   695  
   696  		crd := &apiextensionsv1.CustomResourceDefinition{}
   697  		err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   698  		Expect(err).NotTo(HaveOccurred())
   699  		Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   700  		Expect(len(crd.Spec.Versions)).To(BeEquivalentTo(2))
   701  
   702  		// Store resource version for comparison later on
   703  		firstRV := crd.ResourceVersion
   704  
   705  		err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   706  			{
   707  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   708  					Group: "crew.example.com",
   709  					Names: apiextensionsv1.CustomResourceDefinitionNames{
   710  						Plural: "drivers",
   711  					},
   712  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   713  						{
   714  							Name:    "v1",
   715  							Storage: true,
   716  							Served:  true,
   717  						},
   718  						{
   719  							Name:    "v2",
   720  							Storage: false,
   721  							Served:  true,
   722  						},
   723  					}},
   724  			},
   725  		},
   726  			CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   727  		)
   728  		Expect(err).NotTo(HaveOccurred())
   729  
   730  		// Add one more version and update
   731  		_, err = InstallCRDs(env.Config, CRDInstallOptions{
   732  			Paths: []string{filepath.Join(".", "testdata", "crdv1_updated")},
   733  		})
   734  		Expect(err).NotTo(HaveOccurred())
   735  
   736  		// Expect to find updated CRD
   737  
   738  		crd = &apiextensionsv1.CustomResourceDefinition{}
   739  		err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   740  		Expect(err).NotTo(HaveOccurred())
   741  		Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   742  		Expect(len(crd.Spec.Versions)).To(BeEquivalentTo(3))
   743  		Expect(crd.ResourceVersion).NotTo(BeEquivalentTo(firstRV))
   744  
   745  		err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   746  			{
   747  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   748  					Group: "crew.example.com",
   749  					Names: apiextensionsv1.CustomResourceDefinitionNames{
   750  						Plural: "drivers",
   751  					},
   752  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   753  						{
   754  							Name:    "v1",
   755  							Storage: true,
   756  							Served:  true,
   757  						},
   758  						{
   759  							Name:    "v2",
   760  							Storage: false,
   761  							Served:  true,
   762  						},
   763  						{
   764  							Name:    "v3",
   765  							Storage: false,
   766  							Served:  true,
   767  						},
   768  					}},
   769  			},
   770  		},
   771  			CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   772  		)
   773  		Expect(err).NotTo(HaveOccurred())
   774  	})
   775  
   776  	Describe("UninstallCRDs", func() {
   777  		It("should uninstall the CRDs from the cluster", func() {
   778  
   779  			crds, err = InstallCRDs(env.Config, CRDInstallOptions{
   780  				Paths: []string{validDirectory},
   781  			})
   782  			Expect(err).NotTo(HaveOccurred())
   783  
   784  			// Expect to find the CRDs
   785  
   786  			crd := &apiextensionsv1.CustomResourceDefinition{}
   787  			err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
   788  			Expect(err).NotTo(HaveOccurred())
   789  			Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
   790  
   791  			crd = &apiextensionsv1.CustomResourceDefinition{}
   792  			err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
   793  			Expect(err).NotTo(HaveOccurred())
   794  			Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
   795  
   796  			crd = &apiextensionsv1.CustomResourceDefinition{}
   797  			err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
   798  			Expect(err).NotTo(HaveOccurred())
   799  			Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
   800  
   801  			crd = &apiextensionsv1.CustomResourceDefinition{}
   802  			err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
   803  			Expect(err).NotTo(HaveOccurred())
   804  			Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
   805  
   806  			crd = &apiextensionsv1.CustomResourceDefinition{}
   807  			err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
   808  			Expect(err).NotTo(HaveOccurred())
   809  			Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
   810  
   811  			err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
   812  				{
   813  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   814  						Group: "bar.example.com",
   815  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   816  							{
   817  								Name:    "v1",
   818  								Storage: true,
   819  								Served:  true,
   820  								Schema: &apiextensionsv1.CustomResourceValidation{
   821  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   822  										Type: "object",
   823  									},
   824  								},
   825  							},
   826  						},
   827  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   828  							Plural: "foos",
   829  						}},
   830  				},
   831  				{
   832  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   833  						Group: "qux.example.com",
   834  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   835  							{
   836  								Name:    "v1beta1",
   837  								Storage: true,
   838  								Served:  true,
   839  								Schema: &apiextensionsv1.CustomResourceValidation{
   840  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   841  								},
   842  							},
   843  						},
   844  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   845  							Plural: "bazs",
   846  						}},
   847  				},
   848  				{
   849  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   850  						Group: "crew.example.com",
   851  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   852  							{
   853  								Name:    "v1beta1",
   854  								Storage: true,
   855  								Served:  true,
   856  								Schema: &apiextensionsv1.CustomResourceValidation{
   857  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   858  								},
   859  							},
   860  						},
   861  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   862  							Plural: "captains",
   863  						}},
   864  				},
   865  				{
   866  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   867  						Group: "crew.example.com",
   868  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   869  							{
   870  								Name:    "v1beta1",
   871  								Storage: true,
   872  								Served:  true,
   873  								Schema: &apiextensionsv1.CustomResourceValidation{
   874  									OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
   875  								},
   876  							},
   877  						},
   878  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   879  							Plural: "firstmates",
   880  						}},
   881  				},
   882  				{
   883  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   884  						Group: "crew.example.com",
   885  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   886  							Plural: "drivers",
   887  						},
   888  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   889  							{
   890  								Name:    "v1",
   891  								Storage: true,
   892  								Served:  true,
   893  							},
   894  							{
   895  								Name:    "v2",
   896  								Storage: false,
   897  								Served:  true,
   898  							},
   899  						}},
   900  				},
   901  			},
   902  				CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
   903  			)
   904  			Expect(err).NotTo(HaveOccurred())
   905  
   906  			err = UninstallCRDs(env.Config, CRDInstallOptions{
   907  				Paths: []string{validDirectory},
   908  			})
   909  			Expect(err).NotTo(HaveOccurred())
   910  
   911  			// Expect to NOT find the CRDs
   912  
   913  			crds := []string{
   914  				"foos.bar.example.com",
   915  				"bazs.qux.example.com",
   916  				"captains.crew.example.com",
   917  				"firstmates.crew.example.com",
   918  				"drivers.crew.example.com",
   919  			}
   920  			placeholder := &apiextensionsv1.CustomResourceDefinition{}
   921  			Eventually(func() bool {
   922  				for _, crd := range crds {
   923  					err = c.Get(context.TODO(), types.NamespacedName{Name: crd}, placeholder)
   924  					notFound := err != nil && apierrors.IsNotFound(err)
   925  					if !notFound {
   926  						return false
   927  					}
   928  				}
   929  				return true
   930  			}, 20).Should(BeTrue())
   931  		})
   932  	})
   933  
   934  	Describe("Start", func() {
   935  		It("should raise an error on invalid dir when flag is enabled", func() {
   936  			env := &Environment{ErrorIfCRDPathMissing: true, CRDDirectoryPaths: []string{invalidDirectory}}
   937  			_, err := env.Start()
   938  			Expect(err).To(HaveOccurred())
   939  			Expect(env.Stop()).To(Succeed())
   940  		})
   941  
   942  		It("should not raise an error on invalid dir when flag is disabled", func() {
   943  			env := &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
   944  			_, err := env.Start()
   945  			Expect(err).NotTo(HaveOccurred())
   946  			Expect(env.Stop()).To(Succeed())
   947  		})
   948  	})
   949  
   950  	Describe("Stop", func() {
   951  		It("should cleanup webhook /tmp folder with no error when using existing cluster", func() {
   952  			env := &Environment{}
   953  			_, err := env.Start()
   954  			Expect(err).NotTo(HaveOccurred())
   955  			Expect(env.Stop()).To(Succeed())
   956  
   957  			// check if the /tmp/envtest-serving-certs-* dir doesnt exists any more
   958  			Expect(env.WebhookInstallOptions.LocalServingCertDir).ShouldNot(BeADirectory())
   959  		})
   960  	})
   961  })
   962  

View as plain text