sigs.k8s.io/controller-runtime@v0.18.2/pkg/envtest/envtest_test.go (about) 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 })