Giter Site home page Giter Site logo

kube-openapi's Introduction

Kube OpenAPI

This repo is the home for Kubernetes OpenAPI discovery spec generation. The goal is to support a subset of OpenAPI features to satisfy kubernetes use-cases but implement that subset with little to no assumption about the structure of the code or routes. Thus, there should be no kubernetes specific code in this repo.

There are two main parts:

  • A model generator that goes through .go files, find and generate model definitions.
  • The spec generator that is responsible for dynamically generating the final OpenAPI spec using web service routes or combining other OpenAPI/Json specs.

Contributing

Please see CONTRIBUTING.md for instructions on how to contribute.

kube-openapi's People

Contributors

alexzielenski avatar alphacentory avatar apelisse avatar austince avatar casualjim avatar cici37 avatar dangerontheranger avatar dims avatar fredbi avatar glendc avatar jefftree avatar jerome-laforge avatar jiahuif avatar jlambatl avatar jpbetz avatar k8s-ci-robot avatar keramix avatar lavalamp avatar liggitt avatar luksa avatar mariantalla avatar mbohlool avatar nikhita avatar olivierlemasle avatar pengsrc avatar pytlesk4 avatar roycaihw avatar seans3 avatar sttts avatar thockin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kube-openapi's Issues

CI doesn't honor go module and fails presubmit

https://travis-ci.org/kubernetes/kube-openapi/builds/539009857

travis-ci in this repo doesn't honor go module

go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;
	ignoring go.mod;

instead of fetching the pinged commit, the CI fetches package from HEAD, which includes public interface change, and fails to compile

pkg/schemaconv/smd.go:235:5: unknown field 'DiscriminatedBy' in struct literal of type schema.UnionField
pkg/schemaconv/smd.go:254:3: a.Struct undefined (type *schema.Atom has no field or method Struct)
pkg/schemaconv/smd.go:254:14: undefined: schema.Struct
pkg/schemaconv/smd.go:258:4: a.Struct undefined (type *schema.Atom has no field or method Struct)
pkg/schemaconv/smd.go:271:3: a.Struct undefined (type *schema.Atom has no field or method Struct)

cc @apelisse

Feature request: Add a boolean "forces replacement" field to properties

I'm not sure how difficult this would be, but it would be really handy if we could annotate each property that will force a replacement of the related resource.

For example, changing the .spec.affinity field of a Pod will force a replacement. We've manually curated a list of the ones we've encountered here: https://github.com/pulumi/pulumi-kubernetes/blob/e9f9dda531c3b8cfff519fd438a01f878d5e271a/pkg/provider/diff.go

This list isn't authoritative, and it would be great if we had a real source of truth here.

openapi-gen lacks support for enum

From @tamalsaha's issue kubernetes/kubernetes#62325 and @mbohlool's suggestion to open an issue in this repo (kubernetes/kubernetes#62325 (comment)),

Currently I generate CRD schema validation using a pipeline like below:

types.go ---(openapi-gen) ---> openapi_generated.go ---(crd-validation)---> crd.yaml

While this works, openapi-gen does not generate spec information for enums . We would like to see this supported.

[1] crd-validation: https://github.com/ant31/crd-validation

Question: can the pkg/validation/ module be used to validate Manifests against the Kubernetes Swagger file?

Hello! I've spent some time hacking on kubeval, and a separate, similar project called kubeconform. Both rely on JSON schemas generated from the Kubernetes Swagger file: https://github.com/instrumenta/kubernetes-json-schema . Rationale described by kubeval is that Go Tooling is not convenient to validate against OpenAPI schemas, whereas there is ample tooling for validating against JSON Schemas.

What is the relation between the pkg/validation/ module and go-swagger?
Can that module validate a Kubernetes manifest, using Kubernetes' Swagger file as schema?

Skipping the OpenAPI > JSON Schema conversion step would make tools like kubeval or kubeconform quite simpler and easier to maintain :) Note that I might be a bit confused with regard to the differences between Swagger, OpenAPI (2.0? 3.0?) and jsonschemas.

Thanks a lot!

Kubernetes apimachinery dependency issue for InternalEvent

Summary

I'm trying to use this library to generate the JSON openapi spec for the spark-on-k8s-operator, but I am running into an issue going from the generated models to the spec. Ultimately, I think root issue is a missing +k8s:openapi-gen=false annotation in the kubernetes apimachinery module. Since those annotations are used by this library, I wanted to verify my proposed change here before submitting a PR there to kubernetes/kubernetes.

Proprosal

Add the +k8s:openapi-gen=false annotation to the InternalEvent type defined in k8s apimachinery. Link to the actual type definition: type InternalEvent. Reference copied here for convenience:

// InternalEvent makes watch.Event versioned
// +protobuf=false
type InternalEvent watch.Event

Environment Setup

To simplify the duplication of my issue, I've created the following Dockerfile.

