Skip to content

Commit

Permalink
feat: support yaml stream format input for CRD generation (#73)
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <[email protected]>
  • Loading branch information
Peefy authored Dec 6, 2023
1 parent d8316c0 commit d66c060
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 18 deletions.
67 changes: 63 additions & 4 deletions pkg/kube_resource/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
package generator

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"

Expand Down Expand Up @@ -57,7 +57,7 @@ func GetSpec(opts *GenOpts) (string, error) {
if err != nil {
return "", fmt.Errorf("could not locate spec: %s, err: %s", opts.Spec, err)
}
crdContent, err := ioutil.ReadFile(path)
crdContent, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("could not load spec: %s, err: %s", opts.Spec, err)
}
Expand All @@ -72,9 +72,12 @@ func GetSpec(opts *GenOpts) (string, error) {
return "", fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
}
tmpSpecDir := os.TempDir()
tmpFile, err := ioutil.TempFile(tmpSpecDir, "kcl-swagger-")
tmpFile, err := os.CreateTemp(tmpSpecDir, "kcl-swagger-")
if err != nil {
return "", fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
}
// copy k8s.json to tmpDir
if err := ioutil.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
if err := os.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
return "", fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
}
if _, err := tmpFile.Write(swaggerContent); err != nil {
Expand All @@ -84,6 +87,62 @@ func GetSpec(opts *GenOpts) (string, error) {
return tmpFile.Name(), nil
}

// GetSpecs retrieves specifications from the given GenOpts and returns a list of temporary file paths for the generated OpenAPI specs.
// It returns an error if there is any issue in fetching and generating the specs.
// Parameters:
// - opts: a GenOpts struct that contains the options and parameters required for generating the specs
// Returns:
// - []string: a list of temporary file paths for the generated OpenAPI specs
// - error: an error message if any error occurs.
func GetSpecs(opts *GenOpts) ([]string, error) {
var result []string
// read crd content from file
path, err := filepath.Abs(opts.Spec)
if err != nil {
return result, fmt.Errorf("could not locate spec: %s, err: %s", opts.Spec, err)
}
crdContent, err := os.ReadFile(path)
if err != nil {
return result, fmt.Errorf("could not load spec: %s, err: %s", opts.Spec, err)
}
contents := separateSubDocuments(crdContent)
for _, content := range contents {
// generate openapi spec from crd
swagger, err := generate(string(content))
if err != nil {
return result, fmt.Errorf("could not generate swagger spec: %s, err: %s", opts.Spec, err)
}
// write openapi spec to tmp file, along with the referenced k8s.json
swaggerContent, err := json.MarshalIndent(swagger, "", "")
if err != nil {
return result, fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
}
tmpSpecDir := os.TempDir()
tmpFile, err := os.CreateTemp(tmpSpecDir, "kcl-swagger-")
if err != nil {
return result, fmt.Errorf("could not validate swagger spec: %s, err: %s", opts.Spec, err)
}
// copy k8s.json to tmpDir
if err := os.WriteFile(filepath.Join(tmpSpecDir, "k8s.json"), []byte(k8sFile), 0644); err != nil {
return result, fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
}
if _, err := tmpFile.Write(swaggerContent); err != nil {
return result, fmt.Errorf("could not generate swagger spec file: %s, err: %s", opts.Spec, err)
}
// Append the tmp openapi spec file path
result = append(result, tmpFile.Name())
}
return result, nil
}

func separateSubDocuments(data []byte) [][]byte {
lineBreak := "\n"
if bytes.Contains(data, []byte("\r\n---\r\n")) {
lineBreak = "\r\n"
}
return bytes.Split(data, []byte(lineBreak+"---"+lineBreak))
}

// generate swagger model based on crd
func generate(crdYaml string) (*spec.Swagger, error) {
crdObj, _, err := scheme.Codecs.UniversalDeserializer().
Expand Down
39 changes: 25 additions & 14 deletions pkg/kube_resource/generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ import (
"k8s.io/client-go/kubernetes/scheme"
)

func TestGenerate(t *testing.T) {
swagger, err := generate(workload)
if err != nil {
t.Fatalf("error: %v", err)
}
data, err := json.MarshalIndent(swagger, "", " ")
fmt.Println(string(data))
}

const (
workload = `
---
Expand Down Expand Up @@ -527,10 +518,7 @@ status:
conditions: []
storedVersions: []
`
)

func TestCrdObj2CrdInternal(t *testing.T) {
v1Crd := `
v1Crd = `
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
Expand Down Expand Up @@ -564,7 +552,7 @@ spec:
shortNames:
- ct
`
v1beta1Crd := `
v1beta1Crd = `
---
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
Expand Down Expand Up @@ -609,6 +597,9 @@ spec:
- ct
preserveUnknownFields: false
`
)

func TestCrdObj2CrdInternal(t *testing.T) {
crds := []string{v1Crd, v1beta1Crd}
for _, crdYaml := range crds {
crdObj, _, _ := scheme.Codecs.UniversalDeserializer().
Expand All @@ -619,3 +610,23 @@ spec:
}
}
}

func TestGenerate(t *testing.T) {
swagger, err := generate(workload)
if err != nil {
t.Fatalf("error: %v", err)
}
data, err := json.MarshalIndent(swagger, "", " ")
if err != nil {
t.Errorf("generate failed. err: %s", err)
}
fmt.Println(string(data))
}

func TestSeparateSubDocuments(t *testing.T) {
crds := v1Crd + v1beta1Crd
files := separateSubDocuments([]byte(crds))
if len(files) != 3 {
t.Errorf("separateSubDocuments failed. expected 3, got %d", len(files))
}
}

0 comments on commit d66c060

Please sign in to comment.