diff --git a/api/krusty/openapicustomschema_test.go b/api/krusty/openapicustomschema_test.go index 41cea488b1..a9be5fcfc8 100644 --- a/api/krusty/openapicustomschema_test.go +++ b/api/krusty/openapicustomschema_test.go @@ -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 @@ -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) { diff --git a/api/krusty/testdata/customschema.yaml b/api/krusty/testdata/customschema.yaml new file mode 100644 index 0000000000..4e77065d4a --- /dev/null +++ b/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 diff --git a/cmd/config/go.sum b/cmd/config/go.sum index 7779ee41a1..c273fee61a 100644 --- a/cmd/config/go.sum +++ b/cmd/config/go.sum @@ -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= diff --git a/kustomize/commands/openapi/fetch/fetch.go b/kustomize/commands/openapi/fetch/fetch.go index 798559768d..35804c0d8d 100644 --- a/kustomize/commands/openapi/fetch/fetch.go +++ b/kustomize/commands/openapi/fetch/fetch.go @@ -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"}...) @@ -36,9 +48,10 @@ 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 @@ -46,5 +59,14 @@ Installation and setup instructions: https://kubernetes.io/docs/tasks/tools/inst 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 } diff --git a/kyaml/go.mod b/kyaml/go.mod index 61b581ab84..6cc76c2bd8 100644 --- a/kyaml/go.mod +++ b/kyaml/go.mod @@ -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) diff --git a/kyaml/go.sum b/kyaml/go.sum index 58f7342c0a..673b3e3ad8 100644 --- a/kyaml/go.sum +++ b/kyaml/go.sum @@ -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= diff --git a/kyaml/openapi/openapi.go b/kyaml/openapi/openapi.go index 5e34195f61..5ad69adc70 100644 --- a/kyaml/openapi/openapi.go +++ b/kyaml/openapi/openapi.go @@ -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 @@ -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) }