# Initial portion of Dockerfile is copied from here: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/Dockerfile
FROM golang:1.12.5-alpine as builder
ARG DEP_VERSION="0.5.3"
RUN apk add --no-cache bash git
ADD https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 /usr/bin/dep
RUN chmod +x /usr/bin/dep

# Get necessary go sources
RUN go get -u k8s.io/code-generator/cmd/openapi-gen
RUN go get -d github.com/GoogleCloudPlatform/spark-on-k8s-operator

# Get the dependencies and run openapi-gen to get the models
WORKDIR ${GOPATH}/src/github.com/GoogleCloudPlatform/spark-on-k8s-operator
RUN dep ensure
RUN go run ../../../k8s.io/code-generator/cmd/openapi-gen/main.go \
-i github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/apis/sparkoperator.k8s.io/v1beta2/,k8s.io/api/core/v1,k8s.io/apimachinery/pkg/api/resource,k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/util/intstr,k8s.io/apimachinery/pkg/runtime \
-p github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/apis/sparkoperator.k8s.io/v1beta2/ \
-h hack/custom-boilerplate.go.txt

# Change directories for ease of finding generated code.
WORKDIR pkg/apis/sparkoperator.k8s.io/v1beta2
ENTRYPOINT /bin/bash

After running docker build -t spark-on-k8s-operator:codegen passing in the above Dockerfile, you can run docker run -it spark-on-k8s-operator:codegen to get access to the openapi_generated.go file in the initial directory after getting into the container.

Issue

Now that we have a shared set up, you can open openapi_generated.go and inside, find one of the defined models:

func schema_pkg_apis_meta_v1_InternalEvent(ref common.ReferenceCallback) common.OpenAPIDefinition {                                                                                                                             
        return common.OpenAPIDefinition{                                                                                                                                                                                        
                Schema: spec.Schema{                                                                                                                                                                                            
                        SchemaProps: spec.SchemaProps{                                                                       
                                Description: "InternalEvent makes watch.Event versioned",                                  
                                Type:        []string{"object"},                                                             
                                Properties: map[string]spec.Schema{                                                        
                                        "Type": {                                                                          
                                                SchemaProps: spec.SchemaProps{                                               
                                                        Type:   []string{"string"},                                         
                                                        Format: "",                                                                     
                                                },                                                                              
                                        },                                                                                          
                                        "Object": {                                                                        
                                                SchemaProps: spec.SchemaProps{                                              
                                                        Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Error: *api.Status is recommended; other types may make sense\n   depending on context.",
                                                        Ref:         ref("k8s.io/apimachinery/pkg/runtime.Object"),                                                                                                                                                                                                                  
                                                },                                                                                                                                                                                                                                                                                   
                                        },                                                                                                                                                                                                                                                                                           
                                },                                                                                                                                                                                                                                                                                                   
                                Required: []string{"Type", "Object"},                                                                                                                                                                                                                                                                
                        },                                                                                                                                                                                                                                                                                                           
                },                                                                                                                                                                                                                                                                                                                   
                Dependencies: []string{                                                                                                                                                                                                                                                                                              
                        "k8s.io/apimachinery/pkg/runtime.Object"},                                                                                                                                                                                                                                                                   
        }                                                                                                                                                                                                                                                                                                                            
}   

It is problematic that the model specifies k8s.io/apimachinery/pkg/runtime.Object as a dependency because runtime.Object is not annotated to be a part of the output of running openapi-gen. Because this dependency isn't defined within the generated output, I get the following error when I call the k8s.io/kube-openapi/pkg/builder.BuildOpenAPIDefinitionsForResources method (defined in this project):

2019/09/20 12:55:31 ERROR: cannot find model definition for k8s.io/apimachinery/pkg/runtime.Object. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again
exit status 1

Possible Solution

I was able to get past this issue by going into the vendored file /go/src/github.com/GoogleCloudPlatform/spark-on-k8s-operator/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/watch.go, adding the proposed annotation, and then re-running the openapi-gen code. That change successfully removes the reference to InternalEvent in the generated output, which removes the dependency on runtime.Object, and then the subsequent call to BuildOpenAPIDefinitionsForResources can complete successfully.

It seems to me that the most reasonable solution is to remove the InternalEvent from the openapi-gen output considering that this type is excluded from protobuf generation, that it's name implies it'd be unnecessary in a client, and that the runtime.Object is not new and is not annotated to be included in the openapi-gen output. However, I have not used this library before, and I am new to kubernetes code generation. It's possible that I'm not using this project correctly. Does it make sense to submit a PR to the kubernetes project to add the annotation? Any help or direction here is greatly appreciated. Thanks!

Create a SECURITY_CONTACTS file.

As per the email sent to kubernetes-dev[1], please create a SECURITY_CONTACTS
file.

The template for the file can be found in the kubernetes-template repository[2].
A description for the file is in the steering-committee docs[3], you might need
to search that page for "Security Contacts".

