mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Separate OpenAPI V2 and V3 Config
This commit is contained in:
parent
9d42879d2c
commit
67d3dbfaae
@ -389,6 +389,11 @@ func buildGenericConfig(
|
||||
getOpenAPIDefinitions := openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(generatedopenapi.GetOpenAPIDefinitions)
|
||||
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(getOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
|
||||
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.OpenAPIV3) {
|
||||
genericConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(getOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
|
||||
genericConfig.OpenAPIV3Config.Info.Title = "Kubernetes"
|
||||
}
|
||||
|
||||
genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
|
||||
sets.NewString("watch", "proxy"),
|
||||
sets.NewString("attach", "exec", "proxy", "log", "portforward"),
|
||||
@ -436,7 +441,7 @@ func buildGenericConfig(
|
||||
versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
|
||||
|
||||
// Authentication.ApplyTo requires already applied OpenAPIConfig and EgressSelector if present
|
||||
if lastErr = s.Authentication.ApplyTo(&genericConfig.Authentication, genericConfig.SecureServing, genericConfig.EgressSelector, genericConfig.OpenAPIConfig, clientgoExternalClient, versionedInformers); lastErr != nil {
|
||||
if lastErr = s.Authentication.ApplyTo(&genericConfig.Authentication, genericConfig.SecureServing, genericConfig.EgressSelector, genericConfig.OpenAPIConfig, genericConfig.OpenAPIV3Config, clientgoExternalClient, versionedInformers); lastErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
|
||||
}
|
||||
|
||||
// ApplyTo requires already applied OpenAPIConfig and EgressSelector if present.
|
||||
func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.AuthenticationInfo, secureServing *genericapiserver.SecureServingInfo, egressSelector *egressselector.EgressSelector, openAPIConfig *openapicommon.Config, extclient kubernetes.Interface, versionedInformer informers.SharedInformerFactory) error {
|
||||
func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.AuthenticationInfo, secureServing *genericapiserver.SecureServingInfo, egressSelector *egressselector.EgressSelector, openAPIConfig *openapicommon.Config, openAPIV3Config *openapicommon.Config, extclient kubernetes.Interface, versionedInformer informers.SharedInformerFactory) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
@ -504,6 +504,9 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.Authen
|
||||
}
|
||||
|
||||
authInfo.Authenticator, openAPIConfig.SecurityDefinitions, err = authenticatorConfig.New()
|
||||
if openAPIV3Config != nil {
|
||||
openAPIV3Config.SecurityDefinitions = openAPIConfig.SecurityDefinitions
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -236,9 +236,12 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
||||
// Together they serve the /openapi/v2 endpoint on a generic apiserver. A generic apiserver may
|
||||
// choose to not enable OpenAPI by having null openAPIConfig, and thus OpenAPIVersionedService
|
||||
// and StaticOpenAPISpec are both null. In that case we don't run the CRD OpenAPI controller.
|
||||
if s.GenericAPIServer.OpenAPIVersionedService != nil && s.GenericAPIServer.StaticOpenAPISpec != nil {
|
||||
go openapiController.Run(s.GenericAPIServer.StaticOpenAPISpec, s.GenericAPIServer.OpenAPIVersionedService, context.StopCh)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
if s.GenericAPIServer.StaticOpenAPISpec != nil {
|
||||
if s.GenericAPIServer.OpenAPIVersionedService != nil {
|
||||
go openapiController.Run(s.GenericAPIServer.StaticOpenAPISpec, s.GenericAPIServer.OpenAPIVersionedService, context.StopCh)
|
||||
}
|
||||
|
||||
if s.GenericAPIServer.OpenAPIV3VersionedService != nil && utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
go openapiv3Controller.Run(s.GenericAPIServer.OpenAPIV3VersionedService, context.StopCh)
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +171,8 @@ type Config struct {
|
||||
Serializer runtime.NegotiatedSerializer
|
||||
// OpenAPIConfig will be used in generating OpenAPI spec. This is nil by default. Use DefaultOpenAPIConfig for "working" defaults.
|
||||
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 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 {
|
||||
return &openapicommon.Config{
|
||||
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 {
|
||||
if servingInfo == 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
|
||||
// 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 {
|
||||
@ -494,42 +547,9 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo
|
||||
c.ExternalAddress = net.JoinHostPort(c.ExternalAddress, strconv.Itoa(port))
|
||||
}
|
||||
|
||||
if c.OpenAPIConfig != nil {
|
||||
if c.OpenAPIConfig.SecurityDefinitions != nil {
|
||||
// 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",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
completeOpenAPI(c.OpenAPIConfig, c.Version)
|
||||
completeOpenAPI(c.OpenAPIV3Config, c.Version)
|
||||
|
||||
// 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 {
|
||||
c.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: c.ExternalAddress}
|
||||
}
|
||||
@ -606,6 +626,7 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
|
||||
ExternalAddress: c.ExternalAddress,
|
||||
|
||||
openAPIConfig: c.OpenAPIConfig,
|
||||
openAPIV3Config: c.OpenAPIV3Config,
|
||||
skipOpenAPIInstallation: c.SkipOpenAPIInstallation,
|
||||
|
||||
postStartHooks: map[string]postStartHookEntry{},
|
||||
|
@ -135,6 +135,9 @@ type GenericAPIServer struct {
|
||||
// Enable swagger and/or OpenAPI if these configs are non-nil.
|
||||
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
|
||||
// during PrepareRun.
|
||||
// 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{
|
||||
Config: s.openAPIConfig,
|
||||
}.InstallV2(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
|
||||
if s.openAPIV3Config != nil && !s.skipOpenAPIInstallation {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
s.OpenAPIV3VersionedService = routes.OpenAPI{
|
||||
Config: s.openAPIConfig,
|
||||
Config: s.openAPIV3Config,
|
||||
}.InstallV3(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +144,9 @@ type APIAggregator struct {
|
||||
// Enable swagger and/or OpenAPI if these configs are non-nil.
|
||||
openAPIConfig *openapicommon.Config
|
||||
|
||||
// Enable OpenAPI V3 if these configs are non-nil
|
||||
openAPIV3Config *openapicommon.Config
|
||||
|
||||
// openAPIAggregationController downloads and merges OpenAPI v2 specs.
|
||||
openAPIAggregationController *openapicontroller.AggregationController
|
||||
|
||||
@ -207,6 +210,7 @@ func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.Deleg
|
||||
APIRegistrationInformers: informerFactory,
|
||||
serviceResolver: c.ExtraConfig.ServiceResolver,
|
||||
openAPIConfig: c.GenericConfig.OpenAPIConfig,
|
||||
openAPIV3Config: c.GenericConfig.OpenAPIV3Config,
|
||||
egressSelector: c.GenericConfig.EgressSelector,
|
||||
proxyCurrentCertKeyContent: func() (bytes []byte, bytes2 []byte) { return nil, nil },
|
||||
}
|
||||
@ -363,9 +367,13 @@ func (s *APIAggregator) PrepareRun() (preparedAPIAggregator, error) {
|
||||
if s.openAPIConfig != nil {
|
||||
s.GenericAPIServer.AddPostStartHookOrDie("apiservice-openapi-controller", func(context genericapiserver.PostStartHookContext) error {
|
||||
go s.openAPIAggregationController.Run(context.StopCh)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
go s.openAPIV3AggregationController.Run(context.StopCh)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if s.openAPIV3Config != nil && utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
s.GenericAPIServer.AddPostStartHookOrDie("apiservice-openapiv3-controller", func(context genericapiserver.PostStartHookContext) error {
|
||||
go s.openAPIV3AggregationController.Run(context.StopCh)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -385,18 +393,18 @@ func (s *APIAggregator) PrepareRun() (preparedAPIAggregator, error) {
|
||||
return preparedAPIAggregator{}, err
|
||||
}
|
||||
s.openAPIAggregationController = openapicontroller.NewAggregationController(&specDownloader, openAPIAggregator)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
specDownloaderV3 := openapiv3aggregator.NewDownloader()
|
||||
openAPIV3Aggregator, err := openapiv3aggregator.BuildAndRegisterAggregator(
|
||||
specDownloaderV3,
|
||||
s.GenericAPIServer.NextDelegate(),
|
||||
s.GenericAPIServer.Handler.NonGoRestfulMux)
|
||||
if err != nil {
|
||||
return preparedAPIAggregator{}, err
|
||||
}
|
||||
_ = openAPIV3Aggregator
|
||||
s.openAPIV3AggregationController = openapiv3controller.NewAggregationController(openAPIV3Aggregator)
|
||||
}
|
||||
|
||||
if s.openAPIV3Config != nil && utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
specDownloaderV3 := openapiv3aggregator.NewDownloader()
|
||||
openAPIV3Aggregator, err := openapiv3aggregator.BuildAndRegisterAggregator(
|
||||
specDownloaderV3,
|
||||
s.GenericAPIServer.NextDelegate(),
|
||||
s.GenericAPIServer.Handler.NonGoRestfulMux)
|
||||
if err != nil {
|
||||
return preparedAPIAggregator{}, err
|
||||
}
|
||||
s.openAPIV3AggregationController = openapiv3controller.NewAggregationController(openAPIV3Aggregator)
|
||||
}
|
||||
|
||||
return preparedAPIAggregator{APIAggregator: s, runnable: prepared}, nil
|
||||
|
@ -139,6 +139,12 @@ func (o *WardleServerOptions) Config() (*apiserver.Config, error) {
|
||||
serverConfig.OpenAPIConfig.Info.Title = "Wardle"
|
||||
serverConfig.OpenAPIConfig.Info.Version = "0.1"
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme))
|
||||
serverConfig.OpenAPIV3Config.Info.Title = "Wardle"
|
||||
serverConfig.OpenAPIV3Config.Info.Version = "0.1"
|
||||
}
|
||||
|
||||
if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ func TestOpenAPIV3SpecRoundTrip(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.OpenAPIV3, true)()
|
||||
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfigWithOptions(&framework.ControlPlaneConfigOptions{})
|
||||
controlPlaneConfig.GenericConfig.OpenAPIConfig = framework.DefaultOpenAPIConfig()
|
||||
controlPlaneConfig.GenericConfig.OpenAPIV3Config = framework.DefaultOpenAPIV3Config()
|
||||
instanceConfig, _, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
|
||||
defer closeFn()
|
||||
paths := []string{
|
||||
@ -192,6 +193,7 @@ func TestOpenAPIV3ProtoRoundtrip(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.OpenAPIV3, true)()
|
||||
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfigWithOptions(&framework.ControlPlaneConfigOptions{})
|
||||
controlPlaneConfig.GenericConfig.OpenAPIConfig = framework.DefaultOpenAPIConfig()
|
||||
controlPlaneConfig.GenericConfig.OpenAPIV3Config = framework.DefaultOpenAPIV3Config()
|
||||
instanceConfig, _, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
|
||||
defer closeFn()
|
||||
rt, err := restclient.TransportFor(instanceConfig.GenericAPIServer.LoopbackClientConfig)
|
||||
|
@ -141,6 +141,25 @@ func DefaultOpenAPIConfig() *openapicommon.Config {
|
||||
return openAPIConfig
|
||||
}
|
||||
|
||||
// DefaultOpenAPIV3Config returns an openapicommon.Config initialized to default values.
|
||||
func DefaultOpenAPIV3Config() *openapicommon.Config {
|
||||
openAPIConfig := genericapiserver.DefaultOpenAPIV3Config(openapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme))
|
||||
openAPIConfig.Info = &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
Title: "Kubernetes",
|
||||
Version: "unversioned",
|
||||
},
|
||||
}
|
||||
openAPIConfig.DefaultResponse = &spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: "Default Response.",
|
||||
},
|
||||
}
|
||||
openAPIConfig.GetDefinitions = utilopenapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(openapi.GetOpenAPIDefinitions)
|
||||
|
||||
return openAPIConfig
|
||||
}
|
||||
|
||||
// startAPIServerOrDie starts a kubernetes API server and an httpserver to handle api requests
|
||||
func startAPIServerOrDie(controlPlaneConfig *controlplane.Config, incomingServer *httptest.Server, apiServerReceiver APIServerReceiver) (*controlplane.Instance, *httptest.Server, CloseFunc) {
|
||||
var m *controlplane.Instance
|
||||
|
Loading…
Reference in New Issue
Block a user