Skip to content

Commit 29286ed

Browse files
committed
Add CRD to APIResourceSchema conversion from file
Signed-off-by: Karol Szwaj <karol.szwaj@gmail.com> On-behalf-of: @SAP karol.szwaj@sap.com
1 parent 800c89a commit 29286ed

1 file changed

Lines changed: 83 additions & 14 deletions

File tree

cli/pkg/crd2apiresourceschema/plugin/crd2apiresourceschema.go

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)