mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #40124 from mbohlool/separation
Automatic merge from submit-queue Use full package path for definition name in OpenAPI spec We were using short package name (last part of package name) plus type name for OpenAPI spec definition name. That can result in duplicate names and make the spec invalid. To be sure we will always have unique names, we are going to use full package name as definition name. Also "x-kubernetes-tag" custom field is added to definitions to list Group/Version/Kind for the definitions that has it. This will help clients to discover definitions easier. Lastly, we've added a reference from old definition names to the new ones to keep backward compatibilities. The list of old definitions will not be updated. **Release note**: - Rename OpenAPI definition names to type's full package names to prevent duplicates - Create OpenAPI extension "x-kubernetes-group-version-kind" for definitions to store Group/Version/Kind - Deprecate old definition names and create a reference to the new definitions. Old definitions will be removed in the next release.
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -295,7 +295,7 @@ func Run(s *options.ServerRunOptions) error {
 | 
			
		||||
	genericConfig.Authenticator = apiAuthenticator
 | 
			
		||||
	genericConfig.Authorizer = apiAuthorizer
 | 
			
		||||
	genericConfig.AdmissionControl = admissionController
 | 
			
		||||
	genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.OpenAPIDefinitions)
 | 
			
		||||
	genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions)
 | 
			
		||||
	genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
 | 
			
		||||
	genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
 | 
			
		||||
	genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
 | 
			
		||||
 
 | 
			
		||||