Please feel free to ping me on the PR when you make it, otherwise I will see when
you close this issue. :)

Thanks so much, let me know if you have any questions.

(This issue was generated from a tool, apologies for any weirdness.)

[1] https://groups.google.com/forum/#!topic/kubernetes-dev/codeiIoQ6QE
[2] https://github.com/kubernetes/kubernetes-template-project/blob/master/SECURITY_CONTACTS
[3] https://github.com/kubernetes/community/blob/master/committee-steering/governance/sig-governance-template-short.md

Incomplete OpenAPI operation responses

In the current state, the generated OpenAPI document does not include all response types in operations, and those which are defined do not always include a schema.

For example:

"responses": {
  "200": {
    "description": "OK",
    "schema": {
      "$ref": "#/definitions/io.k8s.api.core.v1.PodList"
    }
  },
  "401": {
    "description": "Unauthorized"
  }
},

This is a problem because code generators cannot emit validation code or even just type signatures for functions sending requests.

Is there a reason this information is missing ?

Update to gnostic v0.5.1?

I'd like to use kube-openapi with latest gnostic (0.5.x) but there is an incompatibility between yaml v2 used by kube-openapi and yaml v3 used by gnostic since version 0.5.0: google/gnostic#195

May you please update kube-openapi to use the latest gnostic (0.5.1)?

Case-Insensitive Import Collision: gnostic/openapiv2

I upgraded my dependencies for my operator using go get -u all but now I receive the following error:
../../../../.go/pkg/mod/k8s.io/[email protected]/pkg/util/proto/document.go:24:2: case-insensitive import collision: "github.com/googleapis/gnostic/openapiv2" and "github.com/googleapis/gnostic/OpenAPIv2"

go.mod:

module github.com/...

go 1.14

require (
	github.com/Azure/go-autorest/autorest v0.11.10 // indirect
	github.com/Azure/go-autorest/autorest/to v0.4.0
	github.com/evanphx/json-patch v4.9.0+incompatible // indirect
	github.com/go-logr/logr v0.2.1 // indirect
	github.com/google/go-cmp v0.5.2 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/uuid v1.1.2 // indirect
	github.com/googleapis/gnostic v0.5.1 // indirect
	github.com/hashicorp/golang-lru v0.5.4 // indirect
	github.com/imdario/mergo v0.3.11 // indirect
	github.com/json-iterator/go v1.1.10 // indirect
	github.com/kr/pretty v0.2.1 // indirect
	github.com/kr/text v0.2.0 // indirect
	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
	github.com/nxadm/tail v1.4.5 // indirect
	github.com/onsi/ginkgo v1.14.1 // indirect
	github.com/onsi/gomega v1.10.2 // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/stretchr/testify v1.6.1 // indirect
	golang.org/x/net v0.0.0-20201009032441-dbdefad45b89 // indirect
	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
	golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
	golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
	gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
	k8s.io/api v0.19.2
	k8s.io/apimachinery v0.19.2
	k8s.io/client-go v0.0.0-20200214082307-e38a84523341
	k8s.io/klog v1.0.0
	k8s.io/klog/v2 v2.3.0 // indirect
	k8s.io/kube-openapi v0.0.0-20200923155610-8b5066479488 // indirect
	k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7 // indirect
	sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect
)

replace (
	golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13
	golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13
	k8s.io/api => k8s.io/api v0.0.0-20200214081623-ecbd4af0fc33
	k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200214081019-7490b3ed6e92
	k8s.io/client-go => k8s.io/client-go v0.0.0-20200214082307-e38a84523341
	k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200214080538-dc8f3adce97c
)

Items fields in List types do not need annotations

https://github.com/kubernetes/kube-openapi/blob/master/pkg/generators/rules/idl_tag.go#L25

This code needs to make an exception for List types (served as a result of a LIST verb and never a target for a mutating operation).

If:

  • There's a Metadata v1meta.ListMeta sibling field AND
  • The field is named "Items" and is a list of something

Then we should actually require that people NOT include a listType= annotation. (and ideally, suppress emitting the tag in the resulting openapi spec)

Why? Otherwise people have to add an exception for this, and I don't want people doing that for nothingburgers, it's bad karma.

Add support for +mapType, +structType

The two annotations used to describe the topology of maps and structs, +mapType and +structType, should result in generating the equivalent openapi extensions (x-kubernetes-map-type and x-kubernetes-struct-type respectively). This is documented but not implemented at the moment.

/assign
(have a tiny PR in progress at the moment)

changes around VisitArbitary rename broke building an initializer

we have an Go app that run as an Kubernetes initializer. It imports the following:

"k8s.io/client-go/tools/clientcmd"

"github.com/ghodss/yaml"

"k8s.io/api/apps/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"

And then invokes 2 two merge this way:
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1beta1.Deployment{})

This works fine up till recently, where building the code failed with the following error:

k8s.io/apimachinery/pkg/util/strategicpatch

