11package bootstrap
22
33import (
4+ "context"
5+ "fmt"
46 "io/fs"
57 "path"
68 "time"
79
10+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
811 v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
12+ "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
13+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
14+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+ "k8s.io/apimachinery/pkg/runtime/schema"
16+ "k8s.io/apimachinery/pkg/util/wait"
917 "k8s.io/apimachinery/pkg/util/yaml"
18+ "k8s.io/client-go/discovery"
1019 "k8s.io/client-go/rest"
11- "sigs. k8s.io/controller-runtime/pkg/envtest "
20+ "k8s.io/client-go/util/retry "
1221)
1322
1423const (
@@ -18,7 +27,7 @@ const (
1827)
1928
2029// CRD installs the CRDs in the filesystem into the kube cluster configured by the rest config.
21- func CRD (restConfig * rest.Config , crdFS fs.ReadDirFS , dir string ) error {
30+ func CRD (ctx context. Context , restConfig * rest.Config , crdFS fs.ReadDirFS , dir string ) error {
2231 crds := make ([]* v1.CustomResourceDefinition , 0 )
2332
2433 crdFiles , err := crdFS .ReadDir (dir )
@@ -37,11 +46,87 @@ func CRD(restConfig *rest.Config, crdFS fs.ReadDirFS, dir string) error {
3746 crds = append (crds , & crd )
3847 }
3948
40- _ , err = envtest .InstallCRDs (restConfig , envtest.CRDInstallOptions {
41- CRDs : crds ,
42- MaxTime : maxCRDInstallTime ,
43- PollInterval : crdInstallPollInterval ,
44- CleanUpAfterUse : false ,
45- })
49+ if err := createCRDs (ctx , restConfig , crds ); err != nil {
50+ return err
51+ }
52+
53+ if err := waitForDiscovery (ctx , restConfig , crds ); err != nil {
54+ return err
55+ }
56+
4657 return err
4758}
59+
60+ // createCRDs creates (or updates) CRDs in the cluster
61+ func createCRDs (ctx context.Context , config * rest.Config , crds []* apiextensionsv1.CustomResourceDefinition ) error {
62+ c , err := clientset .NewForConfig (config )
63+ if err != nil {
64+ return err
65+ }
66+ crdClient := c .ApiextensionsV1 ().CustomResourceDefinitions ()
67+ for _ , crd := range crds {
68+ crd := crd
69+ _ , err = crdClient .Get (ctx , crd .GetName (), metav1.GetOptions {})
70+ if k8serrors .IsNotFound (err ) {
71+ if _ , err := crdClient .Create (ctx , crd , metav1.CreateOptions {}); err != nil {
72+ return fmt .Errorf ("unable to create CRD %q: %w" , crd .Name , err )
73+ }
74+ continue
75+ }
76+ if err != nil {
77+ return fmt .Errorf ("failed when fetching CRD %q: %w" , crd .Name , err )
78+ }
79+
80+ if err := retry .RetryOnConflict (retry .DefaultBackoff , func () error {
81+ got , err := crdClient .Get (ctx , crd .Name , metav1.GetOptions {})
82+ if err != nil {
83+ return err
84+ }
85+ crd .SetResourceVersion (got .GetResourceVersion ())
86+ _ , err = crdClient .Update (ctx , crd , metav1.UpdateOptions {})
87+ return err
88+ }); err != nil {
89+ return err
90+ }
91+ }
92+ return nil
93+ }
94+
95+ func waitForDiscovery (ctx context.Context , config * rest.Config , crds []* apiextensionsv1.CustomResourceDefinition ) error {
96+ gvrs := map [schema.GroupVersionResource ]struct {}{}
97+ for _ , crd := range crds {
98+ for _ , version := range crd .Spec .Versions {
99+ if ! version .Served {
100+ continue
101+ }
102+ gvrs [schema.GroupVersionResource {
103+ Group : crd .Spec .Group ,
104+ Version : version .Name ,
105+ Resource : crd .Spec .Names .Plural ,
106+ }] = struct {}{}
107+ }
108+ }
109+ discoveryClient , err := discovery .NewDiscoveryClientForConfig (config )
110+ if err != nil {
111+ return err
112+ }
113+
114+ return wait .PollUntilContextTimeout (ctx , crdInstallPollInterval , maxCRDInstallTime , true , func (ctx context.Context ) (done bool , err error ) {
115+ _ , serverGVRs , err := discoveryClient .ServerGroupsAndResources ()
116+ if err != nil {
117+ return false , nil
118+ }
119+
120+ for _ , gv := range serverGVRs {
121+ for _ , r := range gv .APIResources {
122+ delete (gvrs , schema.GroupVersionResource {
123+ Group : r .Group ,
124+ Version : r .Version ,
125+ Resource : r .Name ,
126+ })
127+ }
128+ }
129+
130+ return len (gvrs ) == 0 , nil
131+ })
132+ }
0 commit comments