diff --git a/api/v1alpha1/webhook_suite_test.go b/api/v1alpha1/webhook_suite_test.go deleted file mode 100644 index 2b53b5558..000000000 --- a/api/v1alpha1/webhook_suite_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package v1alpha1 - -import ( - "context" - "crypto/tls" - "fmt" - "net" - "path/filepath" - "testing" - "time" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - admissionv1beta1 "k8s.io/api/admission/v1beta1" - //+kubebuilder:scaffold:imports - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment -var ctx context.Context -var cancel context.CancelFunc - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Webhook Suite", - []Reporter{printer.NewlineReporter{}}) -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - ctx, cancel = context.WithCancel(context.TODO()) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: false, - WebhookInstallOptions: envtest.WebhookInstallOptions{ - Paths: []string{filepath.Join("..", "..", "config", "webhook")}, - }, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - scheme := runtime.NewScheme() - err = AddToScheme(scheme) - Expect(err).NotTo(HaveOccurred()) - - err = admissionv1beta1.AddToScheme(scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - - // start webhook server using Manager - webhookInstallOptions := &testEnv.WebhookInstallOptions - mgr, err := ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme, - Host: webhookInstallOptions.LocalServingHost, - Port: webhookInstallOptions.LocalServingPort, - CertDir: webhookInstallOptions.LocalServingCertDir, - LeaderElection: false, - MetricsBindAddress: "0", - }) - Expect(err).NotTo(HaveOccurred()) - - err = (&VCluster{}).SetupWebhookWithManager(mgr) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:webhook - - go func() { - defer GinkgoRecover() - err = mgr.Start(ctx) - Expect(err).NotTo(HaveOccurred()) - }() - - // wait for the webhook server to get ready - dialer := &net.Dialer{Timeout: time.Second} - addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) - Eventually(func() error { - conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) - if err != nil { - return err - } - conn.Close() - return nil - }).Should(Succeed()) - -}, 60) - -var _ = AfterSuite(func() { - cancel() - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/go.mod b/go.mod index 60b223741..6fcf8ee1a 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,6 @@ require ( github.com/google/go-cmp v0.5.9 github.com/loft-sh/utils v0.0.13-alpha github.com/loft-sh/vcluster v0.13.0-alpha.0 - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.23.0 github.com/pkg/errors v0.9.1 k8s.io/api v0.26.1 k8s.io/apimachinery v0.26.1 @@ -60,10 +58,8 @@ require ( github.com/moby/spdystream v0.2.0 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nxadm/tail v1.4.8 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cobra v1.4.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect k8s.io/kubectl v0.25.2 // indirect ) @@ -97,6 +93,8 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.4.0 // indirect + github.com/onsi/gomega v1.23.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect diff --git a/go.sum b/go.sum index d7f5cf492..eab173a18 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,6 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= @@ -164,7 +162,6 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -264,7 +261,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= @@ -341,16 +337,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -527,7 +517,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -539,11 +528,8 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -566,7 +552,6 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -656,7 +641,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -812,11 +796,9 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go deleted file mode 100644 index 3b52ae8f9..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go +++ /dev/null @@ -1,456 +0,0 @@ -/* -Copyright 2018 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 envtest - -import ( - "bufio" - "bytes" - "context" - "errors" - "fmt" - "io" - "os" - "path/filepath" - "time" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - k8syaml "k8s.io/apimachinery/pkg/util/yaml" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "k8s.io/client-go/util/retry" - "k8s.io/utils/pointer" - "sigs.k8s.io/yaml" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/conversion" -) - -// CRDInstallOptions are the options for installing CRDs. -type CRDInstallOptions struct { - // Scheme is used to determine if conversion webhooks should be enabled - // for a particular CRD / object. - // - // Conversion webhooks are going to be enabled if an object in the scheme - // implements Hub and Spoke conversions. - // - // If nil, scheme.Scheme is used. - Scheme *runtime.Scheme - - // Paths is a list of paths to the directories or files containing CRDs - Paths []string - - // CRDs is a list of CRDs to install - CRDs []*apiextensionsv1.CustomResourceDefinition - - // ErrorIfPathMissing will cause an error if a Path does not exist - ErrorIfPathMissing bool - - // MaxTime is the max time to wait - MaxTime time.Duration - - // PollInterval is the interval to check - PollInterval time.Duration - - // CleanUpAfterUse will cause the CRDs listed for installation to be - // uninstalled when terminating the test environment. - // Defaults to false. - CleanUpAfterUse bool - - // WebhookOptions contains the conversion webhook information to install - // on the CRDs. This field is usually inherited by the EnvTest options. - // - // If you're passing this field manually, you need to make sure that - // the CA information and host port is filled in properly. - WebhookOptions WebhookInstallOptions -} - -const defaultPollInterval = 100 * time.Millisecond -const defaultMaxWait = 10 * time.Second - -// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory. -func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]*apiextensionsv1.CustomResourceDefinition, error) { - defaultCRDOptions(&options) - - // Read the CRD yamls into options.CRDs - if err := readCRDFiles(&options); err != nil { - return nil, fmt.Errorf("unable to read CRD files: %w", err) - } - - if err := modifyConversionWebhooks(options.CRDs, options.Scheme, options.WebhookOptions); err != nil { - return nil, err - } - - // Create the CRDs in the apiserver - if err := CreateCRDs(config, options.CRDs); err != nil { - return options.CRDs, fmt.Errorf("unable to create CRD instances: %w", err) - } - - // Wait for the CRDs to appear as Resources in the apiserver - if err := WaitForCRDs(config, options.CRDs, options); err != nil { - return options.CRDs, fmt.Errorf("something went wrong waiting for CRDs to appear as API resources: %w", err) - } - - return options.CRDs, nil -} - -// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs. -func readCRDFiles(options *CRDInstallOptions) error { - if len(options.Paths) > 0 { - crdList, err := renderCRDs(options) - if err != nil { - return err - } - - options.CRDs = append(options.CRDs, crdList...) - } - return nil -} - -// defaultCRDOptions sets the default values for CRDs. -func defaultCRDOptions(o *CRDInstallOptions) { - if o.Scheme == nil { - o.Scheme = scheme.Scheme - } - if o.MaxTime == 0 { - o.MaxTime = defaultMaxWait - } - if o.PollInterval == 0 { - o.PollInterval = defaultPollInterval - } -} - -// WaitForCRDs waits for the CRDs to appear in discovery. -func WaitForCRDs(config *rest.Config, crds []*apiextensionsv1.CustomResourceDefinition, options CRDInstallOptions) error { - // Add each CRD to a map of GroupVersion to Resource - waitingFor := map[schema.GroupVersion]*sets.String{} - for _, crd := range crds { - gvs := []schema.GroupVersion{} - for _, version := range crd.Spec.Versions { - if version.Served { - gvs = append(gvs, schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name}) - } - } - - for _, gv := range gvs { - log.V(1).Info("adding API in waitlist", "GV", gv) - if _, found := waitingFor[gv]; !found { - // Initialize the set - waitingFor[gv] = &sets.String{} - } - // Add the Resource - waitingFor[gv].Insert(crd.Spec.Names.Plural) - } - } - - // Poll until all resources are found in discovery - p := &poller{config: config, waitingFor: waitingFor} - return wait.PollImmediate(options.PollInterval, options.MaxTime, p.poll) -} - -// poller checks if all the resources have been found in discovery, and returns false if not. -type poller struct { - // config is used to get discovery - config *rest.Config - - // waitingFor is the map of resources keyed by group version that have not yet been found in discovery - waitingFor map[schema.GroupVersion]*sets.String -} - -// poll checks if all the resources have been found in discovery, and returns false if not. -func (p *poller) poll() (done bool, err error) { - // Create a new clientset to avoid any client caching of discovery - cs, err := clientset.NewForConfig(p.config) - if err != nil { - return false, err - } - - allFound := true - for gv, resources := range p.waitingFor { - // All resources found, do nothing - if resources.Len() == 0 { - delete(p.waitingFor, gv) - continue - } - - // Get the Resources for this GroupVersion - // TODO: Maybe the controller-runtime client should be able to do this... - resourceList, err := cs.Discovery().ServerResourcesForGroupVersion(gv.Group + "/" + gv.Version) - if err != nil { - return false, nil //nolint:nilerr - } - - // Remove each found resource from the resources set that we are waiting for - for _, resource := range resourceList.APIResources { - resources.Delete(resource.Name) - } - - // Still waiting on some resources in this group version - if resources.Len() != 0 { - allFound = false - } - } - return allFound, nil -} - -// UninstallCRDs uninstalls a collection of CRDs by reading the crd yaml files from a directory. -func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error { - // Read the CRD yamls into options.CRDs - if err := readCRDFiles(&options); err != nil { - return err - } - - // Delete the CRDs from the apiserver - cs, err := client.New(config, client.Options{}) - if err != nil { - return err - } - - // Uninstall each CRD - for _, crd := range options.CRDs { - crd := crd - log.V(1).Info("uninstalling CRD", "crd", crd.GetName()) - if err := cs.Delete(context.TODO(), crd); err != nil { - // If CRD is not found, we can consider success - if !apierrors.IsNotFound(err) { - return err - } - } - } - - return nil -} - -// CreateCRDs creates the CRDs. -func CreateCRDs(config *rest.Config, crds []*apiextensionsv1.CustomResourceDefinition) error { - cs, err := client.New(config, client.Options{}) - if err != nil { - return fmt.Errorf("unable to create client: %w", err) - } - - // Create each CRD - for _, crd := range crds { - crd := crd - log.V(1).Info("installing CRD", "crd", crd.GetName()) - existingCrd := crd.DeepCopy() - err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd) - switch { - case apierrors.IsNotFound(err): - if err := cs.Create(context.TODO(), crd); err != nil { - return fmt.Errorf("unable to create CRD %q: %w", crd.GetName(), err) - } - case err != nil: - return fmt.Errorf("unable to get CRD %q to check if it exists: %w", crd.GetName(), err) - default: - log.V(1).Info("CRD already exists, updating", "crd", crd.GetName()) - if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { - if err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd); err != nil { - return err - } - crd.SetResourceVersion(existingCrd.GetResourceVersion()) - return cs.Update(context.TODO(), crd) - }); err != nil { - return err - } - } - } - return nil -} - -// renderCRDs iterate through options.Paths and extract all CRD files. -func renderCRDs(options *CRDInstallOptions) ([]*apiextensionsv1.CustomResourceDefinition, error) { - type GVKN struct { - GVK schema.GroupVersionKind - Name string - } - - crds := map[GVKN]*apiextensionsv1.CustomResourceDefinition{} - - for _, path := range options.Paths { - var ( - err error - info os.FileInfo - files []string - filePath = path - ) - - // Return the error if ErrorIfPathMissing exists - if info, err = os.Stat(path); os.IsNotExist(err) { - if options.ErrorIfPathMissing { - return nil, err - } - continue - } - - if !info.IsDir() { - filePath, files = filepath.Dir(path), []string{info.Name()} - } else { - entries, err := os.ReadDir(path) - if err != nil { - return nil, err - } - for _, e := range entries { - files = append(files, e.Name()) - } - } - - log.V(1).Info("reading CRDs from path", "path", path) - crdList, err := readCRDs(filePath, files) - if err != nil { - return nil, err - } - - for i, crd := range crdList { - gvkn := GVKN{GVK: crd.GroupVersionKind(), Name: crd.GetName()} - if _, found := crds[gvkn]; found { - // Currently, we only print a log when there are duplicates. We may want to error out if that makes more sense. - log.Info("there are more than one CRD definitions with the same ", "GVKN", gvkn) - } - // We always use the CRD definition that we found last. - crds[gvkn] = crdList[i] - } - } - - // Converting map to a list to return - res := []*apiextensionsv1.CustomResourceDefinition{} - for _, obj := range crds { - res = append(res, obj) - } - return res, nil -} - -// modifyConversionWebhooks takes all the registered CustomResourceDefinitions and applies modifications -// to conditionally enable webhooks if the type is registered within the scheme. -func modifyConversionWebhooks(crds []*apiextensionsv1.CustomResourceDefinition, scheme *runtime.Scheme, webhookOptions WebhookInstallOptions) error { - if len(webhookOptions.LocalServingCAData) == 0 { - return nil - } - - // Determine all registered convertible types. - convertibles := map[schema.GroupKind]struct{}{} - for gvk := range scheme.AllKnownTypes() { - obj, err := scheme.New(gvk) - if err != nil { - return err - } - if ok, err := conversion.IsConvertible(scheme, obj); ok && err == nil { - convertibles[gvk.GroupKind()] = struct{}{} - } - } - - // generate host port. - hostPort, err := webhookOptions.generateHostPort() - if err != nil { - return err - } - url := pointer.StringPtr(fmt.Sprintf("https://%s/convert", hostPort)) - - for i := range crds { - // Continue if we're preserving unknown fields. - if crds[i].Spec.PreserveUnknownFields { - continue - } - // Continue if the GroupKind isn't registered as being convertible. - if _, ok := convertibles[schema.GroupKind{ - Group: crds[i].Spec.Group, - Kind: crds[i].Spec.Names.Kind, - }]; !ok { - continue - } - if crds[i].Spec.Conversion == nil { - crds[i].Spec.Conversion = &apiextensionsv1.CustomResourceConversion{ - Webhook: &apiextensionsv1.WebhookConversion{}, - } - } - crds[i].Spec.Conversion.Strategy = apiextensionsv1.WebhookConverter - crds[i].Spec.Conversion.Webhook.ConversionReviewVersions = []string{"v1", "v1beta1"} - crds[i].Spec.Conversion.Webhook.ClientConfig = &apiextensionsv1.WebhookClientConfig{ - Service: nil, - URL: url, - CABundle: webhookOptions.LocalServingCAData, - } - } - - return nil -} - -// readCRDs reads the CRDs from files and Unmarshals them into structs. -func readCRDs(basePath string, files []string) ([]*apiextensionsv1.CustomResourceDefinition, error) { - var crds []*apiextensionsv1.CustomResourceDefinition - - // White list the file extensions that may contain CRDs - crdExts := sets.NewString(".json", ".yaml", ".yml") - - for _, file := range files { - // Only parse allowlisted file types - if !crdExts.Has(filepath.Ext(file)) { - continue - } - - // Unmarshal CRDs from file into structs - docs, err := readDocuments(filepath.Join(basePath, file)) - if err != nil { - return nil, err - } - - for _, doc := range docs { - crd := &apiextensionsv1.CustomResourceDefinition{} - if err = yaml.Unmarshal(doc, crd); err != nil { - return nil, err - } - - if crd.Kind != "CustomResourceDefinition" || crd.Spec.Names.Kind == "" || crd.Spec.Group == "" { - continue - } - crds = append(crds, crd) - } - - log.V(1).Info("read CRDs from file", "file", file) - } - return crds, nil -} - -// readDocuments reads documents from file. -func readDocuments(fp string) ([][]byte, error) { - b, err := os.ReadFile(fp) - if err != nil { - return nil, err - } - - docs := [][]byte{} - reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(b))) - for { - // Read document - doc, err := reader.Read() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - - return nil, err - } - - docs = append(docs, doc) - } - - return docs, nil -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go deleted file mode 100644 index 412e794cc..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2017 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 envtest provides libraries for integration testing by starting a local control plane -// -// Control plane binaries (etcd and kube-apiserver) are loaded by default from -// /usr/local/kubebuilder/bin. This can be overridden by setting the -// KUBEBUILDER_ASSETS environment variable, or by directly creating a -// ControlPlane for the Environment to use. -// -// Environment can also be configured to work with an existing cluster, and -// simply load CRDs and provide client configuration. -package envtest diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go deleted file mode 100644 index d3b52017d..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2021 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 envtest - -import ( - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/client-go/kubernetes/scheme" -) - -var ( - crdScheme = scheme.Scheme -) - -// init is required to correctly initialize the crdScheme package variable. -func init() { - _ = apiextensionsv1.AddToScheme(crdScheme) -} - -// mergePaths merges two string slices containing paths. -// This function makes no guarantees about order of the merged slice. -func mergePaths(s1, s2 []string) []string { - m := make(map[string]struct{}) - for _, s := range s1 { - m[s] = struct{}{} - } - for _, s := range s2 { - m[s] = struct{}{} - } - merged := make([]string, len(m)) - i := 0 - for key := range m { - merged[i] = key - i++ - } - return merged -} - -// mergeCRDs merges two CRD slices using their names. -// This function makes no guarantees about order of the merged slice. -func mergeCRDs(s1, s2 []*apiextensionsv1.CustomResourceDefinition) []*apiextensionsv1.CustomResourceDefinition { - m := make(map[string]*apiextensionsv1.CustomResourceDefinition) - for _, obj := range s1 { - m[obj.GetName()] = obj - } - for _, obj := range s2 { - m[obj.GetName()] = obj - } - merged := make([]*apiextensionsv1.CustomResourceDefinition, len(m)) - i := 0 - for _, obj := range m { - merged[i] = obj.DeepCopy() - i++ - } - return merged -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/ginkgo.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/ginkgo.go deleted file mode 100644 index d835dc772..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/ginkgo.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2016 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 printer contains setup for a friendlier Ginkgo printer that's easier -// to parse by test automation. -package printer - -import ( - "fmt" - - "github.com/onsi/ginkgo" - "github.com/onsi/ginkgo/config" - "github.com/onsi/ginkgo/types" -) - -var _ ginkgo.Reporter = NewlineReporter{} - -// NewlineReporter is Reporter that Prints a newline after the default Reporter output so that the results -// are correctly parsed by test automation. -// See issue https://github.com/jstemmer/go-junit-report/issues/31 -type NewlineReporter struct{} - -// SpecSuiteWillBegin implements ginkgo.Reporter. -func (NewlineReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { -} - -// BeforeSuiteDidRun implements ginkgo.Reporter. -func (NewlineReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {} - -// AfterSuiteDidRun implements ginkgo.Reporter. -func (NewlineReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {} - -// SpecWillRun implements ginkgo.Reporter. -func (NewlineReporter) SpecWillRun(specSummary *types.SpecSummary) {} - -// SpecDidComplete implements ginkgo.Reporter. -func (NewlineReporter) SpecDidComplete(specSummary *types.SpecSummary) {} - -// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:". -func (NewlineReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { fmt.Printf("\n") } diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/prow.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/prow.go deleted file mode 100644 index 2f4009aa0..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/prow.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright 2020 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 printer - -import ( - "fmt" - "os" - "path/filepath" - "sync" - - "github.com/onsi/ginkgo" - "github.com/onsi/ginkgo/config" - "github.com/onsi/ginkgo/reporters" - "github.com/onsi/ginkgo/types" - - "k8s.io/apimachinery/pkg/util/sets" -) - -var ( - allRegisteredSuites = sets.String{} - allRegisteredSuitesLock = &sync.Mutex{} -) - -type prowReporter struct { - junitReporter *reporters.JUnitReporter -} - -// NewProwReporter returns a prowReporter that will write out junit if running in Prow and do -// nothing otherwise. -// WARNING: It seems this does not always properly fail the test runs when there are failures, -// see https://github.com/onsi/ginkgo/issues/706 -// When using this you must make sure to grep for failures in your junit xmls and fail the run -// if there are any. -func NewProwReporter(suiteName string) ginkgo.Reporter { - allRegisteredSuitesLock.Lock() - if allRegisteredSuites.Has(suiteName) { - panic(fmt.Sprintf("Suite named %q registered more than once", suiteName)) - } - allRegisteredSuites.Insert(suiteName) - allRegisteredSuitesLock.Unlock() - - if os.Getenv("CI") == "" { - return &prowReporter{} - } - artifactsDir := os.Getenv("ARTIFACTS") - if artifactsDir == "" { - return &prowReporter{} - } - - path := filepath.Join(artifactsDir, fmt.Sprintf("junit_%s_%d.xml", suiteName, config.GinkgoConfig.ParallelNode)) - return &prowReporter{ - junitReporter: reporters.NewJUnitReporter(path), - } -} - -func (pr *prowReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { - if pr.junitReporter != nil { - pr.junitReporter.SpecSuiteWillBegin(config, summary) - } -} - -// BeforeSuiteDidRun implements ginkgo.Reporter. -func (pr *prowReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { - if pr.junitReporter != nil { - pr.junitReporter.BeforeSuiteDidRun(setupSummary) - } -} - -// AfterSuiteDidRun implements ginkgo.Reporter. -func (pr *prowReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { - if pr.junitReporter != nil { - pr.junitReporter.AfterSuiteDidRun(setupSummary) - } -} - -// SpecWillRun implements ginkgo.Reporter. -func (pr *prowReporter) SpecWillRun(specSummary *types.SpecSummary) { - if pr.junitReporter != nil { - pr.junitReporter.SpecWillRun(specSummary) - } -} - -// SpecDidComplete implements ginkgo.Reporter. -func (pr *prowReporter) SpecDidComplete(specSummary *types.SpecSummary) { - if pr.junitReporter != nil { - pr.junitReporter.SpecDidComplete(specSummary) - } -} - -// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:". -func (pr *prowReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { - if pr.junitReporter != nil { - pr.junitReporter.SpecSuiteDidEnd(summary) - } -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go deleted file mode 100644 index f9e0bb8ab..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go +++ /dev/null @@ -1,374 +0,0 @@ -/* -Copyright 2016 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 envtest - -import ( - "fmt" - "os" - "strings" - "time" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - - "sigs.k8s.io/controller-runtime/pkg/client/config" - logf "sigs.k8s.io/controller-runtime/pkg/internal/log" - "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane" - "sigs.k8s.io/controller-runtime/pkg/internal/testing/process" -) - -var log = logf.RuntimeLog.WithName("test-env") - -/* -It's possible to override some defaults, by setting the following environment variables: -* USE_EXISTING_CLUSTER (boolean): if set to true, envtest will use an existing cluster -* TEST_ASSET_KUBE_APISERVER (string): path to the api-server binary to use -* TEST_ASSET_ETCD (string): path to the etcd binary to use -* TEST_ASSET_KUBECTL (string): path to the kubectl binary to use -* KUBEBUILDER_ASSETS (string): directory containing the binaries to use (api-server, etcd and kubectl). Defaults to /usr/local/kubebuilder/bin. -* KUBEBUILDER_CONTROLPLANE_START_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s. -* KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s. -* KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT (boolean): if set to true, the control plane's stdout and stderr are attached to os.Stdout and os.Stderr -*/ -const ( - envUseExistingCluster = "USE_EXISTING_CLUSTER" - envStartTimeout = "KUBEBUILDER_CONTROLPLANE_START_TIMEOUT" - envStopTimeout = "KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT" - envAttachOutput = "KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT" - StartTimeout = 60 - StopTimeout = 60 - - defaultKubebuilderControlPlaneStartTimeout = 20 * time.Second - defaultKubebuilderControlPlaneStopTimeout = 20 * time.Second -) - -// internal types we expose as part of our public API. -type ( - // ControlPlane is the re-exported ControlPlane type from the internal testing package. - ControlPlane = controlplane.ControlPlane - - // APIServer is the re-exported APIServer from the internal testing package. - APIServer = controlplane.APIServer - - // Etcd is the re-exported Etcd from the internal testing package. - Etcd = controlplane.Etcd - - // User represents a Kubernetes user to provision for auth purposes. - User = controlplane.User - - // AuthenticatedUser represets a Kubernetes user that's been provisioned. - AuthenticatedUser = controlplane.AuthenticatedUser - - // ListenAddr indicates the address and port that the API server should listen on. - ListenAddr = process.ListenAddr - - // SecureServing contains details describing how the API server should serve - // its secure endpoint. - SecureServing = controlplane.SecureServing - - // Authn is an authentication method that can be used with the control plane to - // provision users. - Authn = controlplane.Authn - - // Arguments allows configuring a process's flags. - Arguments = process.Arguments - - // Arg is a single flag with one or more values. - Arg = process.Arg -) - -var ( - // EmptyArguments constructs a new set of flags with nothing set. - // - // This is mostly useful for testing helper methods -- you'll want to call - // Configure on the APIServer (or etcd) to configure their arguments. - EmptyArguments = process.EmptyArguments -) - -// Environment creates a Kubernetes test environment that will start / stop the Kubernetes control plane and -// install extension APIs. -type Environment struct { - // ControlPlane is the ControlPlane including the apiserver and etcd - ControlPlane controlplane.ControlPlane - - // Scheme is used to determine if conversion webhooks should be enabled - // for a particular CRD / object. - // - // Conversion webhooks are going to be enabled if an object in the scheme - // implements Hub and Spoke conversions. - // - // If nil, scheme.Scheme is used. - Scheme *runtime.Scheme - - // Config can be used to talk to the apiserver. It's automatically - // populated if not set using the standard controller-runtime config - // loading. - Config *rest.Config - - // CRDInstallOptions are the options for installing CRDs. - CRDInstallOptions CRDInstallOptions - - // WebhookInstallOptions are the options for installing webhooks. - WebhookInstallOptions WebhookInstallOptions - - // ErrorIfCRDPathMissing provides an interface for the underlying - // CRDInstallOptions.ErrorIfPathMissing. It prevents silent failures - // for missing CRD paths. - ErrorIfCRDPathMissing bool - - // CRDs is a list of CRDs to install. - // If both this field and CRDs field in CRDInstallOptions are specified, the - // values are merged. - CRDs []*apiextensionsv1.CustomResourceDefinition - - // CRDDirectoryPaths is a list of paths containing CRD yaml or json configs. - // If both this field and Paths field in CRDInstallOptions are specified, the - // values are merged. - CRDDirectoryPaths []string - - // BinaryAssetsDirectory is the path where the binaries required for the envtest are - // located in the local environment. This field can be overridden by setting KUBEBUILDER_ASSETS. - BinaryAssetsDirectory string - - // UseExistingCluster indicates that this environments should use an - // existing kubeconfig, instead of trying to stand up a new control plane. - // This is useful in cases that need aggregated API servers and the like. - UseExistingCluster *bool - - // ControlPlaneStartTimeout is the maximum duration each controlplane component - // may take to start. It defaults to the KUBEBUILDER_CONTROLPLANE_START_TIMEOUT - // environment variable or 20 seconds if unspecified - ControlPlaneStartTimeout time.Duration - - // ControlPlaneStopTimeout is the maximum duration each controlplane component - // may take to stop. It defaults to the KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT - // environment variable or 20 seconds if unspecified - ControlPlaneStopTimeout time.Duration - - // KubeAPIServerFlags is the set of flags passed while starting the api server. - // - // Deprecated: use ControlPlane.GetAPIServer().Configure() instead. - KubeAPIServerFlags []string - - // AttachControlPlaneOutput indicates if control plane output will be attached to os.Stdout and os.Stderr. - // Enable this to get more visibility of the testing control plane. - // It respect KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT environment variable. - AttachControlPlaneOutput bool -} - -// Stop stops a running server. -// Previously installed CRDs, as listed in CRDInstallOptions.CRDs, will be uninstalled -// if CRDInstallOptions.CleanUpAfterUse are set to true. -func (te *Environment) Stop() error { - if te.CRDInstallOptions.CleanUpAfterUse { - if err := UninstallCRDs(te.Config, te.CRDInstallOptions); err != nil { - return err - } - } - - if err := te.WebhookInstallOptions.Cleanup(); err != nil { - return err - } - - if te.useExistingCluster() { - return nil - } - - return te.ControlPlane.Stop() -} - -// Start starts a local Kubernetes server and updates te.ApiserverPort with the port it is listening on. -func (te *Environment) Start() (*rest.Config, error) { - if te.useExistingCluster() { - log.V(1).Info("using existing cluster") - if te.Config == nil { - // we want to allow people to pass in their own config, so - // only load a config if it hasn't already been set. - log.V(1).Info("automatically acquiring client configuration") - - var err error - te.Config, err = config.GetConfig() - if err != nil { - return nil, fmt.Errorf("unable to get configuration for existing cluster: %w", err) - } - } - } else { - apiServer := te.ControlPlane.GetAPIServer() - if len(apiServer.Args) == 0 { //nolint:staticcheck - // pass these through separately from above in case something like - // AddUser defaults APIServer. - // - // TODO(directxman12): if/when we feel like making a bigger - // breaking change here, just make APIServer and Etcd non-pointers - // in ControlPlane. - - // NB(directxman12): we still pass these in so that things work if the - // user manually specifies them, but in most cases we expect them to - // be nil so that we use the new .Configure() logic. - apiServer.Args = te.KubeAPIServerFlags //nolint:staticcheck - } - if te.ControlPlane.Etcd == nil { - te.ControlPlane.Etcd = &controlplane.Etcd{} - } - - if os.Getenv(envAttachOutput) == "true" { - te.AttachControlPlaneOutput = true - } - if apiServer.Out == nil && te.AttachControlPlaneOutput { - apiServer.Out = os.Stdout - } - if apiServer.Err == nil && te.AttachControlPlaneOutput { - apiServer.Err = os.Stderr - } - if te.ControlPlane.Etcd.Out == nil && te.AttachControlPlaneOutput { - te.ControlPlane.Etcd.Out = os.Stdout - } - if te.ControlPlane.Etcd.Err == nil && te.AttachControlPlaneOutput { - te.ControlPlane.Etcd.Err = os.Stderr - } - - apiServer.Path = process.BinPathFinder("kube-apiserver", te.BinaryAssetsDirectory) - te.ControlPlane.Etcd.Path = process.BinPathFinder("etcd", te.BinaryAssetsDirectory) - te.ControlPlane.KubectlPath = process.BinPathFinder("kubectl", te.BinaryAssetsDirectory) - - if err := te.defaultTimeouts(); err != nil { - return nil, fmt.Errorf("failed to default controlplane timeouts: %w", err) - } - te.ControlPlane.Etcd.StartTimeout = te.ControlPlaneStartTimeout - te.ControlPlane.Etcd.StopTimeout = te.ControlPlaneStopTimeout - apiServer.StartTimeout = te.ControlPlaneStartTimeout - apiServer.StopTimeout = te.ControlPlaneStopTimeout - - log.V(1).Info("starting control plane") - if err := te.startControlPlane(); err != nil { - return nil, fmt.Errorf("unable to start control plane itself: %w", err) - } - - // Create the *rest.Config for creating new clients - baseConfig := &rest.Config{ - // gotta go fast during tests -- we don't really care about overwhelming our test API server - QPS: 1000.0, - Burst: 2000.0, - } - - adminInfo := User{Name: "admin", Groups: []string{"system:masters"}} - adminUser, err := te.ControlPlane.AddUser(adminInfo, baseConfig) - if err != nil { - return te.Config, fmt.Errorf("unable to provision admin user: %w", err) - } - te.Config = adminUser.Config() - } - - // Set the default scheme if nil. - if te.Scheme == nil { - te.Scheme = scheme.Scheme - } - - // Call PrepWithoutInstalling to setup certificates first - // and have them available to patch CRD conversion webhook as well. - if err := te.WebhookInstallOptions.PrepWithoutInstalling(); err != nil { - return nil, err - } - - log.V(1).Info("installing CRDs") - te.CRDInstallOptions.CRDs = mergeCRDs(te.CRDInstallOptions.CRDs, te.CRDs) - te.CRDInstallOptions.Paths = mergePaths(te.CRDInstallOptions.Paths, te.CRDDirectoryPaths) - te.CRDInstallOptions.ErrorIfPathMissing = te.ErrorIfCRDPathMissing - te.CRDInstallOptions.WebhookOptions = te.WebhookInstallOptions - crds, err := InstallCRDs(te.Config, te.CRDInstallOptions) - if err != nil { - return te.Config, fmt.Errorf("unable to install CRDs onto control plane: %w", err) - } - te.CRDs = crds - - log.V(1).Info("installing webhooks") - if err := te.WebhookInstallOptions.Install(te.Config); err != nil { - return nil, fmt.Errorf("unable to install webhooks onto control plane: %w", err) - } - return te.Config, nil -} - -// AddUser provisions a new user for connecting to this Environment. The user will -// have the specified name & belong to the specified groups. -// -// If you specify a "base" config, the returned REST Config will contain those -// settings as well as any required by the authentication method. You can use -// this to easily specify options like QPS. -// -// This is effectively a convinience alias for ControlPlane.AddUser -- see that -// for more low-level details. -func (te *Environment) AddUser(user User, baseConfig *rest.Config) (*AuthenticatedUser, error) { - return te.ControlPlane.AddUser(user, baseConfig) -} - -func (te *Environment) startControlPlane() error { - numTries, maxRetries := 0, 5 - var err error - for ; numTries < maxRetries; numTries++ { - // Start the control plane - retry if it fails - err = te.ControlPlane.Start() - if err == nil { - break - } - log.Error(err, "unable to start the controlplane", "tries", numTries) - } - if numTries == maxRetries { - return fmt.Errorf("failed to start the controlplane. retried %d times: %w", numTries, err) - } - return nil -} - -func (te *Environment) defaultTimeouts() error { - var err error - if te.ControlPlaneStartTimeout == 0 { - if envVal := os.Getenv(envStartTimeout); envVal != "" { - te.ControlPlaneStartTimeout, err = time.ParseDuration(envVal) - if err != nil { - return err - } - } else { - te.ControlPlaneStartTimeout = defaultKubebuilderControlPlaneStartTimeout - } - } - - if te.ControlPlaneStopTimeout == 0 { - if envVal := os.Getenv(envStopTimeout); envVal != "" { - te.ControlPlaneStopTimeout, err = time.ParseDuration(envVal) - if err != nil { - return err - } - } else { - te.ControlPlaneStopTimeout = defaultKubebuilderControlPlaneStopTimeout - } - } - return nil -} - -func (te *Environment) useExistingCluster() bool { - if te.UseExistingCluster == nil { - return strings.ToLower(os.Getenv(envUseExistingCluster)) == "true" - } - return *te.UseExistingCluster -} - -// DefaultKubeAPIServerFlags exposes the default args for the APIServer so that -// you can use those to append your own additional arguments. -// -// Deprecated: use APIServer.Configure() instead. -var DefaultKubeAPIServerFlags = controlplane.APIServerDefaultArgs //nolint:staticcheck diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go deleted file mode 100644 index 9b763b6c2..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go +++ /dev/null @@ -1,433 +0,0 @@ -/* -Copyright 2019 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 envtest - -import ( - "context" - "fmt" - "net" - "os" - "path/filepath" - "time" - - admissionv1 "k8s.io/api/admissionregistration/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "sigs.k8s.io/yaml" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr" - "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs" -) - -// WebhookInstallOptions are the options for installing mutating or validating webhooks. -type WebhookInstallOptions struct { - // Paths is a list of paths to the directories or files containing the mutating or validating webhooks yaml or json configs. - Paths []string - - // MutatingWebhooks is a list of MutatingWebhookConfigurations to install - MutatingWebhooks []*admissionv1.MutatingWebhookConfiguration - - // ValidatingWebhooks is a list of ValidatingWebhookConfigurations to install - ValidatingWebhooks []*admissionv1.ValidatingWebhookConfiguration - - // IgnoreErrorIfPathMissing will ignore an error if a DirectoryPath does not exist when set to true - IgnoreErrorIfPathMissing bool - - // LocalServingHost is the host for serving webhooks on. - // it will be automatically populated - LocalServingHost string - - // LocalServingPort is the allocated port for serving webhooks on. - // it will be automatically populated by a random available local port - LocalServingPort int - - // LocalServingCertDir is the allocated directory for serving certificates. - // it will be automatically populated by the local temp dir - LocalServingCertDir string - - // CAData is the CA that can be used to trust the serving certificates in LocalServingCertDir. - LocalServingCAData []byte - - // LocalServingHostExternalName is the hostname to use to reach the webhook server. - LocalServingHostExternalName string - - // MaxTime is the max time to wait - MaxTime time.Duration - - // PollInterval is the interval to check - PollInterval time.Duration -} - -// ModifyWebhookDefinitions modifies webhook definitions by: -// - applying CABundle based on the provided tinyca -// - if webhook client config uses service spec, it's removed and replaced with direct url. -func (o *WebhookInstallOptions) ModifyWebhookDefinitions() error { - caData := o.LocalServingCAData - - // generate host port. - hostPort, err := o.generateHostPort() - if err != nil { - return err - } - - for i := range o.MutatingWebhooks { - for j := range o.MutatingWebhooks[i].Webhooks { - updateClientConfig(&o.MutatingWebhooks[i].Webhooks[j].ClientConfig, hostPort, caData) - } - } - - for i := range o.ValidatingWebhooks { - for j := range o.ValidatingWebhooks[i].Webhooks { - updateClientConfig(&o.ValidatingWebhooks[i].Webhooks[j].ClientConfig, hostPort, caData) - } - } - return nil -} - -func updateClientConfig(cc *admissionv1.WebhookClientConfig, hostPort string, caData []byte) { - cc.CABundle = caData - if cc.Service != nil && cc.Service.Path != nil { - url := fmt.Sprintf("https://%s/%s", hostPort, *cc.Service.Path) - cc.URL = &url - cc.Service = nil - } -} - -func (o *WebhookInstallOptions) generateHostPort() (string, error) { - if o.LocalServingPort == 0 { - port, host, err := addr.Suggest(o.LocalServingHost) - if err != nil { - return "", fmt.Errorf("unable to grab random port for serving webhooks on: %w", err) - } - o.LocalServingPort = port - o.LocalServingHost = host - } - host := o.LocalServingHostExternalName - if host == "" { - host = o.LocalServingHost - } - return net.JoinHostPort(host, fmt.Sprintf("%d", o.LocalServingPort)), nil -} - -// PrepWithoutInstalling does the setup parts of Install (populating host-port, -// setting up CAs, etc), without actually truing to do anything with webhook -// definitions. This is largely useful for internal testing of -// controller-runtime, where we need a random host-port & caData for webhook -// tests, but may be useful in similar scenarios. -func (o *WebhookInstallOptions) PrepWithoutInstalling() error { - if err := o.setupCA(); err != nil { - return err - } - - if err := parseWebhook(o); err != nil { - return err - } - - return o.ModifyWebhookDefinitions() -} - -// Install installs specified webhooks to the API server. -func (o *WebhookInstallOptions) Install(config *rest.Config) error { - if len(o.LocalServingCAData) == 0 { - if err := o.PrepWithoutInstalling(); err != nil { - return err - } - } - - if err := createWebhooks(config, o.MutatingWebhooks, o.ValidatingWebhooks); err != nil { - return err - } - - return WaitForWebhooks(config, o.MutatingWebhooks, o.ValidatingWebhooks, *o) -} - -// Cleanup cleans up cert directories. -func (o *WebhookInstallOptions) Cleanup() error { - if o.LocalServingCertDir != "" { - return os.RemoveAll(o.LocalServingCertDir) - } - return nil -} - -// WaitForWebhooks waits for the Webhooks to be available through API server. -func WaitForWebhooks(config *rest.Config, - mutatingWebhooks []*admissionv1.MutatingWebhookConfiguration, - validatingWebhooks []*admissionv1.ValidatingWebhookConfiguration, - options WebhookInstallOptions) error { - waitingFor := map[schema.GroupVersionKind]*sets.String{} - - for _, hook := range mutatingWebhooks { - h := hook - gvk, err := apiutil.GVKForObject(h, scheme.Scheme) - if err != nil { - return fmt.Errorf("unable to get gvk for MutatingWebhookConfiguration %s: %w", hook.GetName(), err) - } - - if _, ok := waitingFor[gvk]; !ok { - waitingFor[gvk] = &sets.String{} - } - waitingFor[gvk].Insert(h.GetName()) - } - - for _, hook := range validatingWebhooks { - h := hook - gvk, err := apiutil.GVKForObject(h, scheme.Scheme) - if err != nil { - return fmt.Errorf("unable to get gvk for ValidatingWebhookConfiguration %s: %w", hook.GetName(), err) - } - - if _, ok := waitingFor[gvk]; !ok { - waitingFor[gvk] = &sets.String{} - } - waitingFor[gvk].Insert(hook.GetName()) - } - - // Poll until all resources are found in discovery - p := &webhookPoller{config: config, waitingFor: waitingFor} - return wait.PollImmediate(options.PollInterval, options.MaxTime, p.poll) -} - -// poller checks if all the resources have been found in discovery, and returns false if not. -type webhookPoller struct { - // config is used to get discovery - config *rest.Config - - // waitingFor is the map of resources keyed by group version that have not yet been found in discovery - waitingFor map[schema.GroupVersionKind]*sets.String -} - -// poll checks if all the resources have been found in discovery, and returns false if not. -func (p *webhookPoller) poll() (done bool, err error) { - // Create a new clientset to avoid any client caching of discovery - c, err := client.New(p.config, client.Options{}) - if err != nil { - return false, err - } - - allFound := true - for gvk, names := range p.waitingFor { - if names.Len() == 0 { - delete(p.waitingFor, gvk) - continue - } - for _, name := range names.List() { - var obj = &unstructured.Unstructured{} - obj.SetGroupVersionKind(gvk) - err := c.Get(context.Background(), client.ObjectKey{ - Namespace: "", - Name: name, - }, obj) - - if err == nil { - names.Delete(name) - } - - if apierrors.IsNotFound(err) { - allFound = false - } - if err != nil { - return false, err - } - } - } - return allFound, nil -} - -// setupCA creates CA for testing and writes them to disk. -func (o *WebhookInstallOptions) setupCA() error { - hookCA, err := certs.NewTinyCA() - if err != nil { - return fmt.Errorf("unable to set up webhook CA: %w", err) - } - - names := []string{"localhost", o.LocalServingHost, o.LocalServingHostExternalName} - hookCert, err := hookCA.NewServingCert(names...) - if err != nil { - return fmt.Errorf("unable to set up webhook serving certs: %w", err) - } - - localServingCertsDir, err := os.MkdirTemp("", "envtest-serving-certs-") - o.LocalServingCertDir = localServingCertsDir - if err != nil { - return fmt.Errorf("unable to create directory for webhook serving certs: %w", err) - } - - certData, keyData, err := hookCert.AsBytes() - if err != nil { - return fmt.Errorf("unable to marshal webhook serving certs: %w", err) - } - - if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.crt"), certData, 0640); err != nil { //nolint:gosec - return fmt.Errorf("unable to write webhook serving cert to disk: %w", err) - } - if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.key"), keyData, 0640); err != nil { //nolint:gosec - return fmt.Errorf("unable to write webhook serving key to disk: %w", err) - } - - o.LocalServingCAData = certData - return err -} - -func createWebhooks(config *rest.Config, mutHooks []*admissionv1.MutatingWebhookConfiguration, valHooks []*admissionv1.ValidatingWebhookConfiguration) error { - cs, err := client.New(config, client.Options{}) - if err != nil { - return err - } - - // Create each webhook - for _, hook := range mutHooks { - hook := hook - log.V(1).Info("installing mutating webhook", "webhook", hook.GetName()) - if err := ensureCreated(cs, hook); err != nil { - return err - } - } - for _, hook := range valHooks { - hook := hook - log.V(1).Info("installing validating webhook", "webhook", hook.GetName()) - if err := ensureCreated(cs, hook); err != nil { - return err - } - } - return nil -} - -// ensureCreated creates or update object if already exists in the cluster. -func ensureCreated(cs client.Client, obj client.Object) error { - existing := obj.DeepCopyObject().(client.Object) - err := cs.Get(context.Background(), client.ObjectKey{Name: obj.GetName()}, existing) - switch { - case apierrors.IsNotFound(err): - if err := cs.Create(context.Background(), obj); err != nil { - return err - } - case err != nil: - return err - default: - log.V(1).Info("Webhook configuration already exists, updating", "webhook", obj.GetName()) - obj.SetResourceVersion(existing.GetResourceVersion()) - if err := cs.Update(context.Background(), obj); err != nil { - return err - } - } - return nil -} - -// parseWebhook reads the directories or files of Webhooks in options.Paths and adds the Webhook structs to options. -func parseWebhook(options *WebhookInstallOptions) error { - if len(options.Paths) > 0 { - for _, path := range options.Paths { - _, err := os.Stat(path) - if options.IgnoreErrorIfPathMissing && os.IsNotExist(err) { - continue // skip this path - } - if !options.IgnoreErrorIfPathMissing && os.IsNotExist(err) { - return err // treat missing path as error - } - mutHooks, valHooks, err := readWebhooks(path) - if err != nil { - return err - } - options.MutatingWebhooks = append(options.MutatingWebhooks, mutHooks...) - options.ValidatingWebhooks = append(options.ValidatingWebhooks, valHooks...) - } - } - return nil -} - -// readWebhooks reads the Webhooks from files and Unmarshals them into structs -// returns slice of mutating and validating webhook configurations. -func readWebhooks(path string) ([]*admissionv1.MutatingWebhookConfiguration, []*admissionv1.ValidatingWebhookConfiguration, error) { - // Get the webhook files - var files []string - var err error - log.V(1).Info("reading Webhooks from path", "path", path) - info, err := os.Stat(path) - if err != nil { - return nil, nil, err - } - if !info.IsDir() { - path, files = filepath.Dir(path), []string{info.Name()} - } else { - entries, err := os.ReadDir(path) - if err != nil { - return nil, nil, err - } - for _, e := range entries { - files = append(files, e.Name()) - } - } - - // file extensions that may contain Webhooks - resourceExtensions := sets.NewString(".json", ".yaml", ".yml") - - var mutHooks []*admissionv1.MutatingWebhookConfiguration - var valHooks []*admissionv1.ValidatingWebhookConfiguration - for _, file := range files { - // Only parse allowlisted file types - if !resourceExtensions.Has(filepath.Ext(file)) { - continue - } - - // Unmarshal Webhooks from file into structs - docs, err := readDocuments(filepath.Join(path, file)) - if err != nil { - return nil, nil, err - } - - for _, doc := range docs { - var generic metav1.PartialObjectMetadata - if err = yaml.Unmarshal(doc, &generic); err != nil { - return nil, nil, err - } - - const ( - admissionregv1 = "admissionregistration.k8s.io/v1" - ) - switch { - case generic.Kind == "MutatingWebhookConfiguration": - if generic.APIVersion != admissionregv1 { - return nil, nil, fmt.Errorf("only v1 is supported right now for MutatingWebhookConfiguration (name: %s)", generic.Name) - } - hook := &admissionv1.MutatingWebhookConfiguration{} - if err := yaml.Unmarshal(doc, hook); err != nil { - return nil, nil, err - } - mutHooks = append(mutHooks, hook) - case generic.Kind == "ValidatingWebhookConfiguration": - if generic.APIVersion != admissionregv1 { - return nil, nil, fmt.Errorf("only v1 is supported right now for ValidatingWebhookConfiguration (name: %s)", generic.Name) - } - hook := &admissionv1.ValidatingWebhookConfiguration{} - if err := yaml.Unmarshal(doc, hook); err != nil { - return nil, nil, err - } - valHooks = append(valHooks, hook) - default: - continue - } - } - - log.V(1).Info("read webhooks from file", "file", file) - } - return mutHooks, valHooks, nil -}