Merge pull request #109031 from Jefftree/openapiv3beta

OpenAPI V3 Enable Beta

Kubernetes-commit: 904c30562a9a34d26ff3e76db29d00daea2e0f60
This commit is contained in:
Kubernetes Publisher 2022-03-29 20:36:25 -07:00
commit ee1ac0ffde
5 changed files with 84 additions and 56 deletions

18
go.mod
View File

@ -42,12 +42,12 @@ require (
google.golang.org/grpc v1.40.0 google.golang.org/grpc v1.40.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/square/go-jose.v2 v2.2.2 gopkg.in/square/go-jose.v2 v2.2.2
k8s.io/api v0.0.0-20220330011019-6031be5d2a4d k8s.io/api v0.0.0-20220330051021-b754a94214be
k8s.io/apimachinery v0.0.0-20220329130813-31e52c987dc1 k8s.io/apimachinery v0.0.0-20220330050810-00f071187c12
k8s.io/client-go v0.0.0-20220330011324-9cfda74c80a4 k8s.io/client-go v0.0.0-20220330051330-b1e85f6f0092
k8s.io/component-base v0.0.0-20220330011832-6ef47acafa8e k8s.io/component-base v0.0.0-20220330051900-ffc9c87ab39a
k8s.io/klog/v2 v2.60.1 k8s.io/klog/v2 v2.60.1
k8s.io/kube-openapi v0.0.0-20220324211241-9f9c01d62a3a k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2
@ -56,8 +56,8 @@ require (
) )
replace ( replace (
k8s.io/api => k8s.io/api v0.0.0-20220330011019-6031be5d2a4d k8s.io/api => k8s.io/api v0.0.0-20220330051021-b754a94214be
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20220329130813-31e52c987dc1 k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20220330050810-00f071187c12
k8s.io/client-go => k8s.io/client-go v0.0.0-20220330011324-9cfda74c80a4 k8s.io/client-go => k8s.io/client-go v0.0.0-20220330051330-b1e85f6f0092
k8s.io/component-base => k8s.io/component-base v0.0.0-20220330011832-6ef47acafa8e k8s.io/component-base => k8s.io/component-base v0.0.0-20220330051900-ffc9c87ab39a
) )

20
go.sum
View File

@ -954,21 +954,21 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.0.0-20220330011019-6031be5d2a4d h1:JITAFP7p1OtAeKzWnjkjjJxn6ctWoQvwwxabOyc8v7E= k8s.io/api v0.0.0-20220330051021-b754a94214be h1:UnXBdsSVy3e2Y6cyf9rVmzn0wPXyoUuGIZAM43vdTj0=
k8s.io/api v0.0.0-20220330011019-6031be5d2a4d/go.mod h1:DtY4NYpJTdEZbyZNYT6OchYvejyTwdm7DK07dMzPcII= k8s.io/api v0.0.0-20220330051021-b754a94214be/go.mod h1:gL+2VXubbVTH6gK18uLau2gxoDmu43bdiQmz5TTa3zw=
k8s.io/apimachinery v0.0.0-20220329130813-31e52c987dc1 h1:ESix+UawmXFu9oem7ngnHSbufLCiIQrvn9TXHB1x/w4= k8s.io/apimachinery v0.0.0-20220330050810-00f071187c12 h1:+Cp1h0ojFtOluw7Bgiju2A/LqoWzeYyaB+sY/YSflwE=
k8s.io/apimachinery v0.0.0-20220329130813-31e52c987dc1/go.mod h1:WkN7hnr/sIpKTK8v3BZKqLkdqTMz00TBdMWqE0M0O7Q= k8s.io/apimachinery v0.0.0-20220330050810-00f071187c12/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/client-go v0.0.0-20220330011324-9cfda74c80a4 h1:/DhMBD0xkS7DvAriCuffRTIsz1G4fI4NswWFfSNbLgQ= k8s.io/client-go v0.0.0-20220330051330-b1e85f6f0092 h1:juuWgiTcvrIkUVtF+C5CYsVA0YK7eNA6M/uD1J4WxNU=
k8s.io/client-go v0.0.0-20220330011324-9cfda74c80a4/go.mod h1:YxULbpSLECQQvysnBfh02ucl8mDQnaxBbWzj/j4OpyI= k8s.io/client-go v0.0.0-20220330051330-b1e85f6f0092/go.mod h1:891OlZJw6BK4fpxlZNVtaoFv0uIX9BfbxEsmMJBv1xM=
k8s.io/component-base v0.0.0-20220330011832-6ef47acafa8e h1:LVTPrdPXjDa/QVeuJGpWfryOq7PJ4TEzICMomzm0hNE= k8s.io/component-base v0.0.0-20220330051900-ffc9c87ab39a h1:5GgsJwT9dZE4ta+/a+DDXa2FB0f7ZkmwqJbFE6CHZHo=
k8s.io/component-base v0.0.0-20220330011832-6ef47acafa8e/go.mod h1:X2whuyKi0x6081clOWdbkh0RA29kBroU/3eEhlbWHBU= k8s.io/component-base v0.0.0-20220330051900-ffc9c87ab39a/go.mod h1:LJBddfwf8ppsSrBEKyFor1D79VOnf+xhBp7/sE+XB/E=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc=
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20220324211241-9f9c01d62a3a h1:91uLlZzSWSkvb1xuJeHwRMTMLHRHXz7eXPNuKxXJb+0= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU=
k8s.io/kube-openapi v0.0.0-20220324211241-9f9c01d62a3a/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=