../k8s.io/apimachinery/pkg/util/strategicpatch/meta.go:166:17: cannot use kindItem (type *kindItem) as type "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor in argument to s.Schema.Accept:
*kindItem does not implement "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/meta.go:181:17: cannot use sliceItem (type *sliceItem) as type "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor in argument to s.Schema.Accept:
*sliceItem does not implement "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/types.go:55:5: cannot use kindItem literal (type *kindItem) as type LookupPatchItem in assignment:
*kindItem does not implement LookupPatchItem (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/types.go:79:28: cannot use item (type *kindItem) as type "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor in argument to schema.SubSchema().Accept:
*kindItem does not implement "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/types.go:118:5: cannot use sliceItem literal (type *sliceItem) as type LookupPatchItem in assignment:
*sliceItem does not implement LookupPatchItem (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/types.go:146:28: cannot use item (type *sliceItem) as type "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor in argument to schema.SubSchema().Accept:
*sliceItem does not implement "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor (missing VisitArbitrary method)
../k8s.io/apimachinery/pkg/util/strategicpatch/types.go:169:18: cannot use item (type *sliceItem) as type "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor in argument to subschema.Accept:
*sliceItem does not implement "k8s.io/kube-openapi/pkg/util/proto".SchemaVisitor (missing VisitArbitrary method)

Generate valid openapi spec for intstr.IntOrString

From @tamalsaha's issue kubernetes/kubernetes#62329 and @mbohlool's comment to create an issue in this repo (kubernetes/kubernetes#62329 (comment)),

Currently openapi-gen generated spec for intstr.IntOrString only allows string types. https://github.com/kubernetes/apimachinery/blob/5d4f0da8e5fde7cbadf8ab3ce5cfb76f86dd854e/pkg/util/intstr/intstr.go#L124 . This is incorrect and causes problem when used to generate CRD validation schema. I generate CRD schema validation using a pipeline like below:

types.go ---(openapi-gen) ---> openapi_generated.go ---(crd-validation)---> crd.yaml

One fix suggested by @sttts is to use schema like

{
  "anyOf": [
    { "type": "string" },
    { "type": "number" }
  ]
}

But anyOf is not defined in v2 spec so can't be be returned from IntOrString.OpenAPIDefinition() method. But when CRD schema is generated one can update the auto generated schema for IntOrStr to fix this issue. For example: https://github.com/appscode/kutil/pull/133/files

[1] crd-validation: https://github.com/ant31/crd-validation

/cc @sttts @munnerz

Working example

When trying to generate Open API spec for the provided sample testdata, I am getting following API validation error:

$ go run ../../cmd/openapi-gen/openapi-gen.go -i "./testdata/listtype" -o pkg -p generated -O openapi_generated

API rule violation: names_match,./testdata/listtype,AtomicList,Field
API rule violation: names_match,./testdata/listtype,Item,Port
API rule violation: names_match,./testdata/listtype,Item,Protocol
API rule violation: names_match,./testdata/listtype,MapList,Field
API rule violation: names_match,./testdata/listtype,Pod,spec
API rule violation: names_match,./testdata/listtype,SetList,Field
2018/07/23 17:46:45 OpenAPI code generation error: Failed executing generator: some packages had errors:
API rule violations exist
exit status 1


In order to get a working example I used following testdata, which works:

testdata/volume.go

package listtype

// +k8s:openapi-gen=true
type Volume struct {
// Volume's name.
// Must be a DNS_LABEL and unique within the pod.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name string json:"name" protobuf:"bytes,1,opt,name=name"
// VolumeSource represents the location and type of the mounted volume.
// If not specified, the Volume is implied to be an EmptyDir.
// This implied behavior is deprecated and will be removed in a future version.
VolumeSource json:",inline" protobuf:"bytes,2,opt,name=volumeSource"
}

This is basically Type Volume copied from k8s.io/kubernetes/staging/src/k8s.io/api/core/v1/types.go

Line "// +k8s:openapi-gen=true" is added at the top as required by kube-openapi

Omit list_type_missing lint error from *List types

list_type is only useful when writing, and writes to *List types (containing metav1.ListMeta) are not written to

currently, every list type has a lint violation exception in place because of this, and every API promotion adds a new violation

Remove klog dependency

The error surfacing in this package should be self evident.

A self-contained system like Kubernetes which imports kube-openapi may use logging module (glog/klog) to do V-style logging. However this package don't have a good reason to use glog/klog, which interferes/makes assumption about logging mechanism used by downstream systems.

ref: #115

/good-first-issue
/help

'Cannot find model definition for' error during JSON generation

I am trying to generate OpenAPI Spec for some custom type definitions. There are no validation errors and openapi_generated.go is correctly generated. The custom type definition has a field whose type is apimachinery's v1.Time. When using builder.go to generate the JSON OpenAPI Spec, I am getting following error:

2019/04/07 12:00:08 ERROR: cannot find model definition for k8s.io/apimachinery/pkg/apis/meta/v1.Time. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again
exit status 1

The vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go already has '+k8s:openapi-gen=true' set.

Is there a way to get around this issue?

Validation: deserialization time vs creation time concerns

Proto (and, it seems, json-schema) have a "required" concept, by which they mean that you cannot decode/deserialize an object that lacks the field.

Kubernetes has a required concept, by which we mean you cannot create an object if it lacks the field.

Fields that are "required" in the Kubernetes sense are NOT required in the proto/json-schema sense: There are valid uses of kubernetes resources that involve deliberately partially specified objects.

This is just an example of an attribute for which it's very important when it is checked.

I'll categorize the aspects of our system in these two buckets here, as I think of them.

Deserialization-time enforcement:

  • Correct types (e.g. no ints as strings, no arrays in place of scalars, etc)

Validation-time enforcement:

  • required/optional
  • immutability
  • min/max
  • regexp match / enum value

Allow properties to be skipped from the generation

In the Jaeger Operator, we have structs similar to this:

// +k8s:openapi-gen=true
type JaegerSpec struct {
	// +optional
	JaegerCommonSpec `json:",inline,omitempty"`
}

type JaegerQuerySpec struct {
	// +optional
	JaegerCommonSpec `json:",inline,omitempty"`
}

type JaegerCollectorSpec struct {
	// +optional
	JaegerCommonSpec `json:",inline,omitempty"`
}

// and a bunch of other types embedding the common spec

// +k8s:openapi-gen=true
type JaegerCommonSpec struct {
	// +optional
	Volumes []v1.Volume `json:"volumes,omitempty"`

	// +optional
	Affinity *v1.Affinity `json:"affinity,omitempty"`

	// a bunch of other fields here...
}

Generating the CRD with the OpenAPI Schema generates a CRD with 1.3M:

$ ls -lah deploy/crds/jaegertracing.io_jaegers_crd.yaml
-rw-r--r--. 1 jpkroehling wheel 1,3M 29. Nov 16:56 deploy/crds/jaegertracing.io_jaegers_crd.yaml

Kubernetes, in turn, refuses this CRD:

The CustomResourceDefinition "jaegers.jaegertracing.io" is invalid: metadata.annotations: Too long: must have at most 262144 characters

Unfortunately, it looks like overriding the tag k8s:openapi-gen to false in the JaegerCommonSpec type has no effect. Neither has overriding the tag at the property level, so, my request here is to allow properties to be skipped from the schema generation.

openapi-gen should supoort default base package path

In my project, I will use the following command to generate deepcopy.

// Generate deepcopy for apis
//go:generate go run ../../vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go -O zz_generated.deepcopy -i ./... -h ../../hack/boilerplate.go.txt
// Generate openapi for apis
//go:generate go run ../../vendor/k8s.io/kube-openapi/cmd/openapi-gen/openapi-gen.go -O openapi_generated -i ./... -h ../../hack/boilerplate.go.txt

but if got error

go generate ./pkg/... ./cmd/...
2019/01/11 15:07:48 Arguments validation error: output package cannot be empty
exit status 1
pkg/apis/apis.go:20: running "go": exit status 1
make: *** [generate] Error 1

So I have to write a separate generate command for each package, I think it is necessary to have openapi-gen and deepcopy-gen have similar behavior, which can save a lot of unnecessary code.

//go:generate go run ../../vendor/k8s.io/kube-openapi/cmd/openapi-gen/openapi-gen.go -O openapi_generated -i ./devops/v1alpha2 -p github.com/runzexia/kubesphere-crd-sample/pkg/apis/devops/v1alpha2 -h ../../hack/boilerplate.go.txt

Expand coverage/support for atomics

We have a bunch of cases involving the composition of atomics that we don't yet test.

We need to define and test the behavior of all of them. Creating a grid out all possible combinations might be a good first step.

Here are a few we are aware of:

map typeref is tagged with +mapType=atomic (not supported or tested)

type Container struct {
  Field AtomicMapTyperef
}

// +mapType=atomic
type AtomicMapTyperef map[string]string

reference to map typeref is tagged with +mapType=atomic (not tested, seems to work)

type Container struct {
  //+mapType=atomic
  Field AtomicMapTyperef
}

type AtomicMapTyperef map[string]string

set of atomic structs (not tested, not sure if it works)

type Container struct {
  //+listType=set
  SetField []AtomicStruct
}

//+mapType=atomic
type AtomicStruct struct {
  StringField string
}

map value is atomic struct (not tested, not sure if it works)

type Container struct {
  //+listType=map
  //+listMapKey=name
  ListField []ListItem
}

//+mapType=atomic
type ListItem struct {
  Name string
  AtomicStructField AtomicStruct
}

//+mapType=atomic
type AtomicStruct struct {
  StringField string
}

map key is atomic struct (not tested, not sure if it works)

type Container struct {
  //+listType=map
  //+listMapKey=atomicStructField
  ListField []ListItem
}

//+mapType=atomic
type ListItem struct {
  atomicStructField AtomicStruct
}

//+mapType=atomic
type AtomicStruct struct {
  StringField string
}

Implement support for Enum values

Initially opened here kubernetes/kubernetes#97503 but I believe this improvement suggestion might be better here? This is about supporting parameters that support a list of values:

The "Protocol" parameter of a ContainerPort needs to be one of 'TCP', 'UDP', or 'SCTP' - as documented here

kubernetes/staging/src/k8s.io/api/core/v1/types.go

Line 1837 in ddf3eb5
// Protocol for port. Must be UDP, TCP, or SCTP.

However this restriction is not explicit in the generated OpenAPI file: https://raw.githubusercontent.com/kubernetes/kubernetes/ddf3eb5a1877338da806c2be15b53f456b6342c9/api/openapi-spec/swagger.json

There are a number of similar parameters which only accept a list of values - that restriction not being part of the generated OpenAPI file - "RestartPolicy" being another one.

This restricts the amount of validation that schema validators (such as Kubeval/Kubeconform) can do - and confuses users who would expect the tool to catch this kind of error.

OpenAPI does support enums though - is this a restriction of the tooling? It would be great to have these as part of the OpenAPI schema! pray

Allow Types to Specify an Example

Feature request to allow types to register an Example (to be placed in Schema.Example). It seems like what is currently done for custom types + formats would work (OpenAPISchemaType() method registered on type).

I'd propose the method definition to be:

OpenAPISchemaExample() interface{}

The same method would probably work for v3 as well.

Another approach would be to use the WriteSample and ReadSample on the restful.Route, if provided.

Would a PR for this be accepted?

"gnostic" should be updated

Hi

With the current version of gnostic we got the following message.

/private/var/tmp/_bazel_a13705/d47ee6d5190331e265fc3deb51db2812/external/bazel_gazelle/internal/go_repository.bzl:184:13: gazelle: gazelle: finding module path for import github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru: exit status 1: go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator latest
go: finding github.com/googleapis/gnostic/plugins latest
can't load package: package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru: unknown import path "github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru": cannot find module providing package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru
gazelle: finding module path for import github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore: exit status 1: go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator latest
go: finding github.com/googleapis/gnostic/plugins latest
can't load package: package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore: unknown import path "github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore": cannot find module providing package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore
gazelle: finding module path for import github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore: exit status 1: go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples latest
go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator latest
go: finding github.com/googleapis/gnostic/plugins latest
can't load package: package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore: unknown import path "github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore": cannot find module providing package github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore
gazelle: finding module path for import github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/xkcd/xkcd: exit status 1: go: finding github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/xkcd/xkcd latest

Related issue: kubernetes/client-go#636

Integration test README corrections

Found following issues in the README inside test/integration folder

  1. The command to generate openapi_generated.go should be:

go run ../../cmd/openapi-gen/openapi-gen.go -i "./testdata/listtype" -o pkg -p generated -O openapi_generated

  1. There is a typo in this line: The generated file pkg/generaged/openapi_generated.go should have been created.

It should be "pkg/generated/openapi_generated.go"

Adding Validation Constraints

Hi,

I'm interested in tackling kubernetes/kubernetes#8116 and kubernetes/kubernetes#24562. I understand that this project wishes to remain free of Kubernetes particularities, and I also see there's an attempt at integrating kube-openapi at kubernetes/kubernetes#55472.

So my question is if my end goal is to add enums to the generated swagger/openapi Json (or format regexp for Strings), should I start by adding the support to this project? Is this project intended to replace go-restful?

OpenAPI codegen should allow providing list of directories to search for dependencies

When running the openapi-gen code generator in the kubernetes/cluster-registry repo executed by the lines in this script, I see several could not import <some-package-import-path> errors for dependencies that are located within the vendor directory of the repo. For example:

I1220 16:35:12.455910    9557 parse.go:418] type checker: /tmp/gopathnU5sCI0j/src/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time.go:23:10: could not import k8s.io/kube-openapi/pkg/common (unable to import "k8s.io/kube-openapi/pkg/common": cannot find package "k8s.io/kube-openapi/pkg/common" in any of:
	/usr/local/go/src/k8s.io/kube-openapi/pkg/common (from $GOROOT)
	/tmp/gopathnU5sCI0j/src/k8s.io/kube-openapi/pkg/common (from $GOPATH))

The reason for these errors is that the type checker seems to want the import located in the src directory of either the Go toolchain installation or the GOPATH.

Can we instead allow the tool to search a particular comma separated list of directories? This would allow one to specify the vendor directory within their repo to satisfy them all.

How to reproduce it:
To reproduce this, add --v=10 and possibly also --logtostderr (or just look for the file /tmp/openapi-gen.*) in the openapi-gen step at: https://github.com/kubernetes/cluster-registry/blob/cc52bb00104bda72a2a14fdf49d71630e81c1fe8/hack/update-codegen.sh#L114-L120
to see all the errors.

Field path reported in validation errors within slice is incorrect

I noticed when validating a custom resource using the apiextensions NewSchemaValidator (which is using the SchemaValidator in this repo) that when a validation error occurs within a slice, the index of the slice is omitted from the fieldpath returned in the error.

YAML snippet:

spec:
  dependsOn:
    - provider: registry.upbound.io/crossplane/provider-aws
      version: 1

Output:

spec.dependsOn.version in body must be of type string: "integer"

I looked into why this is happening by traversing through the recursive validation that is performed against the schema. When we get to a the sliceValidator for spec.dependsOn, it's Applies() call returns true, causing it to be run.

Screenshot from 2021-11-05 11-51-07

Looking good so far. When the validation actually runs, we get the length for the slice and construct a new SchemaValidator that we will reuse to validate each item (just one item in this case).

Screenshot from 2021-11-05 11-54-40

When we first construct this nested SchemaValidator we set the path to match the parent validator (spec.dependsOn). This is not accurate though and needs to be updated on each iteration, so we call SetPath(). After setting the path, we can see that the validator has the proper index appended (spec.dependsOn.0).

Screenshot from 2021-11-05 11-58-53

Still looking good (though the format is a bit strange, more on this below). Unfortunately, the initial call to NewSchemaValidator() is when each of its child validators are instantiated (e.g. formatValidator, objectValidator, etc.), and the subsequent call to SetPath() updates the SchemaValidator path, but none of the child validator paths (so now the SchemaValidator has path spec.dependsOn.0, but all child validators have path spec.dependsOn). This can be observed when we iterate through each of the child validators and compare their path with the SchemaValidator:

Screenshot from 2021-11-05 12-04-24

Unfortunately this means that if an error occurs anywhere in any descendant validator, the index of the slice is omitted from the field path (as seen at beginning of the ticket). I have also verified that this is happening in the API server validation (that consumes this repo):

Note: this example is using a different resource.

$ kubectl apply -f definition.yaml --validate=false
The CompositeResourceDefinition "compositepostgresqlinstances.database.example.org" is invalid: spec.versions.referenceable: Invalid value: "string": spec.versions.referenceable in body must be of type boolean: "string"

I imagine most users are not catching this because the client-side validation provides a more accurate error:

$ kubectl apply -f definition.yaml 
error: error validating "definition.yaml": error validating data: ValidationError(CompositeResourceDefinition.spec.versions[0].referenceable): invalid type for io.crossplane.apiextensions.v1.CompositeResourceDefinition.spec.versions.referenceable: got "string", expected "boolean"; if you choose to ignore these errors, turn validation off with --validate=false

Proposal

I would like to propose two changes, and I am happy to implement them:

  1. Set path for child validators in SchemaValidator SetPath()

The simplest fix is to set the path for all child validators when the path is set on SchemaValidator. Though I believe there could be some more elegant handling of paths while performing this traversal, this does address the issue and is a lightweight change to fix this in the immediate term.

// SetPath sets the path for this schema validator
func (s *SchemaValidator) SetPath(path string) {
	s.Path = path
	for _, v := range s.validators {
		v.SetPath(path)
	}
}

I have verified that this works correctly:

spec.dependsOn.0.version in body must be of type string: "integer"
  1. Use JSONPath syntax for indices

To be more aligned with client-side validation, and for a more generally accepted format, it would be great to represent that index of a slice as dependsOn[0] instead of dependsOn.0.

If both of these fixes sound reasonable to folks, I'll go ahead and open PRs to address.

/assign
/bug

Having the same type embedded more than once breaks generation

ServiceServingCertSignerConfig embeds metav1.TypeMeta and configv1.GenericControllerConfig: https://github.com/openshift/api/blob/master/servicecertsigner/v1alpha1/types.go#L15-L21

At the time, configv1.GenericControllerConfig also embedded metav1.TypeMeta, which led to:

func schema_openshift_api_servicecertsigner_v1alpha1_ServiceServingCertSignerConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
    return common.OpenAPIDefinition{
        Schema: spec.Schema{
            SchemaProps: spec.SchemaProps{
                Description: "ServiceServingCertSignerConfig provides information to configure a serving serving cert signing controller",
                Properties: map[string]spec.Schema{
                    "kind": {
                        SchemaProps: spec.SchemaProps{
                            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{"string"},
                            Format:      "",
                        },
                    },
                    "apiVersion": {
                        SchemaProps: spec.SchemaProps{
                            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{"string"},
                            Format:      "",
                        },
                    },
                    "kind": {
                        SchemaProps: spec.SchemaProps{
                            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{"string"},
                            Format:      "",
                        },
                    },
                    "apiVersion": {
                        SchemaProps: spec.SchemaProps{
                            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{"string"},
                            Format:      "",
                        },
                    },
pkg/openapi/zz_generated.openapi.go:24107:6: duplicate key "kind" in map literal
pkg/openapi/zz_generated.openapi.go:24114:6: duplicate key "apiVersion" in map literal

Is there any way to convert my k8s CRD into OpenApi json ?

This is my Sample CRD and I want to generate OpenAPI JSON from it.
Is there any way to do it automatically?

        apiVersion: apiextensions.k8s.io/v1beta1
        kind: CustomResourceDefinition
        metadata:
          annotations:
            controller-gen.kubebuilder.io/version: v0.2.4
          creationTimestamp: null
          name: sampleapps.app.mydomain
        spec:
          group: app.mydomain
          names:
            kind: SampleApp
            listKind: SampleAppList
            plural: sampleapps
            singular: sampleapp
          scope: Namespaced
          validation:
            openAPIV3Schema:
              description: SampleApp is the Schema for the sampleapps API
              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/sig-architecture/api-conventions.md#resources'
                  type: string
                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/sig-architecture/api-conventions.md#types-kinds'
                  type: string
                metadata:
                  type: object
                spec:
                  description: SampleAppSpec defines the desired state of SampleApp
                  properties:
                    foo:
                      description: Foo is an example field of SampleApp. Edit SampleApp_types.go
                        to remove/update
                      type: string
                  type: object
                status:
                  description: SampleAppStatus defines the observed state of SampleApp
                  type: object
              type: object
          version: v1
          versions:
          - name: v1
            served: true
            storage: true
        status:
          acceptedNames:
            kind: ""
            plural: ""
          conditions: []
          storedVersions: []

"module-aware" mode is not working during "go test", in github-actions CI pipeline

@apelisse @dims Please advise and will do accordingly.

  • Problem
    While running github-actions CI, using go v.1.16, "go test" fails if GOPATH is not passed explicit to "go test"

  • Description

    • module-aware mode is "on" by default in go version 1.16. So GOPATH should not be be required, as
      there is a "go.mod" file in the root of the repo
    • But "go test" fails in github-actions CI as well as on laptop if GOPATH is not passed to "go-test"
    • This happens even in go version 1.15
    • We are currently checking out code to ${GITHUB/WORKSPACE}/src/k.io/kube-openapi/ . Then we cd into that directory for go build and go test.
    • "go build" works from any directory path. But "go test" works only and only from $GOPATH/src/k8s.io/kbeopenapi/
  • Pull Requests #226 , #232 and Issue #225 are related to this

  • Will close this issue if this not need to be tracked

Decouple REST Framework

Currently, the builder package is tightly coupled with a 2017 version of go-restful. This dependency is exposed in three places:

  • the builder's BuildOpenAPISpec, which takes a slice of *restful.WebServices
  • the common config's GetOperationIDAndTags function, which takes a *restful.Route
  • the handler's BuildAndRegisterOpenAPIVersionedService

It would be nice to be able to use this builder with newer versions of go-restful, but also with other frameworks.

I propose taking ownership of the route interfaces and adding an adapter for the current version of go-restful to support the transition. We could add more adapters in this repo, or 3rd parties could implement them elsewhere.

This would result in three breaking changes that I can see, with the two places the current dependency is exposed. Would this require a formal KEP?

Bug in GetCanonicalTypeName?

The go-restful Returns directive says it's ok to use a nil interface value for the model: https://godoc.org/github.com/emicklei/go-restful#RouteBuilder.Returns

But when I pass nil in (in this case while adding a new route to the K8s API server), it causes a nil pointer dereference in GetCanonicalTypeName. I think this is because reflect.TypeOf returns nil when given a nil interface, but we immediately call t.Kind() without first checking if t is nil:

t := reflect.TypeOf(model)
if t.Kind() == reflect.Ptr {

I don't have time to context-switch to a PR to fix at the moment, but figured I'd report it in case someone else can.

Error `API rule violation: list_type_missing` is faced when the type is `[]string`

We are using k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 and facing API rule violation: list_type_missing when the impl is as follows.

// Status of Nodes
Nodes []string `json:"nodes"`

So, we would like to know if is a bug or the expected behaviour? If it is a bug, could you help us by letting us know if it is solved already?

We could solve the validation issue by doing as follows.

// MemcachedStatus defines the observed state of Memcached
// +k8s:openapi-gen=true
type MemcachedStatus struct {
	// Nodes are the names of the memcached pods
	// +kubebuilder:validation:UniqueItems=true
	Nodes PodList `json:"nodes"`
}

// PodList is a list of names of pods
type PodList struct {
	Names []string
}

func NewPodList(value []string) PodList {
	p := PodList{Names: value}
	return p
}

Extra :

Following the others lbs/versions used with as well.

         k8s.io/api => k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8
	k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
	k8s.io/client-go => k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
	k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190409023720-1bc0c81fa51d

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.