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

support yaml formatted openapi schema #4017

Merged
merged 2 commits into from Jul 15, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
natasha41575 marked this conversation as resolved.
Show resolved Hide resolved
)

// 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