View File

@ -167,6 +167,7 @@ const (
// owner: @jefftree // owner: @jefftree
// kep: http://kep.k8s.io/2896 // kep: http://kep.k8s.io/2896
// alpha: v1.23 // alpha: v1.23
// beta: v1.24
// //
// Enables kubernetes to publish OpenAPI v3 // Enables kubernetes to publish OpenAPI v3
OpenAPIV3 featuregate.Feature = "OpenAPIV3" OpenAPIV3 featuregate.Feature = "OpenAPIV3"
@ -212,7 +213,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
APIServerTracing: {Default: false, PreRelease: featuregate.Alpha}, APIServerTracing: {Default: false, PreRelease: featuregate.Alpha},
OpenAPIEnums: {Default: true, PreRelease: featuregate.Beta}, OpenAPIEnums: {Default: true, PreRelease: featuregate.Beta},
CustomResourceValidationExpressions: {Default: false, PreRelease: featuregate.Alpha}, CustomResourceValidationExpressions: {Default: false, PreRelease: featuregate.Alpha},
OpenAPIV3: {Default: false, PreRelease: featuregate.Alpha}, OpenAPIV3: {Default: true, PreRelease: featuregate.Beta},
ServerSideFieldValidation: {Default: true, PreRelease: featuregate.Beta}, ServerSideFieldValidation: {Default: true, PreRelease: featuregate.Beta},
CronJobTimeZone: {Default: false, PreRelease: featuregate.Alpha}, CronJobTimeZone: {Default: false, PreRelease: featuregate.Alpha},
} }

View File

