@@ -23,6 +23,7 @@ import (
2323 "io"
2424 "os"
2525 "path/filepath"
26+ "strings"
2627 "time"
2728
2829 "github.com/spf13/cobra"
@@ -49,6 +50,8 @@ type CRD2APIResourceSchemaOptions struct {
4950
5051 // GenerateInCluster indicates whether to generate the APIResourceSchema in-cluster.
5152 GenerateInCluster bool
53+ // File containing the CRD to convert to APIResourceSchema.
54+ File string
5255 // OutputDir is the directory where the APIResourceSchemas will be written.
5356 OutputDir string
5457}
@@ -67,6 +70,7 @@ func (b *CRD2APIResourceSchemaOptions) AddCmdFlags(cmd *cobra.Command) {
6770 b .Print .AddFlags (cmd )
6871
6972 cmd .Flags ().BoolVar (& b .GenerateInCluster , "generate-in-cluster" , b .GenerateInCluster , "Generate the APIResourceSchema in-cluster." )
73+ cmd .Flags ().StringVar (& b .File , "file" , b .File , "File with CRD to convert to APIResourceSchema" )
7074 cmd .Flags ().StringVar (& b .OutputDir , "output-dir" , b .OutputDir , "Directory where APIResourceSchemas will be written." )
7175}
7276
@@ -97,32 +101,36 @@ func (b *CRD2APIResourceSchemaOptions) Run(ctx context.Context) error {
97101 b .OutputDir = "."
98102 }
99103
100- crdGVR := apiextensionsv1 .SchemeGroupVersion .WithResource ("customresourcedefinitions" )
101- crdList , err := client .Resource (crdGVR ).List (ctx , metav1.ListOptions {})
102- if err != nil {
103- return fmt .Errorf ("failed to list CRDs: %w" , err )
104- }
105-
106- for _ , crd := range crdList .Items {
107- crdObj := & apiextensionsv1.CustomResourceDefinition {}
108- if err := runtime .DefaultUnstructuredConverter .FromUnstructured (crd .UnstructuredContent (), crdObj ); err != nil {
109- return fmt .Errorf ("failed to convert CRD: %w" , err )
104+ var crdList []* apiextensionsv1.CustomResourceDefinition
105+ if b .File != "" {
106+ fileList , err := b .readCRDsFromFile ()
107+ if err != nil {
108+ return fmt .Errorf ("failed to read CRDs from file: %w" , err )
110109 }
110+ crdList = fileList
111+ } else {
112+ clusterList , err := b .listCRDsFromCluster (ctx , client )
113+ if err != nil {
114+ return fmt .Errorf ("failed to list CRDs from cluster: %w" , err )
115+ }
116+ crdList = clusterList
117+ }
111118
119+ for _ , crdObj := range crdList {
112120 if crdObj .Spec .Group == "kube-bind.io" {
113- fmt .Fprintf (b .Options .ErrOut , "Skipping CRD %s: belongs to group kube-bind.io\n " , crdObj .Name )
121+ fmt .Fprintf (b .Options .ErrOut , "skipping CRD %s: belongs to group kube-bind.io\n " , crdObj .Name )
114122 continue
115123 }
116124
117125 prefix := fmt .Sprintf ("v%s-%s" , time .Now ().Format ("060102" ), string (version .Get ().GitCommit ))
118126 apiResourceSchema , err := helpers .CRDToAPIResourceSchema (crdObj , prefix )
119127 if err != nil {
120- fmt .Fprintf (b .Options .ErrOut , "Failed to convert CRD %s to APIResourceSchema: %v\n " , crdObj .Name , err )
128+ fmt .Fprintf (b .Options .ErrOut , "failed to convert CRD %s to APIResourceSchema: %v\n " , crdObj .Name , err )
121129 continue
122130 }
123131
124132 if apiResourceSchema == nil {
125- fmt .Fprintf (b .Options .ErrOut , "Skipping CRD %s: no schema found\n " , crdObj .Name )
133+ fmt .Fprintf (b .Options .ErrOut , "skipping CRD %s: no schema found\n " , crdObj .Name )
126134 continue
127135 }
128136
@@ -183,6 +191,67 @@ func writeObjectToYAML(outputDir string, apiResourceSchema *kubebindv1alpha2.API
183191 return fmt .Errorf ("failed to write APIResourceSchema to file %s: %w" , outputPath , err )
184192 }
185193
186- fmt .Fprintf (logger , "Wrote APIResourceSchema %s to %s\n " , apiResourceSchema .Name , outputPath )
194+ fmt .Fprintf (logger , "wrote APIResourceSchema %s to %s\n " , apiResourceSchema .Name , outputPath )
187195 return nil
188196}
197+
198+ func (b * CRD2APIResourceSchemaOptions ) readCRDsFromFile () ([]* apiextensionsv1.CustomResourceDefinition , error ) {
199+ data , err := os .ReadFile (b .File )
200+ if err != nil {
201+ return nil , fmt .Errorf ("failed to read file %s: %w" , b .File , err )
202+ }
203+
204+ scheme := runtime .NewScheme ()
205+ if err := apiextensionsv1 .AddToScheme (scheme ); err != nil {
206+ return nil , fmt .Errorf ("failed to register apiextensions v1 scheme: %w" , err )
207+ }
208+
209+ decoder := serializer .NewCodecFactory (scheme ).UniversalDeserializer ()
210+ var crdList []* apiextensionsv1.CustomResourceDefinition
211+
212+ objects := strings .Split (string (data ), "---" )
213+ for i , obj := range objects {
214+ obj = strings .TrimSpace (obj )
215+ if obj == "" {
216+ continue
217+ }
218+
219+ decodedObj , gvk , err := decoder .Decode ([]byte (obj ), nil , nil )
220+ if err != nil {
221+ fmt .Fprintf (b .Options .ErrOut , "warning: failed to decode object %d: %v\n " , i + 1 , err )
222+ continue
223+ }
224+
225+ if crd , ok := decodedObj .(* apiextensionsv1.CustomResourceDefinition ); ok {
226+ crdList = append (crdList , crd )
227+ fmt .Fprintf (b .Options .Out , "found CRD: %s\n " , crd .Name )
228+ } else {
229+ return nil , fmt .Errorf ("error: non-CRD object of type %s" , gvk .String ())
230+ }
231+ }
232+
233+ if len (crdList ) == 0 {
234+ return nil , fmt .Errorf ("no CustomResourceDefinition objects found in file %s" , b .File )
235+ }
236+
237+ return crdList , nil
238+ }
239+
240+ func (b * CRD2APIResourceSchemaOptions ) listCRDsFromCluster (ctx context.Context , client dynamic.Interface ) ([]* apiextensionsv1.CustomResourceDefinition , error ) {
241+ crdGVR := apiextensionsv1 .SchemeGroupVersion .WithResource ("customresourcedefinitions" )
242+ crdList , err := client .Resource (crdGVR ).List (ctx , metav1.ListOptions {})
243+ if err != nil {
244+ return nil , fmt .Errorf ("failed to list CRDs: %w" , err )
245+ }
246+
247+ var result []* apiextensionsv1.CustomResourceDefinition
248+ for _ , crd := range crdList .Items {
249+ crdObj := & apiextensionsv1.CustomResourceDefinition {}
250+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (crd .UnstructuredContent (), crdObj ); err != nil {
251+ return nil , fmt .Errorf ("failed to convert CRD: %w" , err )
252+ }
253+ result = append (result , crdObj )
254+ }
255+
256+ return result , nil
257+ }
0 commit comments