@@ -133,7 +133,7 @@ const (
 | 
			
		||||
// openApiGen produces a file with auto-generated OpenAPI functions.
 | 
			
		||||
type openAPIGen struct {
 | 
			
		||||
	generator.DefaultGen
 | 
			
		||||
	// TargetPackage is the package that will get OpenAPIDefinitions variable contains all open API definitions.
 | 
			
		||||
	// TargetPackage is the package that will get GetOpenAPIDefinitions function returns all open API definitions.
 | 
			
		||||
	targetPackage *types.Package
 | 
			
		||||
	imports       namer.ImportTracker
 | 
			
		||||
	context       *generator.Context
 | 
			
		||||
@@ -186,7 +186,7 @@ func (g *openAPIGen) Imports(c *generator.Context) []string {
 | 
			
		||||
func argsFromType(t *types.Type) generator.Args {
 | 
			
		||||
	return generator.Args{
 | 
			
		||||
		"type":              t,
 | 
			
		||||
		"OpenAPIDefinitions": types.Ref(openAPICommonPackagePath, "OpenAPIDefinitions"),
 | 
			
		||||
		"ReferenceCallback": types.Ref(openAPICommonPackagePath, "ReferenceCallback"),
 | 
			
		||||
		"OpenAPIDefinition": types.Ref(openAPICommonPackagePath, "OpenAPIDefinition"),
 | 
			
		||||
		"SpecSchemaType":    types.Ref(specPackagePath, "Schema"),
 | 
			
		||||
	}
 | 
			
		||||
@@ -194,14 +194,15 @@ func argsFromType(t *types.Type) generator.Args {
 | 
			
		||||
 | 
			
		||||
func (g *openAPIGen) Init(c *generator.Context, w io.Writer) error {
 | 
			
		||||
	sw := generator.NewSnippetWriter(w, c, "$", "$")
 | 
			
		||||
	sw.Do("var OpenAPIDefinitions *$.OpenAPIDefinitions|raw$ = ", argsFromType(nil))
 | 
			
		||||
	sw.Do("&$.OpenAPIDefinitions|raw${\n", argsFromType(nil))
 | 
			
		||||
	sw.Do("func GetOpenAPIDefinitions(ref $.ReferenceCallback|raw$) map[string]$.OpenAPIDefinition|raw$ {\n", argsFromType(nil))
 | 
			
		||||
	sw.Do("return map[string]$.OpenAPIDefinition|raw${\n", argsFromType(nil))
 | 
			
		||||
	return sw.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *openAPIGen) Finalize(c *generator.Context, w io.Writer) error {
 | 
			
		||||
	sw := generator.NewSnippetWriter(w, c, "$", "$")
 | 
			
		||||
	sw.Do("}\n", nil)
 | 
			
		||||
	sw.Do("}\n", nil)
 | 
			
		||||
	return sw.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -308,9 +309,9 @@ func (g openAPITypeWriter) generate(t *types.Type) error {
 | 
			
		||||
	switch t.Kind {
 | 
			
		||||
	case types.Struct:
 | 
			
		||||
		args := argsFromType(t)
 | 
			
		||||
		g.Do("\"$.$\": ", typeShortName(t))
 | 
			
		||||
		g.Do("\"$.$\": ", t.Name)
 | 
			
		||||
		if hasOpenAPIDefinitionMethod(t) {
 | 
			
		||||
			g.Do("$.type|raw${}.OpenAPIDefinition(),", args)
 | 
			
		||||
			g.Do("$.type|raw${}.OpenAPIDefinition(),\n", args)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		g.Do("{\nSchema: spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil)
 | 
			
		||||
@@ -437,14 +438,8 @@ func (g openAPITypeWriter) generateSimpleProperty(typeString, format string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g openAPITypeWriter) generateReferenceProperty(t *types.Type) {
 | 
			
		||||
	var name string
 | 
			
		||||
	if t.Name.Package == "" {
 | 
			
		||||
		name = t.Name.Name
 | 
			
		||||
	} else {
 | 
			
		||||
		name = filepath.Base(t.Name.Package) + "." + t.Name.Name
 | 
			
		||||
	}
 | 
			
		||||
	g.refTypes[name] = t
 | 
			
		||||
	g.Do("Ref: spec.MustCreateRef(\"#/definitions/$.$\"),\n", name)
 | 
			
		||||
	g.refTypes[t.Name.String()] = t
 | 
			
		||||
	g.Do("Ref: ref(\"$.$\"),\n", t.Name.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resolveAliasAndPtrType(t *types.Type) *types.Type {
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,7 @@ type Blah struct {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	assert.Equal(`"foo.Blah": {
 | 
			
		||||
	assert.Equal(`"base/foo.Blah": {
 | 
			
		||||
Schema: spec.Schema{
 | 
			
		||||
SchemaProps: spec.SchemaProps{
 | 
			
		||||
Description: "Blah is a test.",
 | 
			
		||||
@@ -280,7 +280,7 @@ type Blah struct {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	assert.Equal(`"foo.Blah": {
 | 
			
		||||
	assert.Equal(`"base/foo.Blah": {
 | 
			
		||||
Schema: spec.Schema{
 | 
			
		||||
SchemaProps: spec.SchemaProps{
 | 
			
		||||
Description: "PointerSample demonstrate pointer's properties",
 | 
			
		||||
@@ -295,7 +295,7 @@ Format: "",
 | 
			
		||||
"StructPointer": {
 | 
			
		||||
SchemaProps: spec.SchemaProps{
 | 
			
		||||
Description: "A struct pointer",
 | 
			
		||||
Ref: spec.MustCreateRef("#/definitions/foo.Blah"),
 | 
			
		||||
Ref: ref("base/foo.Blah"),
 | 
			
		||||
},
 | 
			
		||||
},
 | 
			
		||||
"SlicePointer": {
 | 
			
		||||
@@ -331,7 +331,7 @@ Required: []string{"StringPointer","StructPointer","SlicePointer","MapPointer"},
 | 
			
		||||
},
 | 
			
		||||
},
 | 
			
		||||
Dependencies: []string{
 | 
			
		||||
"foo.Blah",},
 | 
			
		||||
"base/foo.Blah",},
 | 
			
		||||
},
 | 
			
		||||
`, buffer.String())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -175,7 +175,7 @@ func Run(s *options.ServerRunOptions) error {
 | 
			
		||||
	genericConfig.Authenticator = apiAuthenticator
 | 
			
		||||
	genericConfig.Authorizer = apiAuthorizer
 | 
			
		||||
	genericConfig.AdmissionControl = admissionController
 | 
			
		||||
	genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.OpenAPIDefinitions)
 | 
			
		||||
	genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.GetOpenAPIDefinitions)
 | 
			
		||||
	genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
 | 
			
		||||
	genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
 | 
			
		||||
	genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -5,6 +5,7 @@ licenses(["notice"])
 | 
			
		||||
load(
 | 
			
		||||
    "@io_bazel_rules_go//go:def.bzl",
 | 
			
		||||
    "go_library",
 | 
			
		||||
    "go_test",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
go_library(
 | 
			
		||||
@@ -13,6 +14,11 @@ go_library(
 | 
			
		||||
    tags = ["automanaged"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//vendor:github.com/emicklei/go-restful",
 | 
			
		||||
        "//vendor:github.com/go-openapi/spec",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/openapi",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/runtime",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
 | 
			
		||||
        "//vendor:k8s.io/apiserver/pkg/util/trie",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
@@ -29,3 +35,16 @@ filegroup(
 | 
			
		||||
    srcs = [":package-srcs"],
 | 
			
		||||
    tags = ["automanaged"],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
go_test(
 | 
			
		||||
    name = "go_default_test",
 | 
			
		||||
    srcs = ["openapi_test.go"],
 | 
			
		||||
    library = ":go_default_library",
 | 
			
		||||
    tags = ["automanaged"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//vendor:github.com/go-openapi/spec",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/runtime",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,16 +19,27 @@ package openapi
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful"
 | 
			
		||||
	"github.com/go-openapi/spec"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/openapi"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
			
		||||
	"k8s.io/apiserver/pkg/util/trie"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var verbs = trie.New([]string{"get", "log", "read", "replace", "patch", "delete", "deletecollection", "watch", "connect", "proxy", "list", "create", "patch"})
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	extensionGVK = "x-kubernetes-group-version-kind"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ToValidOperationID makes an string a valid op ID (e.g. removing punctuations and whitespaces and make it camel case)
 | 
			
		||||
func ToValidOperationID(s string, capitalizeFirstLetter bool) string {
 | 
			
		||||
	var buffer bytes.Buffer
 | 
			
		||||
@@ -85,3 +96,382 @@ func GetOperationIDAndTags(servePath string, r *restful.Route) (string, []string
 | 
			
		||||
		return op, tags, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type groupVersionKinds []v1.GroupVersionKind
 | 
			
		||||
 | 
			
		||||
func (s groupVersionKinds) Len() int {
 | 
			
		||||
	return len(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s groupVersionKinds) Swap(i, j int) {
 | 
			
		||||
	s[i], s[j] = s[j], s[i]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s groupVersionKinds) Less(i, j int) bool {
 | 
			
		||||
	if s[i].Group == s[j].Group {
 | 
			
		||||
		if s[i].Version == s[j].Version {
 | 
			
		||||
			return s[i].Kind < s[j].Kind
 | 
			
		||||
		}
 | 
			
		||||
		return s[i].Version < s[j].Version
 | 
			
		||||
	}
 | 
			
		||||
	return s[i].Group < s[j].Group
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefinitionNamer is the type to customize OpenAPI definition name.
 | 
			
		||||
type DefinitionNamer struct {
 | 
			
		||||
	typeGroupVersionKinds map[string]groupVersionKinds
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func gvkConvert(gvk schema.GroupVersionKind) v1.GroupVersionKind {
 | 
			
		||||
	return v1.GroupVersionKind{
 | 
			
		||||
		Group:   gvk.Group,
 | 
			
		||||
		Version: gvk.Version,
 | 
			
		||||
		Kind:    gvk.Kind,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func friendlyName(name string) string {
 | 
			
		||||
	nameParts := strings.Split(name, "/")
 | 
			
		||||
	// Reverse first part. e.g., io.k8s... instead of k8s.io...
 | 
			
		||||
	if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
 | 
			
		||||
		parts := strings.Split(nameParts[0], ".")
 | 
			
		||||
		for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
 | 
			
		||||
			parts[i], parts[j] = parts[j], parts[i]
 | 
			
		||||
		}
 | 
			
		||||
		nameParts[0] = strings.Join(parts, ".")
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(nameParts, ".")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func typeName(t reflect.Type) string {
 | 
			
		||||
	return fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDefinitionNamer constructs a new DefinitionNamer to be used to customize OpenAPI spec.
 | 
			
		||||
func NewDefinitionNamer(s *runtime.Scheme) DefinitionNamer {
 | 
			
		||||
	ret := DefinitionNamer{
 | 
			
		||||
		typeGroupVersionKinds: map[string]groupVersionKinds{},
 | 
			
		||||
	}
 | 
			
		||||
	for gvk, rtype := range s.AllKnownTypes() {
 | 
			
		||||
		ret.typeGroupVersionKinds[typeName(rtype)] = append(ret.typeGroupVersionKinds[typeName(rtype)], gvkConvert(gvk))
 | 
			
		||||
	}
 | 
			
		||||
	for _, gvk := range ret.typeGroupVersionKinds {
 | 
			
		||||
		sort.Sort(gvk)
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDefinitionName returns the name and tags for a given definition
 | 
			
		||||
func (d *DefinitionNamer) GetDefinitionName(servePath string, name string) (string, spec.Extensions) {
 | 
			
		||||
	if groupVersionKinds, ok := d.typeGroupVersionKinds[name]; ok {
 | 
			
		||||
		return friendlyName(name), spec.Extensions{
 | 
			
		||||
			extensionGVK: []v1.GroupVersionKind(groupVersionKinds),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return friendlyName(name), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PostProcessSpec finalize OpenAPI spec and add removed definition for backward compatibility
 | 
			
		||||
func PostProcessSpec(s *spec.Swagger) (*spec.Swagger, error) {
 | 
			
		||||
	compatibilityMap := map[string]string{
 | 
			
		||||
		"v1beta1.DeploymentStatus":            "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentStatus",
 | 
			
		||||
		"v1beta1.ReplicaSetList":              "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ReplicaSetList",
 | 
			
		||||
		"v1beta1.Eviction":                    "k8s.io/kubernetes/pkg/apis/policy/v1beta1.Eviction",
 | 
			
		||||
		"v1beta1.StatefulSetList":             "k8s.io/kubernetes/pkg/apis/apps/v1beta1.StatefulSetList",
 | 
			
		||||
		"v1beta1.RoleBinding":                 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.RoleBinding",
 | 
			
		||||
		"v1beta1.PodSecurityPolicyList":       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.PodSecurityPolicyList",
 | 
			
		||||
		"v1.NodeSpec":                         "k8s.io/kubernetes/pkg/api/v1.NodeSpec",
 | 
			
		||||
		"v1.FlockerVolumeSource":              "k8s.io/kubernetes/pkg/api/v1.FlockerVolumeSource",
 | 
			
		||||
		"v1.ContainerState":                   "k8s.io/kubernetes/pkg/api/v1.ContainerState",
 | 
			
		||||
		"v1beta1.ClusterRole":                 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.ClusterRole",
 | 
			
		||||
		"v1beta1.StorageClass":                "k8s.io/kubernetes/pkg/apis/storage/v1beta1.StorageClass",
 | 
			
		||||
		"v1.FlexVolumeSource":                 "k8s.io/kubernetes/pkg/api/v1.FlexVolumeSource",
 | 
			
		||||
		"v1.SecretKeySelector":                "k8s.io/kubernetes/pkg/api/v1.SecretKeySelector",
 | 
			
		||||
		"v1.DeleteOptions":                    "k8s.io/kubernetes/pkg/api/v1.DeleteOptions",
 | 
			
		||||
		"v1.PodStatus":                        "k8s.io/kubernetes/pkg/api/v1.PodStatus",
 | 
			
		||||
		"v1.NodeStatus":                       "k8s.io/kubernetes/pkg/api/v1.NodeStatus",
 | 
			
		||||
		"v1.ServiceSpec":                      "k8s.io/kubernetes/pkg/api/v1.ServiceSpec",
 | 
			
		||||
		"v1.AttachedVolume":                   "k8s.io/kubernetes/pkg/api/v1.AttachedVolume",
 | 
			
		||||
		"v1.PersistentVolume":                 "k8s.io/kubernetes/pkg/api/v1.PersistentVolume",
 | 
			
		||||
		"v1.LimitRangeList":                   "k8s.io/kubernetes/pkg/api/v1.LimitRangeList",
 | 
			
		||||
		"v1alpha1.Role":                       "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.Role",
 | 
			
		||||
		"v1.Affinity":                         "k8s.io/kubernetes/pkg/api/v1.Affinity",
 | 
			
		||||
		"v1beta1.PodDisruptionBudget":         "k8s.io/kubernetes/pkg/apis/policy/v1beta1.PodDisruptionBudget",
 | 
			
		||||
		"v1alpha1.RoleBindingList":            "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.RoleBindingList",
 | 
			
		||||
		"v1.PodAffinity":                      "k8s.io/kubernetes/pkg/api/v1.PodAffinity",
 | 
			
		||||
		"v1beta1.SELinuxStrategyOptions":      "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.SELinuxStrategyOptions",
 | 
			
		||||
		"v1.ResourceQuotaList":                "k8s.io/kubernetes/pkg/api/v1.ResourceQuotaList",
 | 
			
		||||
		"v1.PodList":                          "k8s.io/kubernetes/pkg/api/v1.PodList",
 | 
			
		||||
		"v1.EnvVarSource":                     "k8s.io/kubernetes/pkg/api/v1.EnvVarSource",
 | 
			
		||||
		"v1beta1.TokenReviewStatus":           "k8s.io/kubernetes/pkg/apis/authentication/v1beta1.TokenReviewStatus",
 | 
			
		||||
		"v1.PersistentVolumeClaimList":        "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeClaimList",
 | 
			
		||||
		"v1beta1.RoleList":                    "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.RoleList",
 | 
			
		||||
		"v1.ListMeta":                         "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta",
 | 
			
		||||
		"v1.ObjectMeta":                       "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta",
 | 
			
		||||
		"v1.APIGroupList":                     "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList",
 | 
			
		||||
		"v2alpha1.Job":                        "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.Job",
 | 
			
		||||
		"v1.EnvFromSource":                    "k8s.io/kubernetes/pkg/api/v1.EnvFromSource",
 | 
			
		||||
		"v1beta1.IngressStatus":               "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressStatus",
 | 
			
		||||
		"v1.Service":                          "k8s.io/kubernetes/pkg/api/v1.Service",
 | 
			
		||||
		"v1beta1.DaemonSetStatus":             "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetStatus",
 | 
			
		||||
		"v1alpha1.Subject":                    "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.Subject",
 | 
			
		||||
		"v1.HorizontalPodAutoscaler":          "k8s.io/kubernetes/pkg/apis/autoscaling/v1.HorizontalPodAutoscaler",
 | 
			
		||||
		"v1.StatusCause":                      "k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause",
 | 
			
		||||
		"v1.NodeSelectorRequirement":          "k8s.io/kubernetes/pkg/api/v1.NodeSelectorRequirement",
 | 
			
		||||
		"v1beta1.NetworkPolicyIngressRule":    "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicyIngressRule",
 | 
			
		||||
		"v1beta1.ThirdPartyResource":          "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ThirdPartyResource",
 | 
			
		||||
		"v1beta1.PodSecurityPolicy":           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.PodSecurityPolicy",
 | 
			
		||||
		"v1beta1.StatefulSet":                 "k8s.io/kubernetes/pkg/apis/apps/v1beta1.StatefulSet",
 | 
			
		||||
		"v1.LabelSelector":                    "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector",
 | 
			
		||||
		"v1.ScaleSpec":                        "k8s.io/kubernetes/pkg/apis/autoscaling/v1.ScaleSpec",
 | 
			
		||||
		"v1.DownwardAPIVolumeFile":            "k8s.io/kubernetes/pkg/api/v1.DownwardAPIVolumeFile",
 | 
			
		||||
		"v1beta1.HorizontalPodAutoscaler":     "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HorizontalPodAutoscaler",
 | 
			
		||||
		"v1.AWSElasticBlockStoreVolumeSource": "k8s.io/kubernetes/pkg/api/v1.AWSElasticBlockStoreVolumeSource",
 | 
			
		||||
		"v1.ComponentStatus":                  "k8s.io/kubernetes/pkg/api/v1.ComponentStatus",
 | 
			
		||||
		"v2alpha1.JobSpec":                    "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.JobSpec",
 | 
			
		||||
		"v1.ContainerImage":                   "k8s.io/kubernetes/pkg/api/v1.ContainerImage",
 | 
			
		||||
		"v1.ReplicationControllerStatus":      "k8s.io/kubernetes/pkg/api/v1.ReplicationControllerStatus",
 | 
			
		||||
		"v1.ResourceQuota":                    "k8s.io/kubernetes/pkg/api/v1.ResourceQuota",
 | 
			
		||||
		"v1beta1.NetworkPolicyList":           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicyList",
 | 
			
		||||
		"v1beta1.NonResourceAttributes":       "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.NonResourceAttributes",
 | 
			
		||||
		"v1.JobCondition":                     "k8s.io/kubernetes/pkg/apis/batch/v1.JobCondition",
 | 
			
		||||
		"v1.LabelSelectorRequirement":         "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement",
 | 
			
		||||
		"v1beta1.Deployment":                  "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Deployment",
 | 
			
		||||
		"v1.LoadBalancerIngress":              "k8s.io/kubernetes/pkg/api/v1.LoadBalancerIngress",
 | 
			
		||||
		"v1.SecretList":                       "k8s.io/kubernetes/pkg/api/v1.SecretList",
 | 
			
		||||
		"v1beta1.ReplicaSetSpec":              "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ReplicaSetSpec",
 | 
			
		||||
		"v1beta1.RoleBindingList":             "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.RoleBindingList",
 | 
			
		||||
		"v1.ServicePort":                      "k8s.io/kubernetes/pkg/api/v1.ServicePort",
 | 
			
		||||
		"v1.Namespace":                        "k8s.io/kubernetes/pkg/api/v1.Namespace",
 | 
			
		||||
		"v1beta1.NetworkPolicyPeer":           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicyPeer",
 | 
			
		||||
		"v1.ReplicationControllerList":        "k8s.io/kubernetes/pkg/api/v1.ReplicationControllerList",
 | 
			
		||||
		"v1beta1.ReplicaSetCondition":         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ReplicaSetCondition",
 | 
			
		||||
		"v1.ReplicationControllerCondition":   "k8s.io/kubernetes/pkg/api/v1.ReplicationControllerCondition",
 | 
			
		||||
		"v1.DaemonEndpoint":                   "k8s.io/kubernetes/pkg/api/v1.DaemonEndpoint",
 | 
			
		||||
		"v1beta1.NetworkPolicyPort":           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicyPort",
 | 
			
		||||
		"v1.NodeSystemInfo":                   "k8s.io/kubernetes/pkg/api/v1.NodeSystemInfo",
 | 
			
		||||
		"v1.LimitRangeItem":                   "k8s.io/kubernetes/pkg/api/v1.LimitRangeItem",
 | 
			
		||||
		"v1.ConfigMapVolumeSource":            "k8s.io/kubernetes/pkg/api/v1.ConfigMapVolumeSource",
 | 
			
		||||
		"v1beta1.ClusterRoleList":             "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.ClusterRoleList",
 | 
			
		||||
		"v1beta1.ResourceAttributes":          "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.ResourceAttributes",
 | 
			
		||||
		"v1.Pod":                              "k8s.io/kubernetes/pkg/api/v1.Pod",
 | 
			
		||||
		"v1.FCVolumeSource":                   "k8s.io/kubernetes/pkg/api/v1.FCVolumeSource",
 | 
			
		||||
		"v1beta1.SubresourceReference":        "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.SubresourceReference",
 | 
			
		||||
		"v1.ResourceQuotaStatus":              "k8s.io/kubernetes/pkg/api/v1.ResourceQuotaStatus",
 | 
			
		||||
		"v1alpha1.RoleBinding":                "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.RoleBinding",
 | 
			
		||||
		"v1.PodCondition":                     "k8s.io/kubernetes/pkg/api/v1.PodCondition",
 | 
			
		||||
		"v1.GroupVersionForDiscovery":         "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery",
 | 
			
		||||
		"v1.NamespaceStatus":                  "k8s.io/kubernetes/pkg/api/v1.NamespaceStatus",
 | 
			
		||||
		"v1.Job":                              "k8s.io/kubernetes/pkg/apis/batch/v1.Job",
 | 
			
		||||
		"v1.PersistentVolumeClaimVolumeSource":        "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeClaimVolumeSource",
 | 
			
		||||
		"v1.Handler":                                  "k8s.io/kubernetes/pkg/api/v1.Handler",
 | 
			
		||||
		"v1.ComponentStatusList":                      "k8s.io/kubernetes/pkg/api/v1.ComponentStatusList",
 | 
			
		||||
		"v1.ServerAddressByClientCIDR":                "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR",
 | 
			
		||||
		"v1.PodAntiAffinity":                          "k8s.io/kubernetes/pkg/api/v1.PodAntiAffinity",
 | 
			
		||||
		"v1.ISCSIVolumeSource":                        "k8s.io/kubernetes/pkg/api/v1.ISCSIVolumeSource",
 | 
			
		||||
		"v1.ContainerStateRunning":                    "k8s.io/kubernetes/pkg/api/v1.ContainerStateRunning",
 | 
			
		||||
		"v1.WeightedPodAffinityTerm":                  "k8s.io/kubernetes/pkg/api/v1.WeightedPodAffinityTerm",
 | 
			
		||||
		"v1beta1.HostPortRange":                       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HostPortRange",
 | 
			
		||||
		"v1.HorizontalPodAutoscalerSpec":              "k8s.io/kubernetes/pkg/apis/autoscaling/v1.HorizontalPodAutoscalerSpec",
 | 
			
		||||
		"v1.HorizontalPodAutoscalerList":              "k8s.io/kubernetes/pkg/apis/autoscaling/v1.HorizontalPodAutoscalerList",
 | 
			
		||||
		"v1beta1.RoleRef":                             "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.RoleRef",
 | 
			
		||||
		"v1.Probe":                                    "k8s.io/kubernetes/pkg/api/v1.Probe",
 | 
			
		||||
		"v1beta1.IngressTLS":                          "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressTLS",
 | 
			
		||||
		"v1beta1.ThirdPartyResourceList":              "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ThirdPartyResourceList",
 | 
			
		||||
		"v1beta1.DaemonSet":                           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSet",
 | 
			
		||||
		"v1.APIGroup":                                 "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup",
 | 
			
		||||
		"v1beta1.Subject":                             "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.Subject",
 | 
			
		||||
		"v1beta1.DeploymentList":                      "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentList",
 | 
			
		||||
		"v1.NodeAffinity":                             "k8s.io/kubernetes/pkg/api/v1.NodeAffinity",
 | 
			
		||||
		"v1beta1.RollingUpdateDeployment":             "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollingUpdateDeployment",
 | 
			
		||||
		"v1beta1.APIVersion":                          "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.APIVersion",
 | 
			
		||||
		"v1alpha1.CertificateSigningRequest":          "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1.CertificateSigningRequest",
 | 
			
		||||
		"v1.CinderVolumeSource":                       "k8s.io/kubernetes/pkg/api/v1.CinderVolumeSource",
 | 
			
		||||
		"v1.NamespaceSpec":                            "k8s.io/kubernetes/pkg/api/v1.NamespaceSpec",
 | 
			
		||||
		"v1beta1.PodDisruptionBudgetSpec":             "k8s.io/kubernetes/pkg/apis/policy/v1beta1.PodDisruptionBudgetSpec",
 | 
			
		||||
		"v1.Patch":                                    "k8s.io/apimachinery/pkg/apis/meta/v1.Patch",
 | 
			
		||||
		"v1beta1.ClusterRoleBinding":                  "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.ClusterRoleBinding",
 | 
			
		||||
		"v1beta1.HorizontalPodAutoscalerSpec":         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HorizontalPodAutoscalerSpec",
 | 
			
		||||
		"v1.PersistentVolumeClaimSpec":                "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeClaimSpec",
 | 
			
		||||
		"v1.Secret":                                   "k8s.io/kubernetes/pkg/api/v1.Secret",
 | 
			
		||||
		"v1.NodeCondition":                            "k8s.io/kubernetes/pkg/api/v1.NodeCondition",
 | 
			
		||||
		"v1.LocalObjectReference":                     "k8s.io/kubernetes/pkg/api/v1.LocalObjectReference",
 | 
			
		||||
		"runtime.RawExtension":                        "k8s.io/apimachinery/pkg/runtime.RawExtension",
 | 
			
		||||
		"v1.PreferredSchedulingTerm":                  "k8s.io/kubernetes/pkg/api/v1.PreferredSchedulingTerm",
 | 
			
		||||
		"v1.RBDVolumeSource":                          "k8s.io/kubernetes/pkg/api/v1.RBDVolumeSource",
 | 
			
		||||
		"v1.KeyToPath":                                "k8s.io/kubernetes/pkg/api/v1.KeyToPath",
 | 
			
		||||
		"v1.ScaleStatus":                              "k8s.io/kubernetes/pkg/apis/autoscaling/v1.ScaleStatus",
 | 
			
		||||
		"v1alpha1.PolicyRule":                         "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.PolicyRule",
 | 
			
		||||
		"v1.EndpointPort":                             "k8s.io/kubernetes/pkg/api/v1.EndpointPort",
 | 
			
		||||
		"v1beta1.IngressList":                         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressList",
 | 
			
		||||
		"v1.EndpointAddress":                          "k8s.io/kubernetes/pkg/api/v1.EndpointAddress",
 | 
			
		||||
		"v1.NodeSelector":                             "k8s.io/kubernetes/pkg/api/v1.NodeSelector",
 | 
			
		||||
		"v1beta1.StorageClassList":                    "k8s.io/kubernetes/pkg/apis/storage/v1beta1.StorageClassList",
 | 
			
		||||
		"v1.ServiceList":                              "k8s.io/kubernetes/pkg/api/v1.ServiceList",
 | 
			
		||||
		"v2alpha1.CronJobSpec":                        "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.CronJobSpec",
 | 
			
		||||
		"v1.ContainerStateTerminated":                 "k8s.io/kubernetes/pkg/api/v1.ContainerStateTerminated",
 | 
			
		||||
		"v1beta1.TokenReview":                         "k8s.io/kubernetes/pkg/apis/authentication/v1beta1.TokenReview",
 | 
			
		||||
		"v1beta1.IngressBackend":                      "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressBackend",
 | 
			
		||||
		"v1.Time":                                     "k8s.io/apimachinery/pkg/apis/meta/v1.Time",
 | 
			
		||||
		"v1beta1.IngressSpec":                         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressSpec",
 | 
			
		||||
		"v2alpha1.JobTemplateSpec":                    "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.JobTemplateSpec",
 | 
			
		||||
		"v1.LimitRange":                               "k8s.io/kubernetes/pkg/api/v1.LimitRange",
 | 
			
		||||
		"v1beta1.UserInfo":                            "k8s.io/kubernetes/pkg/apis/authentication/v1beta1.UserInfo",
 | 
			
		||||
		"v1.ResourceQuotaSpec":                        "k8s.io/kubernetes/pkg/api/v1.ResourceQuotaSpec",
 | 
			
		||||
		"v1.ContainerPort":                            "k8s.io/kubernetes/pkg/api/v1.ContainerPort",
 | 
			
		||||
		"v1beta1.HTTPIngressRuleValue":                "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HTTPIngressRuleValue",
 | 
			
		||||
		"v1.AzureFileVolumeSource":                    "k8s.io/kubernetes/pkg/api/v1.AzureFileVolumeSource",
 | 
			
		||||
		"v1beta1.NetworkPolicySpec":                   "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicySpec",
 | 
			
		||||
		"v1.PodTemplateSpec":                          "k8s.io/kubernetes/pkg/api/v1.PodTemplateSpec",
 | 
			
		||||
		"v1.SecretVolumeSource":                       "k8s.io/kubernetes/pkg/api/v1.SecretVolumeSource",
 | 
			
		||||
		"v1.PodSpec":                                  "k8s.io/kubernetes/pkg/api/v1.PodSpec",
 | 
			
		||||
		"v1.CephFSVolumeSource":                       "k8s.io/kubernetes/pkg/api/v1.CephFSVolumeSource",
 | 
			
		||||
		"v1beta1.CPUTargetUtilization":                "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.CPUTargetUtilization",
 | 
			
		||||
		"v1.Volume":                                   "k8s.io/kubernetes/pkg/api/v1.Volume",
 | 
			
		||||
		"v1beta1.Ingress":                             "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Ingress",
 | 
			
		||||
		"v1beta1.HorizontalPodAutoscalerList":         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HorizontalPodAutoscalerList",
 | 
			
		||||
		"v1.PersistentVolumeStatus":                   "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeStatus",
 | 
			
		||||
		"v1beta1.IDRange":                             "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IDRange",
 | 
			
		||||
		"v2alpha1.JobCondition":                       "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.JobCondition",
 | 
			
		||||
		"v1beta1.IngressRule":                         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.IngressRule",
 | 
			
		||||
		"v1alpha1.RoleRef":                            "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.RoleRef",
 | 
			
		||||
		"v1.PodAffinityTerm":                          "k8s.io/kubernetes/pkg/api/v1.PodAffinityTerm",
 | 
			
		||||
		"v1.ObjectReference":                          "k8s.io/kubernetes/pkg/api/v1.ObjectReference",
 | 
			
		||||
		"v1.ServiceStatus":                            "k8s.io/kubernetes/pkg/api/v1.ServiceStatus",
 | 
			
		||||
		"v1.APIResource":                              "k8s.io/apimachinery/pkg/apis/meta/v1.APIResource",
 | 
			
		||||
		"v1beta1.Scale":                               "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale",
 | 
			
		||||
		"v1.AzureDiskVolumeSource":                    "k8s.io/kubernetes/pkg/api/v1.AzureDiskVolumeSource",
 | 
			
		||||
		"v1beta1.SubjectAccessReviewStatus":           "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.SubjectAccessReviewStatus",
 | 
			
		||||
		"v1.ConfigMap":                                "k8s.io/kubernetes/pkg/api/v1.ConfigMap",
 | 
			
		||||
		"v1.CrossVersionObjectReference":              "k8s.io/kubernetes/pkg/apis/autoscaling/v1.CrossVersionObjectReference",
 | 
			
		||||
		"v1.APIVersions":                              "k8s.io/apimachinery/pkg/apis/meta/v1.APIVersions",
 | 
			
		||||
		"v1alpha1.ClusterRoleList":                    "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.ClusterRoleList",
 | 
			
		||||
		"v1.Node":                                     "k8s.io/kubernetes/pkg/api/v1.Node",
 | 
			
		||||
		"resource.Quantity":                           "k8s.io/kubernetes/pkg/api/resource.Quantity",
 | 
			
		||||
		"v1.Event":                                    "k8s.io/kubernetes/pkg/api/v1.Event",
 | 
			
		||||
		"v1.JobStatus":                                "k8s.io/kubernetes/pkg/apis/batch/v1.JobStatus",
 | 
			
		||||
		"v1.PersistentVolumeSpec":                     "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeSpec",
 | 
			
		||||
		"v1beta1.SubjectAccessReviewSpec":             "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.SubjectAccessReviewSpec",
 | 
			
		||||
		"v1.ResourceFieldSelector":                    "k8s.io/kubernetes/pkg/api/v1.ResourceFieldSelector",
 | 
			
		||||
		"v1.EndpointSubset":                           "k8s.io/kubernetes/pkg/api/v1.EndpointSubset",
 | 
			
		||||
		"v1alpha1.CertificateSigningRequestSpec":      "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1.CertificateSigningRequestSpec",
 | 
			
		||||
		"v1.HostPathVolumeSource":                     "k8s.io/kubernetes/pkg/api/v1.HostPathVolumeSource",
 | 
			
		||||
		"v1.LoadBalancerStatus":                       "k8s.io/kubernetes/pkg/api/v1.LoadBalancerStatus",
 | 
			
		||||
		"v1beta1.HTTPIngressPath":                     "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HTTPIngressPath",
 | 
			
		||||
		"v1beta1.Role":                                "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.Role",
 | 
			
		||||
		"v1beta1.DeploymentStrategy":                  "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentStrategy",
 | 
			
		||||
		"v1beta1.RunAsUserStrategyOptions":            "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RunAsUserStrategyOptions",
 | 
			
		||||
		"v1beta1.DeploymentSpec":                      "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentSpec",
 | 
			
		||||
		"v1.ExecAction":                               "k8s.io/kubernetes/pkg/api/v1.ExecAction",
 | 
			
		||||
		"v1beta1.PodSecurityPolicySpec":               "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.PodSecurityPolicySpec",
 | 
			
		||||
		"v1.HorizontalPodAutoscalerStatus":            "k8s.io/kubernetes/pkg/apis/autoscaling/v1.HorizontalPodAutoscalerStatus",
 | 
			
		||||
		"v1.PersistentVolumeList":                     "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeList",
 | 
			
		||||
		"v1alpha1.ClusterRole":                        "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.ClusterRole",
 | 
			
		||||
		"v1.JobSpec":                                  "k8s.io/kubernetes/pkg/apis/batch/v1.JobSpec",
 | 
			
		||||
		"v1beta1.DaemonSetSpec":                       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetSpec",
 | 
			
		||||
		"v2alpha1.CronJobList":                        "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.CronJobList",
 | 
			
		||||
		"v1.Endpoints":                                "k8s.io/kubernetes/pkg/api/v1.Endpoints",
 | 
			
		||||
		"v1.SELinuxOptions":                           "k8s.io/kubernetes/pkg/api/v1.SELinuxOptions",
 | 
			
		||||
		"v1beta1.SelfSubjectAccessReviewSpec":         "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.SelfSubjectAccessReviewSpec",
 | 
			
		||||
		"v1beta1.ScaleStatus":                         "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ScaleStatus",
 | 
			
		||||
		"v1.NodeSelectorTerm":                         "k8s.io/kubernetes/pkg/api/v1.NodeSelectorTerm",
 | 
			
		||||
		"v1alpha1.CertificateSigningRequestStatus":    "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1.CertificateSigningRequestStatus",
 | 
			
		||||
		"v1.StatusDetails":                            "k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails",
 | 
			
		||||
		"v2alpha1.JobStatus":                          "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.JobStatus",
 | 
			
		||||
		"v1beta1.DeploymentRollback":                  "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentRollback",
 | 
			
		||||
		"v1.GlusterfsVolumeSource":                    "k8s.io/kubernetes/pkg/api/v1.GlusterfsVolumeSource",
 | 
			
		||||
		"v1.ServiceAccountList":                       "k8s.io/kubernetes/pkg/api/v1.ServiceAccountList",
 | 
			
		||||
		"v1.JobList":                                  "k8s.io/kubernetes/pkg/apis/batch/v1.JobList",
 | 
			
		||||
		"v1.EventList":                                "k8s.io/kubernetes/pkg/api/v1.EventList",
 | 
			
		||||
		"v1.ContainerStateWaiting":                    "k8s.io/kubernetes/pkg/api/v1.ContainerStateWaiting",
 | 
			
		||||
		"v1.APIResourceList":                          "k8s.io/apimachinery/pkg/apis/meta/v1.APIResourceList",
 | 
			
		||||
		"v1.ContainerStatus":                          "k8s.io/kubernetes/pkg/api/v1.ContainerStatus",
 | 
			
		||||
		"v2alpha1.JobList":                            "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.JobList",
 | 
			
		||||
		"v1.ConfigMapKeySelector":                     "k8s.io/kubernetes/pkg/api/v1.ConfigMapKeySelector",
 | 
			
		||||
		"v1.PhotonPersistentDiskVolumeSource":         "k8s.io/kubernetes/pkg/api/v1.PhotonPersistentDiskVolumeSource",
 | 
			
		||||
		"v1.PodTemplateList":                          "k8s.io/kubernetes/pkg/api/v1.PodTemplateList",
 | 
			
		||||
		"v1.PersistentVolumeClaimStatus":              "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeClaimStatus",
 | 
			
		||||
		"v1.ServiceAccount":                           "k8s.io/kubernetes/pkg/api/v1.ServiceAccount",
 | 
			
		||||
		"v1alpha1.CertificateSigningRequestList":      "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1.CertificateSigningRequestList",
 | 
			
		||||
		"v1beta1.SupplementalGroupsStrategyOptions":   "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.SupplementalGroupsStrategyOptions",
 | 
			
		||||
		"v1.HTTPHeader":                               "k8s.io/kubernetes/pkg/api/v1.HTTPHeader",
 | 
			
		||||
		"version.Info":                                "k8s.io/apimachinery/pkg/version.Info",
 | 
			
		||||
		"v1.EventSource":                              "k8s.io/kubernetes/pkg/api/v1.EventSource",
 | 
			
		||||
		"v1alpha1.ClusterRoleBindingList":             "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.ClusterRoleBindingList",
 | 
			
		||||
		"v1.OwnerReference":                           "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference",
 | 
			
		||||
		"v1beta1.ClusterRoleBindingList":              "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.ClusterRoleBindingList",
 | 
			
		||||
		"v1beta1.ScaleSpec":                           "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ScaleSpec",
 | 
			
		||||
		"v1.GitRepoVolumeSource":                      "k8s.io/kubernetes/pkg/api/v1.GitRepoVolumeSource",
 | 
			
		||||
		"v1beta1.NetworkPolicy":                       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.NetworkPolicy",
 | 
			
		||||
		"v1.ConfigMapEnvSource":                       "k8s.io/kubernetes/pkg/api/v1.ConfigMapEnvSource",
 | 
			
		||||
		"v1.PodTemplate":                              "k8s.io/kubernetes/pkg/api/v1.PodTemplate",
 | 
			
		||||
		"v1beta1.DeploymentCondition":                 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DeploymentCondition",
 | 
			
		||||
		"v1beta1.PodDisruptionBudgetStatus":           "k8s.io/kubernetes/pkg/apis/policy/v1beta1.PodDisruptionBudgetStatus",
 | 
			
		||||
		"v1.EnvVar":                                   "k8s.io/kubernetes/pkg/api/v1.EnvVar",
 | 
			
		||||
		"v1.LimitRangeSpec":                           "k8s.io/kubernetes/pkg/api/v1.LimitRangeSpec",
 | 
			
		||||
		"v1.DownwardAPIVolumeSource":                  "k8s.io/kubernetes/pkg/api/v1.DownwardAPIVolumeSource",
 | 
			
		||||
		"v1.NodeDaemonEndpoints":                      "k8s.io/kubernetes/pkg/api/v1.NodeDaemonEndpoints",
 | 
			
		||||
		"v1.ComponentCondition":                       "k8s.io/kubernetes/pkg/api/v1.ComponentCondition",
 | 
			
		||||
		"v1alpha1.CertificateSigningRequestCondition": "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1.CertificateSigningRequestCondition",
 | 
			
		||||
		"v1.SecurityContext":                          "k8s.io/kubernetes/pkg/api/v1.SecurityContext",
 | 
			
		||||
		"v1beta1.LocalSubjectAccessReview":            "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.LocalSubjectAccessReview",
 | 
			
		||||
		"v1beta1.StatefulSetSpec":                     "k8s.io/kubernetes/pkg/apis/apps/v1beta1.StatefulSetSpec",
 | 
			
		||||
		"v1.NodeAddress":                              "k8s.io/kubernetes/pkg/api/v1.NodeAddress",
 | 
			
		||||
		"v1.QuobyteVolumeSource":                      "k8s.io/kubernetes/pkg/api/v1.QuobyteVolumeSource",
 | 
			
		||||
		"v1.Capabilities":                             "k8s.io/kubernetes/pkg/api/v1.Capabilities",
 | 
			
		||||
		"v1.GCEPersistentDiskVolumeSource":            "k8s.io/kubernetes/pkg/api/v1.GCEPersistentDiskVolumeSource",
 | 
			
		||||
		"v1beta1.ReplicaSet":                          "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ReplicaSet",
 | 
			
		||||
		"v1beta1.HorizontalPodAutoscalerStatus":       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.HorizontalPodAutoscalerStatus",
 | 
			
		||||
		"v1beta1.PolicyRule":                          "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.PolicyRule",
 | 
			
		||||
		"v1.ConfigMapList":                            "k8s.io/kubernetes/pkg/api/v1.ConfigMapList",
 | 
			
		||||
		"v1.Lifecycle":                                "k8s.io/kubernetes/pkg/api/v1.Lifecycle",
 | 
			
		||||
		"v1beta1.SelfSubjectAccessReview":             "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.SelfSubjectAccessReview",
 | 
			
		||||
		"v2alpha1.CronJob":                            "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.CronJob",
 | 
			
		||||
		"v2alpha1.CronJobStatus":                      "k8s.io/kubernetes/pkg/apis/batch/v2alpha1.CronJobStatus",
 | 
			
		||||
		"v1beta1.SubjectAccessReview":                 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.SubjectAccessReview",
 | 
			
		||||
		"v1.Preconditions":                            "k8s.io/kubernetes/pkg/api/v1.Preconditions",
 | 
			
		||||
		"v1beta1.DaemonSetList":                       "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetList",
 | 
			
		||||
		"v1.PersistentVolumeClaim":                    "k8s.io/kubernetes/pkg/api/v1.PersistentVolumeClaim",
 | 
			
		||||
		"v1.Scale":                                    "k8s.io/kubernetes/pkg/apis/autoscaling/v1.Scale",
 | 
			
		||||
		"v1beta1.StatefulSetStatus":                   "k8s.io/kubernetes/pkg/apis/apps/v1beta1.StatefulSetStatus",
 | 
			
		||||
		"v1.NFSVolumeSource":                          "k8s.io/kubernetes/pkg/api/v1.NFSVolumeSource",
 | 
			
		||||
		"v1.ObjectFieldSelector":                      "k8s.io/kubernetes/pkg/api/v1.ObjectFieldSelector",
 | 
			
		||||
		"v1.ResourceRequirements":                     "k8s.io/kubernetes/pkg/api/v1.ResourceRequirements",
 | 
			
		||||
		"v1.WatchEvent":                               "k8s.io/apimachinery/pkg/apis/meta/v1.WatchEvent",
 | 
			
		||||
		"v1.ReplicationControllerSpec":                "k8s.io/kubernetes/pkg/api/v1.ReplicationControllerSpec",
 | 
			
		||||
		"v1.HTTPGetAction":                            "k8s.io/kubernetes/pkg/api/v1.HTTPGetAction",
 | 
			
		||||
		"v1beta1.RollbackConfig":                      "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollbackConfig",
 | 
			
		||||
		"v1beta1.TokenReviewSpec":                     "k8s.io/kubernetes/pkg/apis/authentication/v1beta1.TokenReviewSpec",
 | 
			
		||||
		"v1.PodSecurityContext":                       "k8s.io/kubernetes/pkg/api/v1.PodSecurityContext",
 | 
			
		||||
		"v1beta1.PodDisruptionBudgetList":             "k8s.io/kubernetes/pkg/apis/policy/v1beta1.PodDisruptionBudgetList",
 | 
			
		||||
		"v1.VolumeMount":                              "k8s.io/kubernetes/pkg/api/v1.VolumeMount",
 | 
			
		||||
		"v1.ReplicationController":                    "k8s.io/kubernetes/pkg/api/v1.ReplicationController",
 | 
			
		||||
		"v1.NamespaceList":                            "k8s.io/kubernetes/pkg/api/v1.NamespaceList",
 | 
			
		||||
		"v1alpha1.ClusterRoleBinding":                 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.ClusterRoleBinding",
 | 
			
		||||
		"v1.TCPSocketAction":                          "k8s.io/kubernetes/pkg/api/v1.TCPSocketAction",
 | 
			
		||||
		"v1.Binding":                                  "k8s.io/kubernetes/pkg/api/v1.Binding",
 | 
			
		||||
		"v1beta1.ReplicaSetStatus":                    "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.ReplicaSetStatus",
 | 
			
		||||
		"intstr.IntOrString":                          "k8s.io/kubernetes/pkg/util/intstr.IntOrString",
 | 
			
		||||
		"v1.EndpointsList":                            "k8s.io/kubernetes/pkg/api/v1.EndpointsList",
 | 
			
		||||
		"v1.Container":                                "k8s.io/kubernetes/pkg/api/v1.Container",
 | 
			
		||||
		"v1alpha1.RoleList":                           "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1.RoleList",
 | 
			
		||||
		"v1.VsphereVirtualDiskVolumeSource":           "k8s.io/kubernetes/pkg/api/v1.VsphereVirtualDiskVolumeSource",
 | 
			
		||||
		"v1.NodeList":                                 "k8s.io/kubernetes/pkg/api/v1.NodeList",
 | 
			
		||||
		"v1.EmptyDirVolumeSource":                     "k8s.io/kubernetes/pkg/api/v1.EmptyDirVolumeSource",
 | 
			
		||||
		"v1beta1.FSGroupStrategyOptions":              "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.FSGroupStrategyOptions",
 | 
			
		||||
		"v1.Status":                                   "k8s.io/apimachinery/pkg/apis/meta/v1.Status",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, v := range compatibilityMap {
 | 
			
		||||
		if _, found := s.Definitions[v]; !found {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		s.Definitions[k] = spec.Schema{
 | 
			
		||||
			SchemaProps: spec.SchemaProps{
 | 
			
		||||
				Ref:         spec.MustCreateRef("#/definitions/" + openapi.EscapeJsonPointer(v)),
 | 
			
		||||
				Description: fmt.Sprintf("Deprecated. Please use %s instead.", v),
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										86
									
								
								pkg/genericapiserver/endpoints/openapi/openapi_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								pkg/genericapiserver/endpoints/openapi/openapi_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2016 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package openapi
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-openapi/spec"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TestType struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t TestType) GetObjectKind() schema.ObjectKind {
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t TestType) SetGroupVersionKind(kind schema.GroupVersionKind) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t TestType) GroupVersionKind() schema.GroupVersionKind {
 | 
			
		||||
	return schema.GroupVersionKind{
 | 
			
		||||
		Group:   "test",
 | 
			
		||||
		Version: "v1",
 | 
			
		||||
		Kind:    "TestType",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func assertEqual(t *testing.T, expected, actual interface{}) {
 | 
			
		||||
	var equal bool
 | 
			
		||||
	if expected == nil || actual == nil {
 | 
			
		||||
		equal = expected == actual
 | 
			
		||||
	} else {
 | 
			
		||||
		equal = reflect.DeepEqual(expected, actual)
 | 
			
		||||
	}
 | 
			
		||||
	if !equal {
 | 
			
		||||
		t.Errorf("%v != %v", expected, actual)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetDefinitionName(t *testing.T) {
 | 
			
		||||
	testType := TestType{}
 | 
			
		||||
	typePkgName := "k8s.io/kubernetes/pkg/genericapiserver/endpoints/openapi.TestType"
 | 
			
		||||
	typeFriendlyName := "io.k8s.kubernetes.pkg.genericapiserver.endpoints.openapi.TestType"
 | 
			
		||||
	if strings.HasSuffix(reflect.TypeOf(testType).PkgPath(), "go_default_test") {
 | 
			
		||||
		// the test is running inside bazel where the package name is changed and
 | 
			
		||||
		// "go_default_test" will add to package path.
 | 
			
		||||
		typePkgName = "k8s.io/kubernetes/pkg/genericapiserver/endpoints/openapi/go_default_test.TestType"
 | 
			
		||||
		typeFriendlyName = "io.k8s.kubernetes.pkg.genericapiserver.endpoints.openapi.go_default_test.TestType"
 | 
			
		||||
	}
 | 
			
		||||
	s := runtime.NewScheme()
 | 
			
		||||
	s.AddKnownTypeWithName(testType.GroupVersionKind(), &testType)
 | 
			
		||||
	namer := NewDefinitionNamer(s)
 | 
			
		||||
	n, e := namer.GetDefinitionName("", typePkgName)
 | 
			
		||||
	assertEqual(t, typeFriendlyName, n)
 | 
			
		||||
	assertEqual(t, e["x-kubernetes-group-version-kind"], []v1.GroupVersionKind{
 | 
			
		||||
		{
 | 
			
		||||
			Group:   "test",
 | 
			
		||||
			Version: "v1",
 | 
			
		||||
			Kind:    "TestType",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	n, e2 := namer.GetDefinitionName("", "test.com/another.Type")
 | 
			
		||||
	assertEqual(t, "com.test.another.Type", n)
 | 
			
		||||
	assertEqual(t, e2, spec.Extensions(nil))
 | 
			
		||||
}
 | 
			
		||||
@@ -213,7 +213,8 @@ func NewConfig() *Config {
 | 
			
		||||
	return config.ApplyOptions(defaultOptions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DefaultOpenAPIConfig(definitions *openapicommon.OpenAPIDefinitions) *openapicommon.Config {
 | 
			
		||||
func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions) *openapicommon.Config {
 | 
			
		||||
	defNamer := apiopenapi.NewDefinitionNamer(api.Scheme)
 | 
			
		||||
	return &openapicommon.Config{
 | 
			
		||||
		ProtocolList:   []string{"https"},
 | 
			
		||||
		IgnorePrefixes: []string{"/swaggerapi"},
 | 
			
		||||
@@ -228,7 +229,9 @@ func DefaultOpenAPIConfig(definitions *openapicommon.OpenAPIDefinitions) *openap
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		GetOperationIDAndTags: apiopenapi.GetOperationIDAndTags,
 | 
			
		||||
		Definitions:           definitions,
 | 
			
		||||
		GetDefinitionName:     defNamer.GetDefinitionName,
 | 
			
		||||
		GetDefinitions:        getDefinitions,
 | 
			
		||||
		PostProcessSpec:       apiopenapi.PostProcessSpec,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
 | 
			
		||||
	config.RequestContextMapper = genericapirequest.NewRequestContextMapper()
 | 
			
		||||
	config.LegacyAPIGroupPrefixes = sets.NewString("/api")
 | 
			
		||||
 | 
			
		||||
	config.OpenAPIConfig = DefaultOpenAPIConfig(openapigen.OpenAPIDefinitions)
 | 
			
		||||
	config.OpenAPIConfig = DefaultOpenAPIConfig(openapigen.GetOpenAPIDefinitions)
 | 
			
		||||
	config.OpenAPIConfig.Info = &spec.Info{
 | 
			
		||||
		InfoProps: spec.InfoProps{
 | 
			
		||||
			Title:   "Kubernetes",
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ type openAPI struct {
 | 
			
		||||
	swagger      *spec.Swagger
 | 
			
		||||
	protocolList []string
 | 
			
		||||
	servePath    string
 | 
			
		||||
	definitions  map[string]openapi.OpenAPIDefinition
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegisterOpenAPIService registers a handler to provides standard OpenAPI specification.
 | 
			
		||||
@@ -79,6 +80,15 @@ func (o *openAPI) init(webServices []*restful.WebService) error {
 | 
			
		||||
			return r.Operation, nil, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if o.config.GetDefinitionName == nil {
 | 
			
		||||
		o.config.GetDefinitionName = func(_, name string) (string, spec.Extensions) {
 | 
			
		||||
			return name[strings.LastIndex(name, "/")+1:], nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
 | 
			
		||||
		defName, _ := o.config.GetDefinitionName(o.servePath, name)
 | 
			
		||||
		return spec.MustCreateRef("#/definitions/" + openapi.EscapeJsonPointer(defName))
 | 
			
		||||
	})
 | 
			
		||||
	if o.config.CommonResponses == nil {
 | 
			
		||||
		o.config.CommonResponses = map[int]spec.Response{}
 | 
			
		||||
	}
 | 
			
		||||
@@ -90,15 +100,43 @@ func (o *openAPI) init(webServices []*restful.WebService) error {
 | 
			
		||||
		o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions
 | 
			
		||||
		o.swagger.Security = o.config.DefaultSecurity
 | 
			
		||||
	}
 | 
			
		||||
	if o.config.PostProcessSpec != nil {
 | 
			
		||||
		o.swagger, err = o.config.PostProcessSpec(o.swagger)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCanonicalizeTypeName(t reflect.Type) string {
 | 
			
		||||
	if t.PkgPath() == "" {
 | 
			
		||||
		return t.Name()
 | 
			
		||||
	}
 | 
			
		||||
	path := t.PkgPath()
 | 
			
		||||
	if strings.Contains(path, "/vendor/") {
 | 
			
		||||
		path = path[strings.Index(path, "/vendor/")+len("/vendor/"):]
 | 
			
		||||
	}
 | 
			
		||||
	return path + "." + t.Name()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
 | 
			
		||||
	if _, ok := o.swagger.Definitions[name]; ok {
 | 
			
		||||
	uniqueName, extensions := o.config.GetDefinitionName(o.servePath, name)
 | 
			
		||||
	if _, ok := o.swagger.Definitions[uniqueName]; ok {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if item, ok := (*o.config.Definitions)[name]; ok {
 | 
			
		||||
		o.swagger.Definitions[name] = item.Schema
 | 
			
		||||
	if item, ok := o.definitions[name]; ok {
 | 
			
		||||
		schema := spec.Schema{
 | 
			
		||||
			SchemaProps:        item.Schema.SchemaProps,
 | 
			
		||||
			SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
 | 
			
		||||
		}
 | 
			
		||||
		if extensions != nil {
 | 
			
		||||
			schema.Extensions = spec.Extensions{}
 | 
			
		||||
			for k, v := range extensions {
 | 
			
		||||
				schema.Extensions[k] = v
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		o.swagger.Definitions[uniqueName] = schema
 | 
			
		||||
		for _, v := range item.Dependencies {
 | 
			
		||||
			if err := o.buildDefinitionRecursively(v); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
@@ -118,11 +156,12 @@ func (o *openAPI) buildDefinitionForType(sample interface{}) (string, error) {
 | 
			
		||||
	if t.Kind() == reflect.Ptr {
 | 
			
		||||
		t = t.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	name := t.String()
 | 
			
		||||
	name := getCanonicalizeTypeName(t)
 | 
			
		||||
	if err := o.buildDefinitionRecursively(name); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return "#/definitions/" + name, nil
 | 
			
		||||
	defName, _ := o.config.GetDefinitionName(o.servePath, name)
 | 
			
		||||
	return "#/definitions/" + openapi.EscapeJsonPointer(defName), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// buildPaths builds OpenAPI paths using go-restful's web services.
 | 
			
		||||
@@ -244,18 +283,12 @@ func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map
 | 
			
		||||
	if len(ret.Responses.StatusCodeResponses) == 0 {
 | 
			
		||||
		ret.Responses.Default = o.config.DefaultResponse
 | 
			
		||||
	}
 | 
			
		||||
	// If there is a read sample, there will be a body param referring to it.
 | 
			
		||||
	if route.ReadSample != nil {
 | 
			
		||||
		if _, err := o.toSchema(reflect.TypeOf(route.ReadSample).String(), route.ReadSample); err != nil {
 | 
			
		||||
			return ret, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Build non-common Parameters
 | 
			
		||||
	ret.Parameters = make([]spec.Parameter, 0)
 | 
			
		||||
	for _, param := range route.ParameterDocs {
 | 
			
		||||
		if _, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]; !isCommon {
 | 
			
		||||
			openAPIParam, err := o.buildParameter(param.Data())
 | 
			
		||||
			openAPIParam, err := o.buildParameter(param.Data(), route.ReadSample)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return ret, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -266,8 +299,7 @@ func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *openAPI) buildResponse(model interface{}, description string) (spec.Response, error) {
 | 
			
		||||
	typeName := reflect.TypeOf(model).String()
 | 
			
		||||
	schema, err := o.toSchema(typeName, model)
 | 
			
		||||
	schema, err := o.toSchema(model)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return spec.Response{}, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -300,8 +332,9 @@ func (o *openAPI) findCommonParameters(routes []restful.Route) (map[interface{}]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for key, count := range paramOpsCountByName {
 | 
			
		||||
		if count == len(routes) {
 | 
			
		||||
			openAPIParam, err := o.buildParameter(paramNameKindToDataMap[key])
 | 
			
		||||
		paramData := paramNameKindToDataMap[key]
 | 
			
		||||
		if count == len(routes) && paramData.Kind != restful.BodyParameterKind {
 | 
			
		||||
			openAPIParam, err := o.buildParameter(paramData, nil)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return commonParamsMap, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -311,8 +344,8 @@ func (o *openAPI) findCommonParameters(routes []restful.Route) (map[interface{}]
 | 
			
		||||
	return commonParamsMap, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *openAPI) toSchema(typeName string, model interface{}) (_ *spec.Schema, err error) {
 | 
			
		||||
	if openAPIType, openAPIFormat := openapi.GetOpenAPITypeFormat(typeName); openAPIType != "" {
 | 
			
		||||
func (o *openAPI) toSchema(model interface{}) (_ *spec.Schema, err error) {
 | 
			
		||||
	if openAPIType, openAPIFormat := openapi.GetOpenAPITypeFormat(getCanonicalizeTypeName(reflect.TypeOf(model))); openAPIType != "" {
 | 
			
		||||
		return &spec.Schema{
 | 
			
		||||
			SchemaProps: spec.SchemaProps{
 | 
			
		||||
				Type:   []string{openAPIType},
 | 
			
		||||
@@ -320,13 +353,10 @@ func (o *openAPI) toSchema(typeName string, model interface{}) (_ *spec.Schema,
 | 
			
		||||
			},
 | 
			
		||||
		}, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		ref := "#/definitions/" + typeName
 | 
			
		||||
		if model != nil {
 | 
			
		||||
			ref, err = o.buildDefinitionForType(model)
 | 
			
		||||
		ref, err := o.buildDefinitionForType(model)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
		return &spec.Schema{
 | 
			
		||||
			SchemaProps: spec.SchemaProps{
 | 
			
		||||
				Ref: spec.MustCreateRef(ref),
 | 
			
		||||
@@ -335,7 +365,7 @@ func (o *openAPI) toSchema(typeName string, model interface{}) (_ *spec.Schema,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *openAPI) buildParameter(restParam restful.ParameterData) (ret spec.Parameter, err error) {
 | 
			
		||||
func (o *openAPI) buildParameter(restParam restful.ParameterData, bodySample interface{}) (ret spec.Parameter, err error) {
 | 
			
		||||
	ret = spec.Parameter{
 | 
			
		||||
		ParamProps: spec.ParamProps{
 | 
			
		||||
			Name:        restParam.Name,
 | 
			
		||||
@@ -345,9 +375,16 @@ func (o *openAPI) buildParameter(restParam restful.ParameterData) (ret spec.Para
 | 
			
		||||
	}
 | 
			
		||||
	switch restParam.Kind {
 | 
			
		||||
	case restful.BodyParameterKind:
 | 
			
		||||
		if bodySample != nil {
 | 
			
		||||
			ret.In = "body"
 | 
			
		||||
		ret.Schema, err = o.toSchema(restParam.DataType, nil)
 | 
			
		||||
			ret.Schema, err = o.toSchema(bodySample)
 | 
			
		||||
			return ret, err
 | 
			
		||||
		} else {
 | 
			
		||||
			// There is not enough information in the body parameter to build the definition.
 | 
			
		||||
			// Body parameter has a data type that is a short name but we need full package name
 | 
			
		||||
			// of the type to create a definition.
 | 
			
		||||
			return ret, fmt.Errorf("restful body parameters are not supported: %v", restParam.DataType)
 | 
			
		||||
		}
 | 
			
		||||
	case restful.PathParameterKind:
 | 
			
		||||
		ret.In = "path"
 | 
			
		||||
		if !restParam.Required {
 | 
			
		||||
@@ -375,7 +412,7 @@ func (o *openAPI) buildParameter(restParam restful.ParameterData) (ret spec.Para
 | 
			
		||||
func (o *openAPI) buildParameters(restParam []*restful.Parameter) (ret []spec.Parameter, err error) {
 | 
			
		||||
	ret = make([]spec.Parameter, len(restParam))
 | 
			
		||||
	for i, v := range restParam {
 | 
			
		||||
		ret[i], err = o.buildParameter(v.Data())
 | 
			
		||||
		ret[i], err = o.buildParameter(v.Data(), nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return ret, err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ package openapi
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful"
 | 
			
		||||
@@ -186,9 +187,22 @@ func getConfig(fullMethods bool) (*openapi.Config, *restful.Container) {
 | 
			
		||||
				Description: "Test API",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Definitions: &openapi.OpenAPIDefinitions{
 | 
			
		||||
			"openapi.TestInput":  *TestInput{}.OpenAPIDefinition(),
 | 
			
		||||
			"openapi.TestOutput": *TestOutput{}.OpenAPIDefinition(),
 | 
			
		||||
		GetDefinitions: func(_ openapi.ReferenceCallback) map[string]openapi.OpenAPIDefinition {
 | 
			
		||||
			return map[string]openapi.OpenAPIDefinition{
 | 
			
		||||
				"k8s.io/kubernetes/pkg/genericapiserver/server/openapi.TestInput":  *TestInput{}.OpenAPIDefinition(),
 | 
			
		||||
				"k8s.io/kubernetes/pkg/genericapiserver/server/openapi.TestOutput": *TestOutput{}.OpenAPIDefinition(),
 | 
			
		||||
				// Bazel changes the package name, this is ok for testing, but we need to fix it if it happened
 | 
			
		||||
				// in the main code.
 | 
			
		||||
				"k8s.io/kubernetes/pkg/genericapiserver/server/openapi/go_default_test.TestInput":  *TestInput{}.OpenAPIDefinition(),
 | 
			
		||||
				"k8s.io/kubernetes/pkg/genericapiserver/server/openapi/go_default_test.TestOutput": *TestOutput{}.OpenAPIDefinition(),
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		GetDefinitionName: func(_ string, name string) (string, spec.Extensions) {
 | 
			
		||||
			friendlyName := name[strings.LastIndex(name, "/")+1:]
 | 
			
		||||
			if strings.HasPrefix(friendlyName, "go_default_test") {
 | 
			
		||||
				friendlyName = "openapi" + friendlyName[len("go_default_test"):]
 | 
			
		||||
			}
 | 
			
		||||
			return friendlyName, nil
 | 
			
		||||
		},
 | 
			
		||||
	}, container
 | 
			
		||||
}
 | 
			
		||||
@@ -216,12 +230,18 @@ func getTestPathItem(allMethods bool, opPrefix string) spec.PathItem {
 | 
			
		||||
	}
 | 
			
		||||
	ret.Get.Parameters = getAdditionalTestParameters()
 | 
			
		||||
	if allMethods {
 | 
			
		||||
		ret.PathItemProps.Put = getTestOperation("put", opPrefix)
 | 
			
		||||
		ret.PathItemProps.Post = getTestOperation("post", opPrefix)
 | 
			
		||||
		ret.PathItemProps.Head = getTestOperation("head", opPrefix)
 | 
			
		||||
		ret.PathItemProps.Patch = getTestOperation("patch", opPrefix)
 | 
			
		||||
		ret.PathItemProps.Delete = getTestOperation("delete", opPrefix)
 | 
			
		||||
		ret.PathItemProps.Options = getTestOperation("options", opPrefix)
 | 
			
		||||
		ret.Put = getTestOperation("put", opPrefix)
 | 
			
		||||
		ret.Put.Parameters = getTestParameters()
 | 
			
		||||
		ret.Post = getTestOperation("post", opPrefix)
 | 
			
		||||
		ret.Post.Parameters = getTestParameters()
 | 
			
		||||
		ret.Head = getTestOperation("head", opPrefix)
 | 
			
		||||
		ret.Head.Parameters = getTestParameters()
 | 
			
		||||
		ret.Patch = getTestOperation("patch", opPrefix)
 | 
			
		||||
		ret.Patch.Parameters = getTestParameters()
 | 
			
		||||
		ret.Delete = getTestOperation("delete", opPrefix)
 | 
			
		||||
		ret.Delete.Parameters = getTestParameters()
 | 
			
		||||
		ret.Options = getTestOperation("options", opPrefix)
 | 
			
		||||
		ret.Options.Parameters = getTestParameters()
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
@@ -250,16 +270,8 @@ func getTestResponses() *spec.Responses {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTestCommonParameters() []spec.Parameter {
 | 
			
		||||
	ret := make([]spec.Parameter, 3)
 | 
			
		||||
	ret := make([]spec.Parameter, 2)
 | 
			
		||||
	ret[0] = spec.Parameter{
 | 
			
		||||
		ParamProps: spec.ParamProps{
 | 
			
		||||
			Name:     "body",
 | 
			
		||||
			In:       "body",
 | 
			
		||||
			Required: true,
 | 
			
		||||
			Schema:   getRefSchema("#/definitions/openapi.TestInput"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	ret[1] = spec.Parameter{
 | 
			
		||||
		SimpleSchema: spec.SimpleSchema{
 | 
			
		||||
			Type: "string",
 | 
			
		||||
		},
 | 
			
		||||
@@ -273,7 +285,7 @@ func getTestCommonParameters() []spec.Parameter {
 | 
			
		||||
			UniqueItems: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	ret[2] = spec.Parameter{
 | 
			
		||||
	ret[1] = spec.Parameter{
 | 
			
		||||
		SimpleSchema: spec.SimpleSchema{
 | 
			
		||||
			Type: "string",
 | 
			
		||||
		},
 | 
			
		||||
@@ -289,9 +301,30 @@ func getTestCommonParameters() []spec.Parameter {
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAdditionalTestParameters() []spec.Parameter {
 | 
			
		||||
	ret := make([]spec.Parameter, 2)
 | 
			
		||||
func getTestParameters() []spec.Parameter {
 | 
			
		||||
	ret := make([]spec.Parameter, 1)
 | 
			
		||||
	ret[0] = spec.Parameter{
 | 
			
		||||
		ParamProps: spec.ParamProps{
 | 
			
		||||
			Name:     "body",
 | 
			
		||||
			In:       "body",
 | 
			
		||||
			Required: true,
 | 
			
		||||
			Schema:   getRefSchema("#/definitions/openapi.TestInput"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAdditionalTestParameters() []spec.Parameter {
 | 
			
		||||
	ret := make([]spec.Parameter, 3)
 | 
			
		||||
	ret[0] = spec.Parameter{
 | 
			
		||||
		ParamProps: spec.ParamProps{
 | 
			
		||||
			Name:     "body",
 | 
			
		||||
			In:       "body",
 | 
			
		||||
			Required: true,
 | 
			
		||||
			Schema:   getRefSchema("#/definitions/openapi.TestInput"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	ret[1] = spec.Parameter{
 | 
			
		||||
		ParamProps: spec.ParamProps{
 | 
			
		||||
			Name:        "fparam",
 | 
			
		||||
			Description: "a test form parameter",
 | 
			
		||||
@@ -304,7 +337,7 @@ func getAdditionalTestParameters() []spec.Parameter {
 | 
			
		||||
			UniqueItems: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	ret[1] = spec.Parameter{
 | 
			
		||||
	ret[2] = spec.Parameter{
 | 
			
		||||
		SimpleSchema: spec.SimpleSchema{
 | 
			
		||||
			Type: "integer",
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ func TestValidOpenAPISpec(t *testing.T) {
 | 
			
		||||
	defer etcdserver.Terminate(t)
 | 
			
		||||
 | 
			
		||||
	config.GenericConfig.EnableIndex = true
 | 
			
		||||
	config.GenericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapigen.OpenAPIDefinitions)
 | 
			
		||||
	config.GenericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapigen.GetOpenAPIDefinitions)
 | 
			
		||||
	config.GenericConfig.OpenAPIConfig.Info = &spec.Info{
 | 
			
		||||
		InfoProps: spec.InfoProps{
 | 
			
		||||
			Title:   "Kubernetes",
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ package openapi
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/emicklei/go-restful"
 | 
			
		||||
	"github.com/go-openapi/spec"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi.
 | 
			
		||||
@@ -27,8 +28,10 @@ type OpenAPIDefinition struct {
 | 
			
		||||
	Dependencies []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ReferenceCallback func(path string) spec.Ref
 | 
			
		||||
 | 
			
		||||
// OpenAPIDefinitions is collection of all definitions.
 | 
			
		||||
type OpenAPIDefinitions map[string]OpenAPIDefinition
 | 
			
		||||
type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition
 | 
			
		||||
 | 
			
		||||
// OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface,
 | 
			
		||||
// the definition returned by it will be used, otherwise the auto-generated definitions will be used. See
 | 
			
		||||
@@ -59,11 +62,18 @@ type Config struct {
 | 
			
		||||
 | 
			
		||||
	// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
 | 
			
		||||
	// or any of the models will result in spec generation failure.
 | 
			
		||||
	Definitions *OpenAPIDefinitions
 | 
			
		||||
	GetDefinitions GetOpenAPIDefinitions
 | 
			
		||||
 | 
			
		||||
	// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
 | 
			
		||||
	GetOperationIDAndTags func(servePath string, r *restful.Route) (string, []string, error)
 | 
			
		||||
 | 
			
		||||
	// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
 | 
			
		||||
	// It is an optional function to customize model names.
 | 
			
		||||
	GetDefinitionName func(servePath string, name string) (string, spec.Extensions)
 | 
			
		||||
 | 
			
		||||
	// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving.
 | 
			
		||||
	PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error)
 | 
			
		||||
 | 
			
		||||
	// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config
 | 
			
		||||
	// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses.
 | 
			
		||||
	SecurityDefinitions *spec.SecurityDefinitions
 | 
			
		||||
@@ -141,3 +151,10 @@ func GetOpenAPITypeFormat(typeName string) (string, string) {
 | 
			
		||||
	}
 | 
			
		||||
	return mapped[0], mapped[1]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func EscapeJsonPointer(p string) string {
 | 
			
		||||
	// Escaping reference name using rfc6901
 | 
			
		||||
	p = strings.Replace(p, "~", "~0", -1)
 | 
			
		||||
	p = strings.Replace(p, "/", "~1", -1)
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -183,7 +183,7 @@ func startMasterOrDie(masterConfig *master.Config, incomingServer *httptest.Serv
 | 
			
		||||
		masterConfig = NewMasterConfig()
 | 
			
		||||
		masterConfig.GenericConfig.EnableProfiling = true
 | 
			
		||||
		masterConfig.GenericConfig.EnableMetrics = true
 | 
			
		||||
		masterConfig.GenericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.OpenAPIDefinitions)
 | 
			
		||||
		masterConfig.GenericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.GetOpenAPIDefinitions)
 | 
			
		||||
		masterConfig.GenericConfig.OpenAPIConfig.Info = &spec.Info{
 | 
			
		||||
			InfoProps: spec.InfoProps{
 | 
			
		||||
				Title:   "Kubernetes",
 | 
			
		||||
@@ -195,7 +195,7 @@ func startMasterOrDie(masterConfig *master.Config, incomingServer *httptest.Serv
 | 
			
		||||
				Description: "Default Response.",
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
		masterConfig.GenericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
 | 
			
		||||
		masterConfig.GenericConfig.OpenAPIConfig.GetDefinitions = openapi.GetOpenAPIDefinitions
 | 
			
		||||
		masterConfig.GenericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user