Skip to content

Serve OpenAPI spec for registered CRDs#67205

Merged
k8s-ci-robot merged 6 commits intokubernetes:masterfrom
roycaihw:crd-openapi-spec
Nov 16, 2018
Merged

Serve OpenAPI spec for registered CRDs#67205
k8s-ci-robot merged 6 commits intokubernetes:masterfrom
roycaihw:crd-openapi-spec

Conversation

@roycaihw
Copy link
Copy Markdown
Member

@roycaihw roycaihw commented Aug 9, 2018

What this PR does / why we need it:
Generate and serve the OpenAPI spec for registered CRDs

Which issue(s) this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close the issue(s) when PR gets merged):
Fixes #58603

Special notes for your reviewer:

Release note:

reverted in #71158, original release note was:

kube-apiserver now serves OpenAPI specs for registered CRDs with defined validation schemata. Kubectl will validate client-side using those.
NONE

/sig api-machinery

cc @mbohlool @sttts

@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Aug 9, 2018
@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Aug 9, 2018
@roycaihw roycaihw force-pushed the crd-openapi-spec branch 8 times, most recently from e3ada48 to e1e5526 Compare August 11, 2018 00:49
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Aug 12, 2018
@roycaihw roycaihw changed the title [WIP] Generate OpenAPI spec for registered CRDs Serve OpenAPI spec for registered CRDs Aug 12, 2018
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 12, 2018
@roycaihw roycaihw force-pushed the crd-openapi-spec branch 2 times, most recently from a5b4f86 to ef38608 Compare August 12, 2018 23:10
@roycaihw
Copy link
Copy Markdown
Member Author

/retest

@roycaihw
Copy link
Copy Markdown
Member Author

/cc @mbohlool @sttts

This PR is ready for review. Please take a look :)

Please see the gist https://gist.github.com/roycaihw/1bb6eb7973b5496cb501ee50c8ee1ee3 for an example of constructed openapi spec for CRD:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: foos.samplecontroller.k8s.io
spec:
  group: samplecontroller.k8s.io
  version: v1alpha1
  names:
    kind: Foo
    plural: foos
  scope: Namespaced
  validation:
    openAPIV3Schema:
        description: test

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: roycaihw, smarterclayton

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the sig/testing Categorizes an issue or PR as relevant to SIG Testing. label Nov 15, 2018
@sttts
Copy link
Copy Markdown
Contributor

sttts commented Nov 16, 2018

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 16, 2018
@k8s-ci-robot k8s-ci-robot merged commit 54ee58b into kubernetes:master Nov 16, 2018
@smarterclayton
Copy link
Copy Markdown
Contributor

I wasn't able to see this from a casual scan of the code, but do we have a way to pass description for fields and model objects back from this? If not, we definitely need that in order to make kubectl explain be able to help users (which is one of the key consumers of openapi).

@sttts
Copy link
Copy Markdown
Contributor

sttts commented Nov 16, 2018

@smarterclayton the description of a scheme prop is copied into the published schema. So from the code it looks like this should work.

@roycaihw can you add an e2e test which calls kubectl explain against such a CRD?

@sttts
Copy link
Copy Markdown
Contributor

sttts commented Nov 16, 2018

@smarterclayton this shows up in the openapi spec (but kubectl explain does not do anything, should it?)

   "samplecontroller.k8s.io.v1alpha1.Foo": {
    "properties": {
     "spec": {
      "properties": {
       "replicas": {
        "description": "replicas description",
        "type": "integer",
        "maximum": 10,
        "minimum": 1,
        "externalDocs": {
         "description": "external replicas description",
         "url": "http://k8s.io"
        },
        "example": 42
       }
      }
     }
    }
   },

@liggitt
Copy link
Copy Markdown
Member

liggitt commented Nov 16, 2018

looks like the individual schema item does not include a x-kubernetes-group-version-kind stanza

kubectl create -f staging/src/k8s.io/csi-api/pkg/crd/manifests/csinodeinfo.yaml

