Skip to content

Commit

Permalink
support yaml formatted openapi schema (#4017)
Browse files Browse the repository at this point in the history
* support yaml formatted openapi schema

* suggested changes
  • Loading branch information
natasha41575 committed Jul 15, 2021
1 parent 339e33d commit 0537b59
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 10 deletions.
20 changes: 20 additions & 0 deletions api/krusty/openapicustomschema_test.go
Expand Up @@ -17,6 +17,11 @@ func writeTestSchema(th kusttest_test.Harness, filepath string) {
th.WriteF(filepath+"mycrd_schema.json", string(bytes))
}

func writeTestSchemaYaml(th kusttest_test.Harness, filepath string) {
bytes, _ := ioutil.ReadFile("testdata/customschema.yaml")
th.WriteF(filepath+"mycrd_schema.yaml", string(bytes))
}

func writeCustomResource(th kusttest_test.Harness, filepath string) {
th.WriteF(filepath, `
apiVersion: example.com/v1alpha1
Expand Down Expand Up @@ -103,6 +108,21 @@ openapi:
th.AssertActualEqualsExpected(m, patchedCustomResource)
}

func TestCustomOpenApiFieldYaml(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- mycrd.yaml
openapi:
path: mycrd_schema.yaml
`+customSchemaPatch)
writeCustomResource(th, "mycrd.yaml")
writeTestSchemaYaml(th, "./")
openapi.ResetOpenAPI()
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, patchedCustomResource)
}

// Error if user tries to specify both builtin version
// and custom schema
func TestCustomOpenApiFieldBothPathAndVersion(t *testing.T) {
Expand Down
75 changes: 75 additions & 0 deletions api/krusty/testdata/customschema.yaml
@@ -0,0 +1,75 @@
definitions:
v1alpha1.MyCRD:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
properties:
template:
"$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec"
type: object
status:
properties:
success:
type: boolean
type: object
type: object
x-kubernetes-group-version-kind:
- group: example.com
kind: MyCRD
version: v1alpha1
io.k8s.api.core.v1.PodTemplateSpec:
properties:
metadata:
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
spec:
"$ref": "#/definitions/io.k8s.api.core.v1.PodSpec"
type: object
io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta:
properties:
name:
type: string
type: object
io.k8s.api.core.v1.PodSpec:
properties:
containers:
items:
"$ref": "#/definitions/io.k8s.api.core.v1.Container"
type: array
x-kubernetes-patch-merge-key: name
x-kubernetes-patch-strategy: merge
type: object
io.k8s.api.core.v1.Container:
properties:
command:
items:
type: string
type: array
image:
type: string
name:
type: string
ports:
items:
"$ref": "#/definitions/io.k8s.api.core.v1.ContainerPort"
type: array
x-kubernetes-list-map-keys:
- containerPort
- protocol
x-kubernetes-list-type: map
x-kubernetes-patch-merge-key: containerPort
x-kubernetes-patch-strategy: merge
type: object
io.k8s.api.core.v1.ContainerPort:
properties:
containerPort:
type: integer
name:
type: string
protocol:
type: string
type: object
1 change: 1 addition & 0 deletions cmd/config/go.sum
Expand Up @@ -248,4 +248,5 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R
sigs.k8s.io/kustomize/kyaml v0.11.0 h1:9KhiCPKaVyuPcgOLJXkvytOvjMJLoxpjodiycb4gHsA=
sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
40 changes: 31 additions & 9 deletions kustomize/commands/openapi/fetch/fetch.go
Expand Up @@ -8,26 +8,38 @@ import (
"os/exec"

"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)

var format string

// NewCmdFetch makes a new fetch command.
func NewCmdFetch(w io.Writer) *cobra.Command {
infoCmd := cobra.Command{
fetchCmd := cobra.Command{
Use: "fetch",
Short: `Fetches the OpenAPI specification from the current kubernetes cluster specified
in the user's kubeconfig`,
Example: `kustomize openapi fetch`,
Run: func(cmd *cobra.Command, args []string) {
printSchema(w)
RunE: func(cmd *cobra.Command, args []string) error {
return printSchema(w)
},
}
return &infoCmd
fetchCmd.Flags().StringVar(
&format,
"format",
"json",
"Specify format for fetched schema ('json' or 'yaml')")
return &fetchCmd
}

func printSchema(w io.Writer) {
func printSchema(w io.Writer) error {
if format != "json" && format != "yaml" {
return fmt.Errorf("format must be either 'json' or 'yaml'")
}

errMsg := `
Error fetching schema from cluster.
Please make sure kubectl is installed and its context is set correctly.
Please make sure kubectl is installed, its context is set correctly, and your cluster is up.
Installation and setup instructions: https://kubernetes.io/docs/tasks/tools/install-kubectl/`

command := exec.Command("kubectl", []string{"get", "--raw", "/openapi/v2"}...)
Expand All @@ -36,15 +48,25 @@ Installation and setup instructions: https://kubernetes.io/docs/tasks/tools/inst
command.Stdout = &stdout
command.Stderr = &stderr
err := command.Run()
if err != nil || stdout.String() == "" {
fmt.Fprintln(w, err, stderr.String()+errMsg)
return
if err != nil {
return fmt.Errorf("%w\n%s", err, stderr.String()+errMsg)
} else if stdout.String() == "" {
return fmt.Errorf(stderr.String() + errMsg)
}

// format and output
var jsonSchema map[string]interface{}
output := stdout.Bytes()
json.Unmarshal(output, &jsonSchema)
output, _ = json.MarshalIndent(jsonSchema, "", " ")

if format == "yaml" {
output, err = yaml.JSONToYAML(output)
if err != nil {
return err
}
}

fmt.Fprintln(w, string(output))
return nil
}
1 change: 1 addition & 0 deletions kyaml/go.mod
Expand Up @@ -19,6 +19,7 @@ require (
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
gopkg.in/yaml.v2 v2.4.0
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
sigs.k8s.io/yaml v1.2.0
)

// These can be removed after upgrading golangci-lint (Issue #3663)
Expand Down
1 change: 1 addition & 0 deletions kyaml/go.sum
Expand Up @@ -225,4 +225,5 @@ k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
10 changes: 9 additions & 1 deletion kyaml/openapi/openapi.go
Expand Up @@ -16,6 +16,7 @@ import (
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
"sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
k8syaml "sigs.k8s.io/yaml"
)

// globalSchema contains global state information about the openapi
Expand Down Expand Up @@ -536,7 +537,14 @@ func parseBuiltinSchema(version string) {
// parse parses and indexes a single json schema
func parse(b []byte) error {
var swagger spec.Swagger

s := string(b)
if len(s) > 0 && s[0] != '{' {
var err error
b, err = k8syaml.YAMLToJSON(b)
if err != nil {
return errors.Wrap(err)
}
}
if err := swagger.UnmarshalJSON(b); err != nil {
return errors.Wrap(err)
}
Expand Down

0 comments on commit 0537b59

Please sign in to comment.