Skip to content

Commit d66c060

Browse files
authored
feat: support yaml stream format input for CRD generation (#73)
Signed-off-by: peefy <[email protected]>
1 parent d8316c0 commit d66c060

File tree

2 files changed

+88
-18
lines changed

2 files changed

+88
-18
lines changed

pkg/kube_resource/generator/generator.go

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
package generator
1616

1717
import (
18+
"bytes"
1819
"encoding/json"
1920
"errors"
2021
"fmt"
21-
"io/ioutil"
2222
"os"
2323
"path/filepath"
2424

@@ -57,7 +57,7 @@ func GetSpec(opts *GenOpts) (string, error) {
5757
if err != nil {
5858
return "", fmt.Errorf("could not locate spec: %s, err: %s", opts.Spec, err)
5959
}
60-
crdContent, err := ioutil.ReadFile(path)
60+
crdContent, err := os.ReadFile(path)
6161
if err != nil {
6262
return "", fmt.Errorf("could not load spec: %s, err: %s", opts.Spec, err)
6363
}
@@ -72,9 +72,12 @@ func GetSpec(opts *GenOpts) (string, error) {
7272
return "", fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
7373
}
7474
tmpSpecDir := os.TempDir()
75-
tmpFile, err := ioutil.TempFile(tmpSpecDir, "kcl-swagger-")
75+
tmpFile, err := os.CreateTemp(tmpSpecDir, "kcl-swagger-")
76+
if err != nil {
77+
return "", fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
78+
}
7679
// copy k8s.json to tmpDir
77-
if err := ioutil.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
80+
if err := os.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
7881
return "", fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
7982
}
8083
if _, err := tmpFile.Write(swaggerContent); err != nil {
@@ -84,6 +87,62 @@ func GetSpec(opts *GenOpts) (string, error) {
8487
return tmpFile.Name(), nil
8588
}
8689

90+
// GetSpecs retrieves specifications from the given GenOpts and returns a list of temporary file paths for the generated OpenAPI specs.
91+
// It returns an error if there is any issue in fetching and generating the specs.
92+
// Parameters:
93+
// - opts: a GenOpts struct that contains the options and parameters required for generating the specs
94+
// Returns:
95+
// - []string: a list of temporary file paths for the generated OpenAPI specs
96+
// - error: an error message if any error occurs.
97+
func GetSpecs(opts *GenOpts) ([]string, error) {
98+
var result []string
99+
// read crd content from file
100+
path, err := filepath.Abs(opts.Spec)
101+
if err != nil {
102+
return result, fmt.Errorf("could not locate spec: %s, err: %s", opts.Spec, err)
103+
}
104+
crdContent, err := os.ReadFile(path)
105+
if err != nil {
106+
return result, fmt.Errorf("could not load spec: %s, err: %s", opts.Spec, err)
107+
}
108+
contents := separateSubDocuments(crdContent)
109+
for _, content := range contents {
110+
// generate openapi spec from crd
111+
swagger, err := generate(string(content))
112+
if err != nil {
113+
return result, fmt.Errorf("could not generate swagger spec: %s, err: %s", opts.Spec, err)
114+
}
115+
// write openapi spec to tmp file, along with the referenced k8s.json
116+
swaggerContent, err := json.MarshalIndent(swagger, "", "")
117+
if err != nil {
118+
return result, fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
119+
}
120+
tmpSpecDir := os.TempDir()
121+
tmpFile, err := os.CreateTemp(tmpSpecDir, "kcl-swagger-")
122+
if err != nil {
123+
return result, fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
124+
}
125+
// copy k8s.json to tmpDir
126+
if err := os.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
127+
return result, fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
128+
}
129+
if _, err := tmpFile.Write(swaggerContent); err != nil {
130+
return result, fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
131+
}
132+
// Append the tmp openapi spec file path
133+
result = append(result, tmpFile.Name())
134+
}
135+
return result, nil
136+
}
137+
138+
func separateSubDocuments(data []byte) [][]byte {
139+
lineBreak := "\n"
140+
if bytes.Contains(data, []byte("\r\n---\r\n")) {
141+
lineBreak = "\r\n"
142+
}
143+
return bytes.Split(data, []byte(lineBreak+"---"+lineBreak))
144+
}
145+
87146
// generate swagger model based on crd
88147
func generate(crdYaml string) (*spec.Swagger, error) {
89148
crdObj, _, err := scheme.Codecs.UniversalDeserializer().

pkg/kube_resource/generator/generator_test.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,6 @@ import (
88
"k8s.io/client-go/kubernetes/scheme"
99
)
1010

11-
func TestGenerate(t *testing.T) {
12-
swagger, err := generate(workload)
13-
if err != nil {
14-
t.Fatalf("error: %v", err)
15-
}
16-
data, err := json.MarshalIndent(swagger, "", " ")
17-
fmt.Println(string(data))
18-
}
19-
2011
const (
2112
workload = `
2213
---
@@ -527,10 +518,7 @@ status:
527518
conditions: []
528519
storedVersions: []
529520
`
530-
)
531-
532-
func TestCrdObj2CrdInternal(t *testing.T) {
533-
v1Crd := `
521+
v1Crd = `
534522
---
535523
apiVersion: apiextensions.k8s.io/v1
536524
kind: CustomResourceDefinition
@@ -564,7 +552,7 @@ spec:
564552
shortNames:
565553
- ct
566554
`
567-
v1beta1Crd := `
555+
v1beta1Crd = `
568556
---
569557
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
570558
apiVersion: apiextensions.k8s.io/v1beta1
@@ -609,6 +597,9 @@ spec:
609597
- ct
610598
preserveUnknownFields: false
611599
`
600+
)
601+
602+
func TestCrdObj2CrdInternal(t *testing.T) {
612603
crds := []string{v1Crd, v1beta1Crd}
613604
for _, crdYaml := range crds {
614605
crdObj, _, _ := scheme.Codecs.UniversalDeserializer().
@@ -619,3 +610,23 @@ spec:
619610
}
620611
}
621612
}
613+
614+
func TestGenerate(t *testing.T) {
615+
swagger, err := generate(workload)
616+
if err != nil {
617+
t.Fatalf("error: %v", err)
618+
}
619+
data, err := json.MarshalIndent(swagger, "", " ")
620+
if err != nil {
621+
t.Errorf("generate failed. err: %s", err)
622+
}
623+
fmt.Println(string(data))
624+
}
625+
626+
func TestSeparateSubDocuments(t *testing.T) {
627+
crds := v1Crd + v1beta1Crd
628+
files := separateSubDocuments([]byte(crds))
629+
if len(files) != 3 {
630+
t.Errorf("separateSubDocuments failed. expected 3, got %d", len(files))
631+
}
632+
}

0 commit comments

Comments
 (0)