kubectl get --raw /openapi/v2 | grep '"csi.storage.k8s.io.v1alpha1.CSINodeInfo":' -A 200
   "csi.storage.k8s.io.v1alpha1.CSINodeInfo": {
    "properties": {
     "spec": {
      "description": "Specification of CSINodeInfo",
      "properties": {
       "drivers": {
        "description": "List of CSI drivers running on the node and their specs.",
        "type": "array",
        "items": {
         "properties": {
          "name": {
           "description": "The CSI driver that this object refers to.",
           "type": "string"
          },
          "nodeID": {
           "description": "The node from the driver point of view.",
           "type": "string"
          },
          "topologyKeys": {
           "description": "List of keys supported by the driver.",
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "status": {
      "description": "Status of CSINodeInfo",
      "properties": {
       "drivers": {
        "description": "List of CSI drivers running on the node and their statuses.",
        "type": "array",
        "items": {
         "properties": {
          "available": {
           "description": "Whether the CSI driver is installed.",
           "type": "boolean"
          },
          "name": {
           "description": "The CSI driver that this object refers to.",
           "type": "string"
          },
          "volumePluginMechanism": {
           "description": "Indicates to external components the required mechanism to use for any in-tree plugins replaced by this driver.",
           "type": "string",
           "pattern": "in-tree|csi"
          }
         }
        }
       }
      }
     }
    }
   },
   "csi.storage.k8s.io.v1alpha1.CSINodeInfoList": {
    "description": "CSINodeInfoList is a list of CSINodeInfo",
    "required": [
     "items"
    ],
    "properties": {
     "apiVersion": {
      "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
      "type": "string"
     },
     "items": {
      "description": "List of csinodeinfos. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md",
      "type": "array",
      "items": {
       "$ref": "#/definitions/csi.storage.k8s.io.v1alpha1.CSINodeInfo"
      }
     },
     "kind": {
      "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
      "type": "string"
     },
     "metadata": {
      "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
      "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta"
     }
    },
    "x-kubernetes-group-version-kind": {
     "group": "csi.storage.k8s.io",
     "kind": "CSINodeInfoList",
     "version": "v1alpha1"
    }
   },
...

@liggitt
Copy link
Copy Markdown
Member

liggitt commented Nov 16, 2018

interestingly, it looks like the <CustomKind>List object schema does include the gvk

@smarterclayton
Copy link
Copy Markdown
Contributor

smarterclayton commented Nov 16, 2018 via email

@liggitt
Copy link
Copy Markdown
Member

liggitt commented Nov 16, 2018

this adds the GVK to the openapi spec:

diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/construction.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/construction.go
index 804681da1f..0327e6eacb 100644
--- a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/construction.go
+++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/construction.go
@@ -96,6 +96,11 @@ func (c *SwaggerConstructor) ConstructCRDOpenAPISpec() *spec.Swagger {
        var schema spec.Schema
        if c.schema != nil {
                schema = *c.schema
+               schema.AddExtension("x-kubernetes-group-version-kind", map[string]string{
+                       "group":   c.group,
+                       "kind":    c.kind,
+                       "version": c.version,
+               })
        }

but explain is still confused:

kubectl explain csinodeinfos
error: Couldn't find resource for "csi.storage.k8s.io/v1alpha1, Kind=CSINodeInfo"

and kubectl validation doesn't pick up the schema and complain about unknown fields:

echo '{"kind":"CSINodeInfo","apiVersion":"csi.storage.k8s.io/v1alpha1","metadata":{"name":"foo"},"spec":{"foo":true}}' \
  | kubectl create -f -
csinodeinfo.csi.storage.k8s.io/foo created

@roycaihw
Copy link
Copy Markdown
Member Author

@liggitt The format of x-kubernetes-group-version-kind in my code was wrong. It should be a list of map, instead of a single map. Fixing

@roycaihw
Copy link
Copy Markdown
Member Author

kubectl explain and validation works now. Will send a PR with an e2e test

$ kubectl explain csinodeinfos
KIND:     CSINodeInfo
VERSION:  csi.storage.k8s.io/v1alpha1

DESCRIPTION:

FIELDS:
   spec	<Object>
     Specification of CSINodeInfo

   status	<Object>
     Status of CSINodeInfo

$ echo '{"kind":"CSINodeInfo","apiVersion":"csi.storage.k8s.io/v1alpha1","metadata":{"name":"foo"},"spec":{"foo":true}}' \
  | kubectl create -f -
error: error validating "STDIN": error validating data: [ValidationError(CSINodeInfo): unknown field "apiVersion" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo): unknown field "kind" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo): unknown field "metadata" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo.spec): unknown field "foo" in csi.storage.k8s.io.v1alpha1.CSINodeInfo.spec]; if you choose to ignore these errors, turn validation off with --validate=false

@liggitt
Copy link
Copy Markdown
Member

liggitt commented Nov 16, 2018

ValidationError(CSINodeInfo): unknown field "apiVersion" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo): unknown field "kind" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo): unknown field "metadata" in csi.storage.k8s.io.v1alpha1.CSINodeInfo, ValidationError(CSINodeInfo.spec): unknown field "foo" in csi.storage.k8s.io.v1alpha1.CSINodeInfo.spec]; if you choose to ignore these errors, turn validation off with --validate=false

that actually illustrates a problem... the published schema does not contain standard object fields kind/apiVersion/metadata

this was not caught by the tests because of the delay in publishing the schema and the missing group version kind.

at this point, I think it is too late to rush to fix these issues. I think we need to roll back this PR and queue it up for 1.14 (or file for an exception while the issues are worked on out of master)

@liggitt liggitt mentioned this pull request Nov 16, 2018
liggitt added a commit to liggitt/kubernetes that referenced this pull request Nov 16, 2018
…-spec"

This reverts commit 54ee58b, reversing
changes made to 9e2820e.
@k8s-ci-robot k8s-ci-robot added release-note-none Denotes a PR that doesn't merit a release note. and removed release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Nov 18, 2018
@roycaihw roycaihw mentioned this pull request Nov 19, 2018
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/apiserver area/custom-resources cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate OpenAPI spec for registered CRDs