@ -171,6 +171,8 @@ type Config struct {
Serializer runtime.NegotiatedSerializer Serializer runtime.NegotiatedSerializer
// OpenAPIConfig will be used in generating OpenAPI spec. This is nil by default. Use DefaultOpenAPIConfig for "working" defaults. // OpenAPIConfig will be used in generating OpenAPI spec. This is nil by default. Use DefaultOpenAPIConfig for "working" defaults.
OpenAPIConfig *openapicommon.Config OpenAPIConfig *openapicommon.Config
// OpenAPIV3Config will be used in generating OpenAPI V3 spec. This is nil by default. Use DefaultOpenAPIV3Config for "working" defaults.
OpenAPIV3Config *openapicommon.Config
// SkipOpenAPIInstallation avoids installing the OpenAPI handler if set to true. // SkipOpenAPIInstallation avoids installing the OpenAPI handler if set to true.
SkipOpenAPIInstallation bool SkipOpenAPIInstallation bool
@ -382,6 +384,7 @@ func NewRecommendedConfig(codecs serializer.CodecFactory) *RecommendedConfig {
} }
} }
// DefaultOpenAPIConfig provides the default OpenAPIConfig used to build the OpenAPI V2 spec
func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, defNamer *apiopenapi.DefinitionNamer) *openapicommon.Config { func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, defNamer *apiopenapi.DefinitionNamer) *openapicommon.Config {
return &openapicommon.Config{ return &openapicommon.Config{
ProtocolList: []string{"https"}, ProtocolList: []string{"https"},
@ -402,6 +405,17 @@ func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, de
} }
} }
// DefaultOpenAPIV3Config provides the default OpenAPIV3Config used to build the OpenAPI V3 spec
func DefaultOpenAPIV3Config(getDefinitions openapicommon.GetOpenAPIDefinitions, defNamer *apiopenapi.DefinitionNamer) *openapicommon.Config {
defaultConfig := DefaultOpenAPIConfig(getDefinitions, defNamer)
defaultConfig.Definitions = getDefinitions(func(name string) spec.Ref {
defName, _ := defaultConfig.GetDefinitionName(name)
return spec.MustCreateRef("#/components/schemas/" + openapicommon.EscapeJsonPointer(defName))
})
return defaultConfig
}
func (c *AuthenticationInfo) ApplyClientCert(clientCA dynamiccertificates.CAContentProvider, servingInfo *SecureServingInfo) error { func (c *AuthenticationInfo) ApplyClientCert(clientCA dynamiccertificates.CAContentProvider, servingInfo *SecureServingInfo) error {
if servingInfo == nil { if servingInfo == nil {
return nil return nil
@ -475,6 +489,45 @@ func (c *Config) AddPostStartHookOrDie(name string, hook PostStartHookFunc) {
} }
} }
func completeOpenAPI(config *openapicommon.Config, version *version.Info) {
if config == nil {
return
}
if config.SecurityDefinitions != nil {
// Setup OpenAPI security: all APIs will have the same authentication for now.
config.DefaultSecurity = []map[string][]string{}
keys := []string{}
for k := range *config.SecurityDefinitions {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
config.DefaultSecurity = append(config.DefaultSecurity, map[string][]string{k: {}})
}
if config.CommonResponses == nil {
config.CommonResponses = map[int]spec.Response{}
}
if _, exists := config.CommonResponses[http.StatusUnauthorized]; !exists {
config.CommonResponses[http.StatusUnauthorized] = spec.Response{
ResponseProps: spec.ResponseProps{
Description: "Unauthorized",
},
}
}
}
// make sure we populate info, and info.version, if not manually set
if config.Info == nil {
config.Info = &spec.Info{}
}
if config.Info.Version == "" {
if version != nil {
config.Info.Version = strings.Split(version.String(), "-")[0]
} else {
config.Info.Version = "unversioned"
}
}
}
// Complete fills in any fields not set that are required to have valid data and can be derived // Complete fills in any fields not set that are required to have valid data and can be derived
// from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver. // from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver.
func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig { func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig {
@ -494,42 +547,9 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo
c.ExternalAddress = net.JoinHostPort(c.ExternalAddress, strconv.Itoa(port)) c.ExternalAddress = net.JoinHostPort(c.ExternalAddress, strconv.Itoa(port))
} }
if c.OpenAPIConfig != nil { completeOpenAPI(c.OpenAPIConfig, c.Version)
if c.OpenAPIConfig.SecurityDefinitions != nil { completeOpenAPI(c.OpenAPIV3Config, c.Version)
// Setup OpenAPI security: all APIs will have the same authentication for now.
c.OpenAPIConfig.DefaultSecurity = []map[string][]string{}
keys := []string{}
for k := range *c.OpenAPIConfig.SecurityDefinitions {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
c.OpenAPIConfig.DefaultSecurity = append(c.OpenAPIConfig.DefaultSecurity, map[string][]string{k: {}})
}
if c.OpenAPIConfig.CommonResponses == nil {
c.OpenAPIConfig.CommonResponses = map[int]spec.Response{}
}
if _, exists := c.OpenAPIConfig.CommonResponses[http.StatusUnauthorized]; !exists {
c.OpenAPIConfig.CommonResponses[http.StatusUnauthorized] = spec.Response{
ResponseProps: spec.ResponseProps{
Description: "Unauthorized",
},
}
}
}
// make sure we populate info, and info.version, if not manually set
if c.OpenAPIConfig.Info == nil {
c.OpenAPIConfig.Info = &spec.Info{}
}
if c.OpenAPIConfig.Info.Version == "" {
if c.Version != nil {
c.OpenAPIConfig.Info.Version = strings.Split(c.Version.String(), "-")[0]
} else {
c.OpenAPIConfig.Info.Version = "unversioned"
}
}
}
if c.DiscoveryAddresses == nil { if c.DiscoveryAddresses == nil {
c.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: c.ExternalAddress} c.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: c.ExternalAddress}
} }
@ -606,6 +626,7 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
ExternalAddress: c.ExternalAddress, ExternalAddress: c.ExternalAddress,
openAPIConfig: c.OpenAPIConfig, openAPIConfig: c.OpenAPIConfig,
openAPIV3Config: c.OpenAPIV3Config,
skipOpenAPIInstallation: c.SkipOpenAPIInstallation, skipOpenAPIInstallation: c.SkipOpenAPIInstallation,
postStartHooks: map[string]postStartHookEntry{}, postStartHooks: map[string]postStartHookEntry{},

View File

@ -135,6 +135,9 @@ type GenericAPIServer struct {
// Enable swagger and/or OpenAPI if these configs are non-nil. // Enable swagger and/or OpenAPI if these configs are non-nil.
openAPIConfig *openapicommon.Config openAPIConfig *openapicommon.Config
// Enable swagger and/or OpenAPI V3 if these configs are non-nil.
openAPIV3Config *openapicommon.Config
// SkipOpenAPIInstallation indicates not to install the OpenAPI handler // SkipOpenAPIInstallation indicates not to install the OpenAPI handler
// during PrepareRun. // during PrepareRun.
// Set this to true when the specific API Server has its own OpenAPI handler // Set this to true when the specific API Server has its own OpenAPI handler
@ -351,9 +354,12 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
s.OpenAPIVersionedService, s.StaticOpenAPISpec = routes.OpenAPI{ s.OpenAPIVersionedService, s.StaticOpenAPISpec = routes.OpenAPI{
Config: s.openAPIConfig, Config: s.openAPIConfig,
}.InstallV2(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux) }.InstallV2(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
}
if s.openAPIV3Config != nil && !s.skipOpenAPIInstallation {
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) { if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
s.OpenAPIV3VersionedService = routes.OpenAPI{ s.OpenAPIV3VersionedService = routes.OpenAPI{
Config: s.openAPIConfig, Config: s.openAPIV3Config,
}.InstallV3(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux) }.InstallV3(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
} }
} }