Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support yaml stream format input for CRD generation #73

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
}
}
Loading