Merge pull request #122882 from Jefftree/agg-discovery-v2-usage
Use Aggregated Discovery v2 types and promote to GA
This commit is contained in:
		@@ -1176,7 +1176,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	genericfeatures.AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
						genericfeatures.AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genericfeatures.AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.Beta},
 | 
						genericfeatures.AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
 | 
						genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	autoscaling "k8s.io/api/autoscaling/v1"
 | 
						autoscaling "k8s.io/api/autoscaling/v1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/labels"
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
@@ -87,7 +87,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{}
 | 
						apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{}
 | 
				
			||||||
	apiResourcesForDiscovery := []metav1.APIResource{}
 | 
						apiResourcesForDiscovery := []metav1.APIResource{}
 | 
				
			||||||
	aggregatedApiResourcesForDiscovery := []apidiscoveryv2beta1.APIResourceDiscovery{}
 | 
						aggregatedAPIResourcesForDiscovery := []apidiscoveryv2.APIResourceDiscovery{}
 | 
				
			||||||
	versionsForDiscoveryMap := map[metav1.GroupVersion]bool{}
 | 
						versionsForDiscoveryMap := map[metav1.GroupVersion]bool{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	crds, err := c.crdLister.List(labels.Everything())
 | 
						crds, err := c.crdLister.List(labels.Everything())
 | 
				
			||||||
@@ -158,13 +158,13 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if c.resourceManager != nil {
 | 
							if c.resourceManager != nil {
 | 
				
			||||||
			var scope apidiscoveryv2beta1.ResourceScope
 | 
								var scope apidiscoveryv2.ResourceScope
 | 
				
			||||||
			if crd.Spec.Scope == apiextensionsv1.NamespaceScoped {
 | 
								if crd.Spec.Scope == apiextensionsv1.NamespaceScoped {
 | 
				
			||||||
				scope = apidiscoveryv2beta1.ScopeNamespace
 | 
									scope = apidiscoveryv2.ScopeNamespace
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				scope = apidiscoveryv2beta1.ScopeCluster
 | 
									scope = apidiscoveryv2.ScopeCluster
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			apiResourceDiscovery := apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								apiResourceDiscovery := apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				Resource:         crd.Status.AcceptedNames.Plural,
 | 
									Resource:         crd.Status.AcceptedNames.Plural,
 | 
				
			||||||
				SingularResource: crd.Status.AcceptedNames.Singular,
 | 
									SingularResource: crd.Status.AcceptedNames.Singular,
 | 
				
			||||||
				Scope:            scope,
 | 
									Scope:            scope,
 | 
				
			||||||
@@ -178,7 +178,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
				Categories: crd.Status.AcceptedNames.Categories,
 | 
									Categories: crd.Status.AcceptedNames.Categories,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if subresources != nil && subresources.Status != nil {
 | 
								if subresources != nil && subresources.Status != nil {
 | 
				
			||||||
				apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
									apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
					Subresource: "status",
 | 
										Subresource: "status",
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   version.Group,
 | 
											Group:   version.Group,
 | 
				
			||||||
@@ -189,7 +189,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
				})
 | 
									})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if subresources != nil && subresources.Scale != nil {
 | 
								if subresources != nil && subresources.Scale != nil {
 | 
				
			||||||
				apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
									apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
					Subresource: "scale",
 | 
										Subresource: "scale",
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   autoscaling.GroupName,
 | 
											Group:   autoscaling.GroupName,
 | 
				
			||||||
@@ -200,7 +200,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
				})
 | 
									})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			aggregatedApiResourcesForDiscovery = append(aggregatedApiResourcesForDiscovery, apiResourceDiscovery)
 | 
								aggregatedAPIResourcesForDiscovery = append(aggregatedAPIResourcesForDiscovery, apiResourceDiscovery)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if subresources != nil && subresources.Status != nil {
 | 
							if subresources != nil && subresources.Status != nil {
 | 
				
			||||||
@@ -260,14 +260,14 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
 | 
				
			|||||||
		return apiResourcesForDiscovery
 | 
							return apiResourcesForDiscovery
 | 
				
			||||||
	})))
 | 
						})))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort.Slice(aggregatedApiResourcesForDiscovery[:], func(i, j int) bool {
 | 
						sort.Slice(aggregatedAPIResourcesForDiscovery, func(i, j int) bool {
 | 
				
			||||||
		return aggregatedApiResourcesForDiscovery[i].Resource < aggregatedApiResourcesForDiscovery[j].Resource
 | 
							return aggregatedAPIResourcesForDiscovery[i].Resource < aggregatedAPIResourcesForDiscovery[j].Resource
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if c.resourceManager != nil {
 | 
						if c.resourceManager != nil {
 | 
				
			||||||
		c.resourceManager.AddGroupVersion(version.Group, apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							c.resourceManager.AddGroupVersion(version.Group, apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
								Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			Version:   version.Version,
 | 
								Version:   version.Version,
 | 
				
			||||||
			Resources: aggregatedApiResourcesForDiscovery,
 | 
								Resources: aggregatedAPIResourcesForDiscovery,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		// Default priority for CRDs
 | 
							// Default priority for CRDs
 | 
				
			||||||
		c.resourceManager.SetGroupVersionPriority(metav1.GroupVersion(version), 1000, 100)
 | 
							c.resourceManager.SetGroupVersionPriority(metav1.GroupVersion(version), 1000, 100)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
						v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
						"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
 | 
						"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
 | 
				
			||||||
@@ -125,13 +125,13 @@ var coolBarCRD = &v1.CustomResourceDefinition{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var coolFooDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta1.APIVersionDiscovery{
 | 
					var coolFooDiscovery apidiscoveryv2.APIVersionDiscovery = apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
	Version:   "v1",
 | 
						Version:   "v1",
 | 
				
			||||||
	Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
						Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
	Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
						Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Resource:         "coolfoos",
 | 
								Resource:         "coolfoos",
 | 
				
			||||||
			Scope:            apidiscoveryv2beta1.ScopeCluster,
 | 
								Scope:            apidiscoveryv2.ScopeCluster,
 | 
				
			||||||
			SingularResource: "coolfoo",
 | 
								SingularResource: "coolfoo",
 | 
				
			||||||
			Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
								Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
				
			||||||
			ShortNames:       []string{"foo"},
 | 
								ShortNames:       []string{"foo"},
 | 
				
			||||||
@@ -141,7 +141,7 @@ var coolFooDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2bet
 | 
				
			|||||||
				Version: "v1",
 | 
									Version: "v1",
 | 
				
			||||||
				Kind:    "CoolFoo",
 | 
									Kind:    "CoolFoo",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
								Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Subresource:   "status",
 | 
										Subresource:   "status",
 | 
				
			||||||
					Verbs:         []string{"get", "patch", "update"},
 | 
										Verbs:         []string{"get", "patch", "update"},
 | 
				
			||||||
@@ -157,13 +157,13 @@ var coolFooDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2bet
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var mergedDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta1.APIVersionDiscovery{
 | 
					var mergedDiscovery apidiscoveryv2.APIVersionDiscovery = apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
	Version:   "v1",
 | 
						Version:   "v1",
 | 
				
			||||||
	Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
						Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
	Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
						Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Resource:         "coolbars",
 | 
								Resource:         "coolbars",
 | 
				
			||||||
			Scope:            apidiscoveryv2beta1.ScopeCluster,
 | 
								Scope:            apidiscoveryv2.ScopeCluster,
 | 
				
			||||||
			SingularResource: "coolbar",
 | 
								SingularResource: "coolbar",
 | 
				
			||||||
			Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
								Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
				
			||||||
			ShortNames:       []string{"bar"},
 | 
								ShortNames:       []string{"bar"},
 | 
				
			||||||
@@ -175,7 +175,7 @@ var mergedDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
			Resource:         "coolfoos",
 | 
								Resource:         "coolfoos",
 | 
				
			||||||
			Scope:            apidiscoveryv2beta1.ScopeCluster,
 | 
								Scope:            apidiscoveryv2.ScopeCluster,
 | 
				
			||||||
			SingularResource: "coolfoo",
 | 
								SingularResource: "coolfoo",
 | 
				
			||||||
			Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
								Verbs:            []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
 | 
				
			||||||
			ShortNames:       []string{"foo"},
 | 
								ShortNames:       []string{"foo"},
 | 
				
			||||||
@@ -185,7 +185,7 @@ var mergedDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta
 | 
				
			|||||||
				Version: "v1",
 | 
									Version: "v1",
 | 
				
			||||||
				Kind:    "CoolFoo",
 | 
									Kind:    "CoolFoo",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
								Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Subresource:   "status",
 | 
										Subresource:   "status",
 | 
				
			||||||
					Verbs:         []string{"get", "patch", "update"},
 | 
										Verbs:         []string{"get", "patch", "update"},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2024 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.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This file was duplicated from the auto-generated file by conversion-gen in
 | 
				
			||||||
 | 
					// k8s.io/kubernetes/pkg/apis/apidiscovery Unlike most k8s types discovery is
 | 
				
			||||||
 | 
					// served by all apiservers and conversion is needed by all apiservers. The
 | 
				
			||||||
 | 
					// concept of internal/hub type does not exist for discovery as we work directly
 | 
				
			||||||
 | 
					// with the versioned types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The conversion code here facilities conversion strictly between v2beta1 and
 | 
				
			||||||
 | 
					// v2 types. It is only necessary in k8s versions where mixed state could be
 | 
				
			||||||
 | 
					// possible before the full removal of the v2beta1 types. It is placed in this
 | 
				
			||||||
 | 
					// directory such that all apiservers can benefit from the conversion without
 | 
				
			||||||
 | 
					// having to implement their own if the client/server they're communicating with
 | 
				
			||||||
 | 
					// only supports one version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Once the v2beta1 types are removed (intended for Kubernetes v1.33), this file
 | 
				
			||||||
 | 
					// will be removed.
 | 
				
			||||||
 | 
					package v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						unsafe "unsafe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						v2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
						v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
 | 
						conversion "k8s.io/apimachinery/pkg/conversion"
 | 
				
			||||||
 | 
						runtime "k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RegisterConversions adds conversion functions to the given scheme.
 | 
				
			||||||
 | 
					// Public to allow building arbitrary schemes.
 | 
				
			||||||
 | 
					func RegisterConversions(s *runtime.Scheme) error {
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2beta1.APIGroupDiscovery)(nil), (*v2.APIGroupDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(a.(*v2beta1.APIGroupDiscovery), b.(*v2.APIGroupDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2.APIGroupDiscovery)(nil), (*v2beta1.APIGroupDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(a.(*v2.APIGroupDiscovery), b.(*v2beta1.APIGroupDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2beta1.APIGroupDiscoveryList)(nil), (*v2.APIGroupDiscoveryList)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(a.(*v2beta1.APIGroupDiscoveryList), b.(*v2.APIGroupDiscoveryList), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2.APIGroupDiscoveryList)(nil), (*v2beta1.APIGroupDiscoveryList)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(a.(*v2.APIGroupDiscoveryList), b.(*v2beta1.APIGroupDiscoveryList), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2beta1.APIResourceDiscovery)(nil), (*v2.APIResourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(a.(*v2beta1.APIResourceDiscovery), b.(*v2.APIResourceDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2.APIResourceDiscovery)(nil), (*v2beta1.APIResourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(a.(*v2.APIResourceDiscovery), b.(*v2beta1.APIResourceDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2beta1.APISubresourceDiscovery)(nil), (*v2.APISubresourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(a.(*v2beta1.APISubresourceDiscovery), b.(*v2.APISubresourceDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2.APISubresourceDiscovery)(nil), (*v2beta1.APISubresourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(a.(*v2.APISubresourceDiscovery), b.(*v2beta1.APISubresourceDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2beta1.APIVersionDiscovery)(nil), (*v2.APIVersionDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(a.(*v2beta1.APIVersionDiscovery), b.(*v2.APIVersionDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.AddGeneratedConversionFunc((*v2.APIVersionDiscovery)(nil), (*v2beta1.APIVersionDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
				
			||||||
 | 
							return Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(a.(*v2.APIVersionDiscovery), b.(*v2beta1.APIVersionDiscovery), scope)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in *v2beta1.APIGroupDiscovery, out *v2.APIGroupDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.ObjectMeta = in.ObjectMeta
 | 
				
			||||||
 | 
						out.Versions = *(*[]v2.APIVersionDiscovery)(unsafe.Pointer(&in.Versions))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in *v2beta1.APIGroupDiscovery, out *v2.APIGroupDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in *v2.APIGroupDiscovery, out *v2beta1.APIGroupDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.ObjectMeta = in.ObjectMeta
 | 
				
			||||||
 | 
						out.Versions = *(*[]v2beta1.APIVersionDiscovery)(unsafe.Pointer(&in.Versions))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in *v2.APIGroupDiscovery, out *v2beta1.APIGroupDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in *v2beta1.APIGroupDiscoveryList, out *v2.APIGroupDiscoveryList, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.ListMeta = in.ListMeta
 | 
				
			||||||
 | 
						out.Items = *(*[]v2.APIGroupDiscovery)(unsafe.Pointer(&in.Items))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in *v2beta1.APIGroupDiscoveryList, out *v2.APIGroupDiscoveryList, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in *v2.APIGroupDiscoveryList, out *v2beta1.APIGroupDiscoveryList, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.ListMeta = in.ListMeta
 | 
				
			||||||
 | 
						out.Items = *(*[]v2beta1.APIGroupDiscovery)(unsafe.Pointer(&in.Items))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in *v2.APIGroupDiscoveryList, out *v2beta1.APIGroupDiscoveryList, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in *v2beta1.APIResourceDiscovery, out *v2.APIResourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Resource = in.Resource
 | 
				
			||||||
 | 
						out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
 | 
				
			||||||
 | 
						out.Scope = v2.ResourceScope(in.Scope)
 | 
				
			||||||
 | 
						out.SingularResource = in.SingularResource
 | 
				
			||||||
 | 
						out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
 | 
				
			||||||
 | 
						out.ShortNames = *(*[]string)(unsafe.Pointer(&in.ShortNames))
 | 
				
			||||||
 | 
						out.Categories = *(*[]string)(unsafe.Pointer(&in.Categories))
 | 
				
			||||||
 | 
						out.Subresources = *(*[]v2.APISubresourceDiscovery)(unsafe.Pointer(&in.Subresources))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in *v2beta1.APIResourceDiscovery, out *v2.APIResourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in *v2.APIResourceDiscovery, out *v2beta1.APIResourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Resource = in.Resource
 | 
				
			||||||
 | 
						out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
 | 
				
			||||||
 | 
						out.Scope = v2beta1.ResourceScope(in.Scope)
 | 
				
			||||||
 | 
						out.SingularResource = in.SingularResource
 | 
				
			||||||
 | 
						out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
 | 
				
			||||||
 | 
						out.ShortNames = *(*[]string)(unsafe.Pointer(&in.ShortNames))
 | 
				
			||||||
 | 
						out.Categories = *(*[]string)(unsafe.Pointer(&in.Categories))
 | 
				
			||||||
 | 
						out.Subresources = *(*[]v2beta1.APISubresourceDiscovery)(unsafe.Pointer(&in.Subresources))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in *v2.APIResourceDiscovery, out *v2beta1.APIResourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in *v2beta1.APISubresourceDiscovery, out *v2.APISubresourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Subresource = in.Subresource
 | 
				
			||||||
 | 
						out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
 | 
				
			||||||
 | 
						out.AcceptedTypes = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.AcceptedTypes))
 | 
				
			||||||
 | 
						out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in *v2beta1.APISubresourceDiscovery, out *v2.APISubresourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in *v2.APISubresourceDiscovery, out *v2beta1.APISubresourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Subresource = in.Subresource
 | 
				
			||||||
 | 
						out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
 | 
				
			||||||
 | 
						out.AcceptedTypes = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.AcceptedTypes))
 | 
				
			||||||
 | 
						out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in *v2.APISubresourceDiscovery, out *v2beta1.APISubresourceDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in *v2beta1.APIVersionDiscovery, out *v2.APIVersionDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Version = in.Version
 | 
				
			||||||
 | 
						out.Resources = *(*[]v2.APIResourceDiscovery)(unsafe.Pointer(&in.Resources))
 | 
				
			||||||
 | 
						out.Freshness = v2.DiscoveryFreshness(in.Freshness)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in *v2beta1.APIVersionDiscovery, out *v2.APIVersionDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func autoConvertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in *v2.APIVersionDiscovery, out *v2beta1.APIVersionDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						out.Version = in.Version
 | 
				
			||||||
 | 
						out.Resources = *(*[]v2beta1.APIResourceDiscovery)(unsafe.Pointer(&in.Resources))
 | 
				
			||||||
 | 
						out.Freshness = v2beta1.DiscoveryFreshness(in.Freshness)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery is an autogenerated conversion function.
 | 
				
			||||||
 | 
					func Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in *v2.APIVersionDiscovery, out *v2beta1.APIVersionDiscovery, s conversion.Scope) error {
 | 
				
			||||||
 | 
						return autoConvertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in, out, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								staging/src/k8s.io/apiserver/pkg/apis/apidiscovery/v2/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								staging/src/k8s.io/apiserver/pkg/apis/apidiscovery/v2/doc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2024 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.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +groupName=apidiscovery.k8s.io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package v2 // import "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2024 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 v2_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						v2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
						v2scheme "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
 | 
						v2beta1scheme "k8s.io/apiserver/pkg/apis/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
 | 
						runtime "k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
 | 
						fuzz "github.com/google/gofuzz"
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestConversionRoundTrip(t *testing.T) {
 | 
				
			||||||
 | 
						scheme := runtime.NewScheme()
 | 
				
			||||||
 | 
						err := v2beta1scheme.AddToScheme(scheme)
 | 
				
			||||||
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
						v2scheme.SchemeBuilder.Register(v2scheme.RegisterConversions)
 | 
				
			||||||
 | 
						err = v2scheme.AddToScheme(scheme)
 | 
				
			||||||
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fuzzer := fuzz.NewWithSeed(2374375)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// v2 -> v2beta1 -> v2
 | 
				
			||||||
 | 
						for i := 0; i < 100; i++ {
 | 
				
			||||||
 | 
							expected := &v2.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
							fuzzer.Fuzz(expected)
 | 
				
			||||||
 | 
							expected.TypeMeta = metav1.TypeMeta{
 | 
				
			||||||
 | 
								Kind:       "APIGroupDiscoveryList",
 | 
				
			||||||
 | 
								APIVersion: "apidiscovery.k8s.io/v2",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							o, err := scheme.ConvertToVersion(expected, v2beta1.SchemeGroupVersion)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							v2beta1Type := o.(*v2beta1.APIGroupDiscoveryList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							o2, err := scheme.ConvertToVersion(v2beta1Type, v2.SchemeGroupVersion)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							actual := o2.(*v2.APIGroupDiscoveryList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(expected, actual) {
 | 
				
			||||||
 | 
								t.Error(cmp.Diff(expected, actual))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// v2beta1 -> v2 -> v2beta1
 | 
				
			||||||
 | 
						for i := 0; i < 100; i++ {
 | 
				
			||||||
 | 
							expected := &v2beta1.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
							fuzzer.Fuzz(expected)
 | 
				
			||||||
 | 
							expected.TypeMeta = metav1.TypeMeta{
 | 
				
			||||||
 | 
								Kind:       "APIGroupDiscoveryList",
 | 
				
			||||||
 | 
								APIVersion: "apidiscovery.k8s.io/v2beta1",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							o, err := scheme.ConvertToVersion(expected, v2.SchemeGroupVersion)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							v2Type := o.(*v2.APIGroupDiscoveryList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							o2, err := scheme.ConvertToVersion(v2Type, v2beta1.SchemeGroupVersion)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							actual := o2.(*v2beta1.APIGroupDiscoveryList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(expected, actual) {
 | 
				
			||||||
 | 
								t.Error(cmp.Diff(expected, actual))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2024 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 v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GroupName is the group name use in this package
 | 
				
			||||||
 | 
					const GroupName = "apidiscovery.k8s.io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SchemeGroupVersion is group version used to register these objects
 | 
				
			||||||
 | 
					var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resource takes an unqualified resource and returns a Group qualified GroupResource
 | 
				
			||||||
 | 
					func Resource(resource string) schema.GroupResource {
 | 
				
			||||||
 | 
						return SchemeGroupVersion.WithResource(resource).GroupResource()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						SchemeBuilder = &apidiscoveryv2.SchemeBuilder
 | 
				
			||||||
 | 
						// AddToScheme adds api to a scheme
 | 
				
			||||||
 | 
						AddToScheme = SchemeBuilder.AddToScheme
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2022 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.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +groupName=apidiscovery.k8s.io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package v2beta1 // import "k8s.io/apiserver/pkg/apis/apidiscovery/v2beta1"
 | 
				
			||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2022 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 v2beta1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GroupName is the group name use in this package
 | 
				
			||||||
 | 
					const GroupName = "apidiscovery.k8s.io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SchemeGroupVersion is group version used to register these objects
 | 
				
			||||||
 | 
					var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2beta1"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resource takes an unqualified resource and returns a Group qualified GroupResource
 | 
				
			||||||
 | 
					func Resource(resource string) schema.GroupResource {
 | 
				
			||||||
 | 
						return SchemeGroupVersion.WithResource(resource).GroupResource()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						localSchemeBuilder = &apidiscoveryv2beta1.SchemeBuilder
 | 
				
			||||||
 | 
						// AddToScheme adds api to a scheme
 | 
				
			||||||
 | 
						AddToScheme = localSchemeBuilder.AddToScheme
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -24,6 +24,7 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
 | 
						"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,6 +40,7 @@ import (
 | 
				
			|||||||
func ServeHTTPWithETag(
 | 
					func ServeHTTPWithETag(
 | 
				
			||||||
	object runtime.Object,
 | 
						object runtime.Object,
 | 
				
			||||||
	hash string,
 | 
						hash string,
 | 
				
			||||||
 | 
						targetGV schema.GroupVersion,
 | 
				
			||||||
	serializer runtime.NegotiatedSerializer,
 | 
						serializer runtime.NegotiatedSerializer,
 | 
				
			||||||
	w http.ResponseWriter,
 | 
						w http.ResponseWriter,
 | 
				
			||||||
	req *http.Request,
 | 
						req *http.Request,
 | 
				
			||||||
@@ -64,7 +66,7 @@ func ServeHTTPWithETag(
 | 
				
			|||||||
	responsewriters.WriteObjectNegotiated(
 | 
						responsewriters.WriteObjectNegotiated(
 | 
				
			||||||
		serializer,
 | 
							serializer,
 | 
				
			||||||
		DiscoveryEndpointRestrictions,
 | 
							DiscoveryEndpointRestrictions,
 | 
				
			||||||
		AggregatedDiscoveryGV,
 | 
							targetGV,
 | 
				
			||||||
		w,
 | 
							w,
 | 
				
			||||||
		req,
 | 
							req,
 | 
				
			||||||
		http.StatusOK,
 | 
							http.StatusOK,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/emicklei/go-restful/v3"
 | 
						"github.com/emicklei/go-restful/v3"
 | 
				
			||||||
	"github.com/google/go-cmp/cmp"
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -122,7 +122,7 @@ func (f *recorderResourceManager) SetGroupVersionPriority(gv metav1.GroupVersion
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *recorderResourceManager) AddGroupVersion(groupName string, value apidiscoveryv2beta1.APIVersionDiscovery) {
 | 
					func (f *recorderResourceManager) AddGroupVersion(groupName string, value apidiscoveryv2.APIVersionDiscovery) {
 | 
				
			||||||
	f.lock.Lock()
 | 
						f.lock.Lock()
 | 
				
			||||||
	defer f.lock.Unlock()
 | 
						defer f.lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -153,7 +153,7 @@ func (f *recorderResourceManager) RemoveGroupVersion(gv metav1.GroupVersion) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (f *recorderResourceManager) SetGroups(values []apidiscoveryv2beta1.APIGroupDiscovery) {
 | 
					func (f *recorderResourceManager) SetGroups(values []apidiscoveryv2.APIGroupDiscovery) {
 | 
				
			||||||
	f.lock.Lock()
 | 
						f.lock.Lock()
 | 
				
			||||||
	defer f.lock.Unlock()
 | 
						defer f.lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,15 +17,22 @@ limitations under the License.
 | 
				
			|||||||
package aggregated
 | 
					package aggregated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
						"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/version"
 | 
						"k8s.io/apimachinery/pkg/version"
 | 
				
			||||||
 | 
						apidiscoveryv2conversion "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
 | 
						"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/metrics"
 | 
						"k8s.io/apiserver/pkg/endpoints/metrics"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
@@ -51,7 +58,7 @@ type ResourceManager interface {
 | 
				
			|||||||
	// Adds knowledge of the given groupversion to the discovery document
 | 
						// Adds knowledge of the given groupversion to the discovery document
 | 
				
			||||||
	// If it was already being tracked, updates the stored APIVersionDiscovery
 | 
						// If it was already being tracked, updates the stored APIVersionDiscovery
 | 
				
			||||||
	// Thread-safe
 | 
						// Thread-safe
 | 
				
			||||||
	AddGroupVersion(groupName string, value apidiscoveryv2beta1.APIVersionDiscovery)
 | 
						AddGroupVersion(groupName string, value apidiscoveryv2.APIVersionDiscovery)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Sets a priority to be used while sorting a specific group and
 | 
						// Sets a priority to be used while sorting a specific group and
 | 
				
			||||||
	// group-version. If two versions report different priorities for
 | 
						// group-version. If two versions report different priorities for
 | 
				
			||||||
@@ -72,7 +79,7 @@ type ResourceManager interface {
 | 
				
			|||||||
	// Resets the manager's known list of group-versions and replaces them
 | 
						// Resets the manager's known list of group-versions and replaces them
 | 
				
			||||||
	// with the given groups
 | 
						// with the given groups
 | 
				
			||||||
	// Thread-Safe
 | 
						// Thread-Safe
 | 
				
			||||||
	SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery)
 | 
						SetGroups([]apidiscoveryv2.APIGroupDiscovery)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Returns the same resource manager using a different source
 | 
						// Returns the same resource manager using a different source
 | 
				
			||||||
	// The source is used to decide how to de-duplicate groups.
 | 
						// The source is used to decide how to de-duplicate groups.
 | 
				
			||||||
@@ -87,7 +94,7 @@ type resourceManager struct {
 | 
				
			|||||||
	*resourceDiscoveryManager
 | 
						*resourceDiscoveryManager
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rm resourceManager) AddGroupVersion(groupName string, value apidiscoveryv2beta1.APIVersionDiscovery) {
 | 
					func (rm resourceManager) AddGroupVersion(groupName string, value apidiscoveryv2.APIVersionDiscovery) {
 | 
				
			||||||
	rm.resourceDiscoveryManager.AddGroupVersion(rm.source, groupName, value)
 | 
						rm.resourceDiscoveryManager.AddGroupVersion(rm.source, groupName, value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (rm resourceManager) SetGroupVersionPriority(gv metav1.GroupVersion, grouppriority, versionpriority int) {
 | 
					func (rm resourceManager) SetGroupVersionPriority(gv metav1.GroupVersion, grouppriority, versionpriority int) {
 | 
				
			||||||
@@ -99,7 +106,7 @@ func (rm resourceManager) RemoveGroup(groupName string) {
 | 
				
			|||||||
func (rm resourceManager) RemoveGroupVersion(gv metav1.GroupVersion) {
 | 
					func (rm resourceManager) RemoveGroupVersion(gv metav1.GroupVersion) {
 | 
				
			||||||
	rm.resourceDiscoveryManager.RemoveGroupVersion(rm.source, gv)
 | 
						rm.resourceDiscoveryManager.RemoveGroupVersion(rm.source, gv)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (rm resourceManager) SetGroups(groups []apidiscoveryv2beta1.APIGroupDiscovery) {
 | 
					func (rm resourceManager) SetGroups(groups []apidiscoveryv2.APIGroupDiscovery) {
 | 
				
			||||||
	rm.resourceDiscoveryManager.SetGroups(rm.source, groups)
 | 
						rm.resourceDiscoveryManager.SetGroups(rm.source, groups)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,7 +140,7 @@ type resourceDiscoveryManager struct {
 | 
				
			|||||||
	// Writes protected by the lock.
 | 
						// Writes protected by the lock.
 | 
				
			||||||
	// List of all apigroups & resources indexed by the resource manager
 | 
						// List of all apigroups & resources indexed by the resource manager
 | 
				
			||||||
	lock              sync.RWMutex
 | 
						lock              sync.RWMutex
 | 
				
			||||||
	apiGroups         map[groupKey]*apidiscoveryv2beta1.APIGroupDiscovery
 | 
						apiGroups         map[groupKey]*apidiscoveryv2.APIGroupDiscovery
 | 
				
			||||||
	versionPriorities map[groupVersionKey]priorityInfo
 | 
						versionPriorities map[groupVersionKey]priorityInfo
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,8 +151,12 @@ type priorityInfo struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func NewResourceManager(path string) ResourceManager {
 | 
					func NewResourceManager(path string) ResourceManager {
 | 
				
			||||||
	scheme := runtime.NewScheme()
 | 
						scheme := runtime.NewScheme()
 | 
				
			||||||
	codecs := serializer.NewCodecFactory(scheme)
 | 
						// Register conversion for apidiscovery
 | 
				
			||||||
 | 
						apidiscoveryv2.SchemeBuilder.Register(apidiscoveryv2conversion.RegisterConversions)
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2.AddToScheme(scheme))
 | 
				
			||||||
	utilruntime.Must(apidiscoveryv2beta1.AddToScheme(scheme))
 | 
						utilruntime.Must(apidiscoveryv2beta1.AddToScheme(scheme))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						codecs := serializer.NewCodecFactory(scheme)
 | 
				
			||||||
	rdm := &resourceDiscoveryManager{
 | 
						rdm := &resourceDiscoveryManager{
 | 
				
			||||||
		serializer:        codecs,
 | 
							serializer:        codecs,
 | 
				
			||||||
		versionPriorities: make(map[groupVersionKey]priorityInfo),
 | 
							versionPriorities: make(map[groupVersionKey]priorityInfo),
 | 
				
			||||||
@@ -181,7 +192,7 @@ func (rdm *resourceDiscoveryManager) SetGroupVersionPriority(source Source, gv m
 | 
				
			|||||||
	rdm.cache.Store(nil)
 | 
						rdm.cache.Store(nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rdm *resourceDiscoveryManager) SetGroups(source Source, groups []apidiscoveryv2beta1.APIGroupDiscovery) {
 | 
					func (rdm *resourceDiscoveryManager) SetGroups(source Source, groups []apidiscoveryv2.APIGroupDiscovery) {
 | 
				
			||||||
	rdm.lock.Lock()
 | 
						rdm.lock.Lock()
 | 
				
			||||||
	defer rdm.lock.Unlock()
 | 
						defer rdm.lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,17 +232,17 @@ func (rdm *resourceDiscoveryManager) SetGroups(source Source, groups []apidiscov
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rdm *resourceDiscoveryManager) AddGroupVersion(source Source, groupName string, value apidiscoveryv2beta1.APIVersionDiscovery) {
 | 
					func (rdm *resourceDiscoveryManager) AddGroupVersion(source Source, groupName string, value apidiscoveryv2.APIVersionDiscovery) {
 | 
				
			||||||
	rdm.lock.Lock()
 | 
						rdm.lock.Lock()
 | 
				
			||||||
	defer rdm.lock.Unlock()
 | 
						defer rdm.lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rdm.addGroupVersionLocked(source, groupName, value)
 | 
						rdm.addGroupVersionLocked(source, groupName, value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rdm *resourceDiscoveryManager) addGroupVersionLocked(source Source, groupName string, value apidiscoveryv2beta1.APIVersionDiscovery) {
 | 
					func (rdm *resourceDiscoveryManager) addGroupVersionLocked(source Source, groupName string, value apidiscoveryv2.APIVersionDiscovery) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if rdm.apiGroups == nil {
 | 
						if rdm.apiGroups == nil {
 | 
				
			||||||
		rdm.apiGroups = make(map[groupKey]*apidiscoveryv2beta1.APIGroupDiscovery)
 | 
							rdm.apiGroups = make(map[groupKey]*apidiscoveryv2.APIGroupDiscovery)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key := groupKey{
 | 
						key := groupKey{
 | 
				
			||||||
@@ -264,11 +275,11 @@ func (rdm *resourceDiscoveryManager) addGroupVersionLocked(source Source, groupN
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		group := &apidiscoveryv2beta1.APIGroupDiscovery{
 | 
							group := &apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
				Name: groupName,
 | 
									Name: groupName,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{value},
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{value},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rdm.apiGroups[key] = group
 | 
							rdm.apiGroups[key] = group
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -354,12 +365,12 @@ func (rdm *resourceDiscoveryManager) RemoveGroup(source Source, groupName string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Prepares the api group list for serving by converting them from map into
 | 
					// Prepares the api group list for serving by converting them from map into
 | 
				
			||||||
// list and sorting them according to insertion order
 | 
					// list and sorting them according to insertion order
 | 
				
			||||||
func (rdm *resourceDiscoveryManager) calculateAPIGroupsLocked() []apidiscoveryv2beta1.APIGroupDiscovery {
 | 
					func (rdm *resourceDiscoveryManager) calculateAPIGroupsLocked() []apidiscoveryv2.APIGroupDiscovery {
 | 
				
			||||||
	regenerationCounter.Inc()
 | 
						regenerationCounter.Inc()
 | 
				
			||||||
	// Re-order the apiGroups by their priority.
 | 
						// Re-order the apiGroups by their priority.
 | 
				
			||||||
	groups := []apidiscoveryv2beta1.APIGroupDiscovery{}
 | 
						groups := []apidiscoveryv2.APIGroupDiscovery{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	groupsToUse := map[string]apidiscoveryv2beta1.APIGroupDiscovery{}
 | 
						groupsToUse := map[string]apidiscoveryv2.APIGroupDiscovery{}
 | 
				
			||||||
	sourcesUsed := map[metav1.GroupVersion]Source{}
 | 
						sourcesUsed := map[metav1.GroupVersion]Source{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for key, group := range rdm.apiGroups {
 | 
						for key, group := range rdm.apiGroups {
 | 
				
			||||||
@@ -475,7 +486,7 @@ func (rdm *resourceDiscoveryManager) fetchFromCache() *cachedGroupList {
 | 
				
			|||||||
	if cacheLoad != nil {
 | 
						if cacheLoad != nil {
 | 
				
			||||||
		return cacheLoad
 | 
							return cacheLoad
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	response := apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
						response := apidiscoveryv2.APIGroupDiscoveryList{
 | 
				
			||||||
		Items: rdm.calculateAPIGroupsLocked(),
 | 
							Items: rdm.calculateAPIGroupsLocked(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	etag, err := calculateETag(response)
 | 
						etag, err := calculateETag(response)
 | 
				
			||||||
@@ -492,7 +503,13 @@ func (rdm *resourceDiscoveryManager) fetchFromCache() *cachedGroupList {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type cachedGroupList struct {
 | 
					type cachedGroupList struct {
 | 
				
			||||||
	cachedResponse     apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
						cachedResponse apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
 | 
						// etag is calculated based on a SHA hash of only the JSON object.
 | 
				
			||||||
 | 
						// A response via different Accept encodings (eg: protobuf, json) will
 | 
				
			||||||
 | 
						// yield the same etag. This is okay because Accept is part of the Vary header.
 | 
				
			||||||
 | 
						// Per RFC7231 a client must only cache a response etag pair if the header field
 | 
				
			||||||
 | 
						// matches as indicated by the Vary field. Thus, protobuf and json and other Accept
 | 
				
			||||||
 | 
						// encodings will not be cached as the same response despite having the same etag.
 | 
				
			||||||
	cachedResponseETag string
 | 
						cachedResponseETag string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -505,11 +522,30 @@ func (rdm *resourceDiscoveryManager) serveHTTP(resp http.ResponseWriter, req *ht
 | 
				
			|||||||
	response := cache.cachedResponse
 | 
						response := cache.cachedResponse
 | 
				
			||||||
	etag := cache.cachedResponseETag
 | 
						etag := cache.cachedResponseETag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mediaType, _, err := negotiation.NegotiateOutputMediaType(req, rdm.serializer, DiscoveryEndpointRestrictions)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// Should never happen. wrapper.go will only proxy requests to this
 | 
				
			||||||
 | 
							// handler if the media type passes DiscoveryEndpointRestrictions
 | 
				
			||||||
 | 
							utilruntime.HandleError(err)
 | 
				
			||||||
 | 
							resp.WriteHeader(http.StatusInternalServerError)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var targetGV schema.GroupVersion
 | 
				
			||||||
 | 
						if mediaType.Convert == nil ||
 | 
				
			||||||
 | 
							(mediaType.Convert.GroupVersion() != apidiscoveryv2.SchemeGroupVersion &&
 | 
				
			||||||
 | 
								mediaType.Convert.GroupVersion() != apidiscoveryv2beta1.SchemeGroupVersion) {
 | 
				
			||||||
 | 
							utilruntime.HandleError(fmt.Errorf("expected aggregated discovery group version, got group: %s, version %s", mediaType.Convert.Group, mediaType.Convert.Version))
 | 
				
			||||||
 | 
							resp.WriteHeader(http.StatusInternalServerError)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						targetGV = mediaType.Convert.GroupVersion()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(etag) > 0 {
 | 
						if len(etag) > 0 {
 | 
				
			||||||
		// Use proper e-tag headers if one is available
 | 
							// Use proper e-tag headers if one is available
 | 
				
			||||||
		ServeHTTPWithETag(
 | 
							ServeHTTPWithETag(
 | 
				
			||||||
			&response,
 | 
								&response,
 | 
				
			||||||
			etag,
 | 
								etag,
 | 
				
			||||||
 | 
								targetGV,
 | 
				
			||||||
			rdm.serializer,
 | 
								rdm.serializer,
 | 
				
			||||||
			resp,
 | 
								resp,
 | 
				
			||||||
			req,
 | 
								req,
 | 
				
			||||||
@@ -520,7 +556,7 @@ func (rdm *resourceDiscoveryManager) serveHTTP(resp http.ResponseWriter, req *ht
 | 
				
			|||||||
		responsewriters.WriteObjectNegotiated(
 | 
							responsewriters.WriteObjectNegotiated(
 | 
				
			||||||
			rdm.serializer,
 | 
								rdm.serializer,
 | 
				
			||||||
			DiscoveryEndpointRestrictions,
 | 
								DiscoveryEndpointRestrictions,
 | 
				
			||||||
			AggregatedDiscoveryGV,
 | 
								targetGV,
 | 
				
			||||||
			resp,
 | 
								resp,
 | 
				
			||||||
			req,
 | 
								req,
 | 
				
			||||||
			http.StatusOK,
 | 
								http.StatusOK,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,11 +32,15 @@ import (
 | 
				
			|||||||
	fuzz "github.com/google/gofuzz"
 | 
						fuzz "github.com/google/gofuzz"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
 | 
						runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
 | 
				
			||||||
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/version"
 | 
						"k8s.io/apimachinery/pkg/version"
 | 
				
			||||||
 | 
						apidiscoveryv2conversion "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
	discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
						discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,21 +50,23 @@ var codecs = runtimeserializer.NewCodecFactory(scheme)
 | 
				
			|||||||
const discoveryPath = "/apis"
 | 
					const discoveryPath = "/apis"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	// Add all builtin types to scheme
 | 
						// Register conversion for apidiscovery
 | 
				
			||||||
	apidiscoveryv2beta1.AddToScheme(scheme)
 | 
						apidiscoveryv2.SchemeBuilder.Register(apidiscoveryv2conversion.RegisterConversions)
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2.AddToScheme(scheme))
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2beta1.AddToScheme(scheme))
 | 
				
			||||||
	codecs = runtimeserializer.NewCodecFactory(scheme)
 | 
						codecs = runtimeserializer.NewCodecFactory(scheme)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2beta1.APIGroupDiscoveryList {
 | 
					func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2.APIGroupDiscoveryList {
 | 
				
			||||||
	fuzzer := fuzz.NewWithSeed(seed)
 | 
						fuzzer := fuzz.NewWithSeed(seed)
 | 
				
			||||||
	fuzzer.NumElements(atLeastNumGroups, maxNumGroups)
 | 
						fuzzer.NumElements(atLeastNumGroups, maxNumGroups)
 | 
				
			||||||
	fuzzer.NilChance(0)
 | 
						fuzzer.NilChance(0)
 | 
				
			||||||
	fuzzer.Funcs(func(o *apidiscoveryv2beta1.APIGroupDiscovery, c fuzz.Continue) {
 | 
						fuzzer.Funcs(func(o *apidiscoveryv2.APIGroupDiscovery, c fuzz.Continue) {
 | 
				
			||||||
		c.FuzzNoCustom(o)
 | 
							c.FuzzNoCustom(o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The ResourceManager will just not serve the group if its versions
 | 
							// The ResourceManager will just not serve the group if its versions
 | 
				
			||||||
		// list is empty
 | 
							// list is empty
 | 
				
			||||||
		atLeastOne := apidiscoveryv2beta1.APIVersionDiscovery{}
 | 
							atLeastOne := apidiscoveryv2.APIVersionDiscovery{}
 | 
				
			||||||
		c.Fuzz(&atLeastOne)
 | 
							c.Fuzz(&atLeastOne)
 | 
				
			||||||
		o.Versions = append(o.Versions, atLeastOne)
 | 
							o.Versions = append(o.Versions, atLeastOne)
 | 
				
			||||||
		sort.Slice(o.Versions[:], func(i, j int) bool {
 | 
							sort.Slice(o.Versions[:], func(i, j int) bool {
 | 
				
			||||||
@@ -75,28 +81,58 @@ func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var apis []apidiscoveryv2beta1.APIGroupDiscovery
 | 
						var apis []apidiscoveryv2.APIGroupDiscovery
 | 
				
			||||||
	fuzzer.Fuzz(&apis)
 | 
						fuzzer.Fuzz(&apis)
 | 
				
			||||||
	sort.Slice(apis[:], func(i, j int) bool {
 | 
						sort.Slice(apis[:], func(i, j int) bool {
 | 
				
			||||||
		return apis[i].Name < apis[j].Name
 | 
							return apis[i].Name < apis[j].Name
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
						return apidiscoveryv2.APIGroupDiscoveryList{
 | 
				
			||||||
		TypeMeta: metav1.TypeMeta{
 | 
							TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
			Kind:       "APIGroupDiscoveryList",
 | 
								Kind:       "APIGroupDiscoveryList",
 | 
				
			||||||
			APIVersion: "apidiscovery.k8s.io/v2beta1",
 | 
								APIVersion: "apidiscovery.k8s.io/v2",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Items: apis,
 | 
							Items: apis,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func fetchPath(handler http.Handler, acceptPrefix string, path string, etag string) (*http.Response, []byte, *apidiscoveryv2beta1.APIGroupDiscoveryList) {
 | 
					func fetchPathV2Beta1(handler http.Handler, acceptPrefix string, path string, etag string) (*http.Response, []byte, *apidiscoveryv2beta1.APIGroupDiscoveryList) {
 | 
				
			||||||
 | 
						acceptSuffix := ";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
						r, bytes := fetchPathHelper(handler, acceptPrefix+acceptSuffix, path, etag)
 | 
				
			||||||
 | 
						var decoded *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
 | 
						if len(bytes) > 0 {
 | 
				
			||||||
 | 
							decoded = &apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
							err := runtime.DecodeInto(codecs.UniversalDecoder(), bytes, decoded)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(fmt.Sprintf("failed to decode response: %v", err))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return r, bytes, decoded
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fetchPath(handler http.Handler, acceptPrefix string, path string, etag string) (*http.Response, []byte, *apidiscoveryv2.APIGroupDiscoveryList) {
 | 
				
			||||||
 | 
						acceptSuffix := ";g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList,"
 | 
				
			||||||
 | 
						acceptSuffixV2Beta1 := ";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList,"
 | 
				
			||||||
 | 
						r, bytes := fetchPathHelper(handler, acceptPrefix+acceptSuffix+","+acceptPrefix+acceptSuffixV2Beta1, path, etag)
 | 
				
			||||||
 | 
						var decoded *apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
 | 
						if len(bytes) > 0 {
 | 
				
			||||||
 | 
							decoded = &apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
							err := runtime.DecodeInto(codecs.UniversalDecoder(), bytes, decoded)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(fmt.Sprintf("failed to decode response: %v", err))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return r, bytes, decoded
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fetchPathHelper(handler http.Handler, accept string, path string, etag string) (*http.Response, []byte) {
 | 
				
			||||||
	// Expect json-formatted apis group list
 | 
						// Expect json-formatted apis group list
 | 
				
			||||||
	w := httptest.NewRecorder()
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
	req := httptest.NewRequest("GET", discoveryPath, nil)
 | 
						req := httptest.NewRequest("GET", discoveryPath, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Ask for JSON response
 | 
						// Ask for JSON response
 | 
				
			||||||
	req.Header.Set("Accept", acceptPrefix+";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList")
 | 
						req.Header.Set("Accept", accept)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if etag != "" {
 | 
						if etag != "" {
 | 
				
			||||||
		// Quote provided etag if unquoted
 | 
							// Quote provided etag if unquoted
 | 
				
			||||||
@@ -110,13 +146,7 @@ func fetchPath(handler http.Handler, acceptPrefix string, path string, etag stri
 | 
				
			|||||||
	handler.ServeHTTP(w, req)
 | 
						handler.ServeHTTP(w, req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bytes := w.Body.Bytes()
 | 
						bytes := w.Body.Bytes()
 | 
				
			||||||
	var decoded *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
						return w.Result(), bytes
 | 
				
			||||||
	if len(bytes) > 0 {
 | 
					 | 
				
			||||||
		decoded = &apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
					 | 
				
			||||||
		runtime.DecodeInto(codecs.UniversalDecoder(), bytes, decoded)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return w.Result(), bytes, decoded
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Add all builtin APIServices to the manager and check the output
 | 
					// Add all builtin APIServices to the manager and check the output
 | 
				
			||||||
@@ -132,7 +162,7 @@ func TestBasicResponse(t *testing.T) {
 | 
				
			|||||||
	require.NoError(t, err, "json marshal should always succeed")
 | 
						require.NoError(t, err, "json marshal should always succeed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, http.StatusOK, response.StatusCode, "response should be 200 OK")
 | 
						assert.Equal(t, http.StatusOK, response.StatusCode, "response should be 200 OK")
 | 
				
			||||||
	assert.Equal(t, "application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList", response.Header.Get("Content-Type"), "Content-Type response header should be as requested in Accept header if supported")
 | 
						assert.Equal(t, "application/json;g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList", response.Header.Get("Content-Type"), "Content-Type response header should be as requested in Accept header if supported")
 | 
				
			||||||
	assert.NotEmpty(t, response.Header.Get("ETag"), "E-Tag should be set")
 | 
						assert.NotEmpty(t, response.Header.Get("ETag"), "E-Tag should be set")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.NoError(t, err, "decode should always succeed")
 | 
						assert.NoError(t, err, "decode should always succeed")
 | 
				
			||||||
@@ -149,11 +179,39 @@ func TestBasicResponseProtobuf(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	response, _, decoded := fetchPath(manager, "application/vnd.kubernetes.protobuf", discoveryPath, "")
 | 
						response, _, decoded := fetchPath(manager, "application/vnd.kubernetes.protobuf", discoveryPath, "")
 | 
				
			||||||
	assert.Equal(t, http.StatusOK, response.StatusCode, "response should be 200 OK")
 | 
						assert.Equal(t, http.StatusOK, response.StatusCode, "response should be 200 OK")
 | 
				
			||||||
	assert.Equal(t, "application/vnd.kubernetes.protobuf;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList", response.Header.Get("Content-Type"), "Content-Type response header should be as requested in Accept header if supported")
 | 
						assert.Equal(t, "application/vnd.kubernetes.protobuf;g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList", response.Header.Get("Content-Type"), "Content-Type response header should be as requested in Accept header if supported")
 | 
				
			||||||
	assert.NotEmpty(t, response.Header.Get("ETag"), "E-Tag should be set")
 | 
						assert.NotEmpty(t, response.Header.Get("ETag"), "E-Tag should be set")
 | 
				
			||||||
	assert.EqualValues(t, &apis, decoded, "decoded value should equal input")
 | 
						assert.EqualValues(t, &apis, decoded, "decoded value should equal input")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// V2Beta1 should still be served
 | 
				
			||||||
 | 
					func TestV2Beta1SkewSupport(t *testing.T) {
 | 
				
			||||||
 | 
						manager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apis := fuzzAPIGroups(1, 3, 10)
 | 
				
			||||||
 | 
						manager.SetGroups(apis.Items)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						converted, err := scheme.ConvertToVersion(&apis, &schema.GroupVersion{Group: "apidiscovery.k8s.io", Version: "v2beta1"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v2beta1apis := converted.(*apidiscoveryv2beta1.APIGroupDiscoveryList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response, body, decoded := fetchPathV2Beta1(manager, "application/json", discoveryPath, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						jsonFormatted, err := json.Marshal(v2beta1apis)
 | 
				
			||||||
 | 
						require.NoError(t, err, "json marshal should always succeed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, http.StatusOK, response.StatusCode, "response should be 200 OK")
 | 
				
			||||||
 | 
						assert.Equal(t, "application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList", response.Header.Get("Content-Type"), "Content-Type response header should be as requested in Accept header if supported")
 | 
				
			||||||
 | 
						assert.NotEmpty(t, response.Header.Get("ETag"), "E-Tag should be set")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.NoError(t, err, "decode should always succeed")
 | 
				
			||||||
 | 
						assert.EqualValues(t, v2beta1apis, decoded, "decoded value should equal input")
 | 
				
			||||||
 | 
						assert.Equal(t, string(jsonFormatted)+"\n", string(body), "response should be the api group list")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test that an etag associated with the service only depends on the apiresources
 | 
					// Test that an etag associated with the service only depends on the apiresources
 | 
				
			||||||
// e.g.: Multiple services with the same contents should have the same etag.
 | 
					// e.g.: Multiple services with the same contents should have the same etag.
 | 
				
			||||||
func TestEtagConsistent(t *testing.T) {
 | 
					func TestEtagConsistent(t *testing.T) {
 | 
				
			||||||
@@ -348,7 +406,7 @@ func TestUpdateService(t *testing.T) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var newapis apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
						var newapis apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
	err = json.Unmarshal(b, &newapis)
 | 
						err = json.Unmarshal(b, &newapis)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
@@ -369,7 +427,7 @@ func TestUpdateService(t *testing.T) {
 | 
				
			|||||||
func TestMultipleSources(t *testing.T) {
 | 
					func TestMultipleSources(t *testing.T) {
 | 
				
			||||||
	type pair struct {
 | 
						type pair struct {
 | 
				
			||||||
		manager discoveryendpoint.ResourceManager
 | 
							manager discoveryendpoint.ResourceManager
 | 
				
			||||||
		apis    apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
							apis    apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pairs := []pair{}
 | 
						pairs := []pair{}
 | 
				
			||||||
@@ -388,7 +446,7 @@ func TestMultipleSources(t *testing.T) {
 | 
				
			|||||||
		pairs = append(pairs, pair{manager, apis})
 | 
							pairs = append(pairs, pair{manager, apis})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expectedResult := []apidiscoveryv2beta1.APIGroupDiscovery{}
 | 
						expectedResult := []apidiscoveryv2.APIGroupDiscovery{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	groupCounter := 0
 | 
						groupCounter := 0
 | 
				
			||||||
	for _, p := range pairs {
 | 
						for _, p := range pairs {
 | 
				
			||||||
@@ -422,7 +480,7 @@ func TestSourcePrecedence(t *testing.T) {
 | 
				
			|||||||
	apis := fuzzAPIGroups(1, 3, int64(15))
 | 
						apis := fuzzAPIGroups(1, 3, int64(15))
 | 
				
			||||||
	for _, g := range apis.Items {
 | 
						for _, g := range apis.Items {
 | 
				
			||||||
		for i, v := range g.Versions {
 | 
							for i, v := range g.Versions {
 | 
				
			||||||
			v.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessCurrent
 | 
								v.Freshness = apidiscoveryv2.DiscoveryFreshnessCurrent
 | 
				
			||||||
			g.Versions[i] = v
 | 
								g.Versions[i] = v
 | 
				
			||||||
			otherManager.AddGroupVersion(g.Name, v)
 | 
								otherManager.AddGroupVersion(g.Name, v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -434,12 +492,12 @@ func TestSourcePrecedence(t *testing.T) {
 | 
				
			|||||||
	// Add the first groupversion under default.
 | 
						// Add the first groupversion under default.
 | 
				
			||||||
	// No versions should appear in discovery document except this one
 | 
						// No versions should appear in discovery document except this one
 | 
				
			||||||
	overrideVersion := initialDocument.Items[0].Versions[0]
 | 
						overrideVersion := initialDocument.Items[0].Versions[0]
 | 
				
			||||||
	overrideVersion.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessStale
 | 
						overrideVersion.Freshness = apidiscoveryv2.DiscoveryFreshnessStale
 | 
				
			||||||
	defaultManager.AddGroupVersion(initialDocument.Items[0].Name, overrideVersion)
 | 
						defaultManager.AddGroupVersion(initialDocument.Items[0].Name, overrideVersion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, _, maskedDocument := fetchPath(defaultManager, "application/json", discoveryPath, "")
 | 
						_, _, maskedDocument := fetchPath(defaultManager, "application/json", discoveryPath, "")
 | 
				
			||||||
	masked := initialDocument.DeepCopy()
 | 
						masked := initialDocument.DeepCopy()
 | 
				
			||||||
	masked.Items[0].Versions[0].Freshness = apidiscoveryv2beta1.DiscoveryFreshnessStale
 | 
						masked.Items[0].Versions[0].Freshness = apidiscoveryv2.DiscoveryFreshnessStale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	require.Equal(t, masked.Items, maskedDocument.Items)
 | 
						require.Equal(t, masked.Items, maskedDocument.Items)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -593,19 +651,19 @@ func TestAbuse(t *testing.T) {
 | 
				
			|||||||
func TestVersionSortingNoPriority(t *testing.T) {
 | 
					func TestVersionSortingNoPriority(t *testing.T) {
 | 
				
			||||||
	manager := discoveryendpoint.NewResourceManager("apis")
 | 
						manager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1alpha1",
 | 
							Version: "v1alpha1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v2beta1",
 | 
							Version: "v2beta1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1",
 | 
							Version: "v1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1beta1",
 | 
							Version: "v1beta1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v2",
 | 
							Version: "v2",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -625,11 +683,11 @@ func TestVersionSortingNoPriority(t *testing.T) {
 | 
				
			|||||||
func TestVersionSortingWithPriority(t *testing.T) {
 | 
					func TestVersionSortingWithPriority(t *testing.T) {
 | 
				
			||||||
	manager := discoveryendpoint.NewResourceManager("apis")
 | 
						manager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1",
 | 
							Version: "v1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1alpha1",
 | 
							Version: "v1alpha1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1alpha1"}, 1000, 200)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1alpha1"}, 1000, 200)
 | 
				
			||||||
@@ -648,15 +706,15 @@ func TestVersionSortingWithPriority(t *testing.T) {
 | 
				
			|||||||
func TestGroupVersionSortingConflictingPriority(t *testing.T) {
 | 
					func TestGroupVersionSortingConflictingPriority(t *testing.T) {
 | 
				
			||||||
	manager := discoveryendpoint.NewResourceManager("apis")
 | 
						manager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1",
 | 
							Version: "v1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
 | 
				
			||||||
	manager.AddGroupVersion("test", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("test", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1alpha1",
 | 
							Version: "v1alpha1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 500, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 500, 100)
 | 
				
			||||||
	manager.AddGroupVersion("test", apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion("test", apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1alpha2",
 | 
							Version: "v1alpha2",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 2000, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 2000, 100)
 | 
				
			||||||
@@ -679,17 +737,17 @@ func TestStatelessGroupPriorityMinimum(t *testing.T) {
 | 
				
			|||||||
	stableGroup := "stable.example.com"
 | 
						stableGroup := "stable.example.com"
 | 
				
			||||||
	experimentalGroup := "experimental.example.com"
 | 
						experimentalGroup := "experimental.example.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion(stableGroup, apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion(stableGroup, apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1",
 | 
							Version: "v1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: stableGroup, Version: "v1"}, 1000, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: stableGroup, Version: "v1"}, 1000, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion(experimentalGroup, apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion(experimentalGroup, apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1",
 | 
							Version: "v1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1"}, 100, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1"}, 100, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manager.AddGroupVersion(experimentalGroup, apidiscoveryv2beta1.APIVersionDiscovery{
 | 
						manager.AddGroupVersion(experimentalGroup, apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
		Version: "v1alpha1",
 | 
							Version: "v1alpha1",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1alpha1"}, 10000, 100)
 | 
						manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1alpha1"}, 10000, 100)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,6 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var AggregatedDiscoveryGV = schema.GroupVersion{Group: "apidiscovery.k8s.io", Version: "v2beta1"}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Interface is from "k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
 | 
					// Interface is from "k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DiscoveryEndpointRestrictions allows requests to /apis to provide a Content Negotiation GVK for aggregated discovery.
 | 
					// DiscoveryEndpointRestrictions allows requests to /apis to provide a Content Negotiation GVK for aggregated discovery.
 | 
				
			||||||
@@ -39,7 +37,7 @@ func (discoveryEndpointRestrictions) AllowsStreamSchema(s string) bool { return
 | 
				
			|||||||
// IsAggregatedDiscoveryGVK checks if a provided GVK is the GVK for serving aggregated discovery.
 | 
					// IsAggregatedDiscoveryGVK checks if a provided GVK is the GVK for serving aggregated discovery.
 | 
				
			||||||
func IsAggregatedDiscoveryGVK(gvk *schema.GroupVersionKind) bool {
 | 
					func IsAggregatedDiscoveryGVK(gvk *schema.GroupVersionKind) bool {
 | 
				
			||||||
	if gvk != nil {
 | 
						if gvk != nil {
 | 
				
			||||||
		return gvk.Group == "apidiscovery.k8s.io" && gvk.Version == "v2beta1" && gvk.Kind == "APIGroupDiscoveryList"
 | 
							return gvk.Group == "apidiscovery.k8s.io" && (gvk.Version == "v2beta1" || gvk.Version == "v2") && gvk.Kind == "APIGroupDiscoveryList"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,10 @@ package aggregated
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
						"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
				
			||||||
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/emicklei/go-restful/v3"
 | 
						"github.com/emicklei/go-restful/v3"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -69,10 +71,11 @@ func (wrapped *WrappedHandler) GenerateWebService(prefix string, returnType inte
 | 
				
			|||||||
// WrapAggregatedDiscoveryToHandler wraps a handler with an option to
 | 
					// WrapAggregatedDiscoveryToHandler wraps a handler with an option to
 | 
				
			||||||
// emit the aggregated discovery by passing in the aggregated
 | 
					// emit the aggregated discovery by passing in the aggregated
 | 
				
			||||||
// discovery type in content negotiation headers: eg: (Accept:
 | 
					// discovery type in content negotiation headers: eg: (Accept:
 | 
				
			||||||
// application/json;v=v2beta1;g=apidiscovery.k8s.io;as=APIGroupDiscoveryList)
 | 
					// application/json;v=v2;g=apidiscovery.k8s.io;as=APIGroupDiscoveryList)
 | 
				
			||||||
func WrapAggregatedDiscoveryToHandler(handler http.Handler, aggHandler http.Handler) *WrappedHandler {
 | 
					func WrapAggregatedDiscoveryToHandler(handler http.Handler, aggHandler http.Handler) *WrappedHandler {
 | 
				
			||||||
	scheme := runtime.NewScheme()
 | 
						scheme := runtime.NewScheme()
 | 
				
			||||||
	apidiscoveryv2beta1.AddToScheme(scheme)
 | 
						utilruntime.Must(apidiscoveryv2.AddToScheme(scheme))
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2beta1.AddToScheme(scheme))
 | 
				
			||||||
	codecs := serializer.NewCodecFactory(scheme)
 | 
						codecs := serializer.NewCodecFactory(scheme)
 | 
				
			||||||
	return &WrappedHandler{codecs, handler, aggHandler}
 | 
						return &WrappedHandler{codecs, handler, aggHandler}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,8 +32,11 @@ import (
 | 
				
			|||||||
const discoveryPath = "/apis"
 | 
					const discoveryPath = "/apis"
 | 
				
			||||||
const jsonAccept = "application/json"
 | 
					const jsonAccept = "application/json"
 | 
				
			||||||
const protobufAccept = "application/vnd.kubernetes.protobuf"
 | 
					const protobufAccept = "application/vnd.kubernetes.protobuf"
 | 
				
			||||||
const aggregatedAcceptSuffix = ";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
					const aggregatedV2Beta1AcceptSuffix = ";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
					const aggregatedAcceptSuffix = ";g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const aggregatedV2Beta1JSONAccept = jsonAccept + aggregatedV2Beta1AcceptSuffix
 | 
				
			||||||
 | 
					const aggregatedV2Beta1ProtoAccept = protobufAccept + aggregatedV2Beta1AcceptSuffix
 | 
				
			||||||
const aggregatedJSONAccept = jsonAccept + aggregatedAcceptSuffix
 | 
					const aggregatedJSONAccept = jsonAccept + aggregatedAcceptSuffix
 | 
				
			||||||
const aggregatedProtoAccept = protobufAccept + aggregatedAcceptSuffix
 | 
					const aggregatedProtoAccept = protobufAccept + aggregatedAcceptSuffix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,6 +78,12 @@ func TestAggregationEnabled(t *testing.T) {
 | 
				
			|||||||
			// Empty accept headers are valid and should be handled by the unaggregated handler
 | 
								// Empty accept headers are valid and should be handled by the unaggregated handler
 | 
				
			||||||
			accept:   "",
 | 
								accept:   "",
 | 
				
			||||||
			expected: "unaggregated",
 | 
								expected: "unaggregated",
 | 
				
			||||||
 | 
							}, {
 | 
				
			||||||
 | 
								accept:   aggregatedV2Beta1JSONAccept,
 | 
				
			||||||
 | 
								expected: "aggregated",
 | 
				
			||||||
 | 
							}, {
 | 
				
			||||||
 | 
								accept:   aggregatedV2Beta1ProtoAccept,
 | 
				
			||||||
 | 
								expected: "aggregated",
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
			accept:   aggregatedJSONAccept,
 | 
								accept:   aggregatedJSONAccept,
 | 
				
			||||||
			expected: "aggregated",
 | 
								expected: "aggregated",
 | 
				
			||||||
@@ -103,54 +112,3 @@ func TestAggregationEnabled(t *testing.T) {
 | 
				
			|||||||
		assert.Equal(t, tc.expected, body)
 | 
							assert.Equal(t, tc.expected, body)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestAggregationDisabled(t *testing.T) {
 | 
					 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.AggregatedDiscoveryEndpoint, false)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unaggregated := fakeHTTPHandler{data: "unaggregated"}
 | 
					 | 
				
			||||||
	aggregated := fakeHTTPHandler{data: "aggregated"}
 | 
					 | 
				
			||||||
	wrapped := WrapAggregatedDiscoveryToHandler(unaggregated, aggregated)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	testCases := []struct {
 | 
					 | 
				
			||||||
		accept   string
 | 
					 | 
				
			||||||
		expected string
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			// Misconstructed/incorrect accept headers should be passed to the unaggregated handler to return an error
 | 
					 | 
				
			||||||
			accept:   "application/json;foo=bar",
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			// Empty accept headers are valid and should be handled by the unaggregated handler
 | 
					 | 
				
			||||||
			accept:   "",
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			accept:   aggregatedJSONAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			accept:   aggregatedProtoAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			accept:   jsonAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			accept:   protobufAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			// Server should return the first accepted type.
 | 
					 | 
				
			||||||
			// If aggregation is disabled, the unaggregated type should be returned.
 | 
					 | 
				
			||||||
			accept:   aggregatedJSONAccept + "," + jsonAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			// Server should return the first accepted type.
 | 
					 | 
				
			||||||
			// If aggregation is disabled, the unaggregated type should be returned.
 | 
					 | 
				
			||||||
			accept:   aggregatedProtoAccept + "," + protobufAccept,
 | 
					 | 
				
			||||||
			expected: "unaggregated",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tc := range testCases {
 | 
					 | 
				
			||||||
		body := fetchPath(wrapped, discoveryPath, tc.accept)
 | 
					 | 
				
			||||||
		assert.Equal(t, tc.expected, body)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	restful "github.com/emicklei/go-restful/v3"
 | 
						restful "github.com/emicklei/go-restful/v3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
@@ -107,7 +107,7 @@ type APIGroupVersion struct {
 | 
				
			|||||||
// InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
 | 
					// InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
 | 
				
			||||||
// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
 | 
					// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
 | 
				
			||||||
// in a slash.
 | 
					// in a slash.
 | 
				
			||||||
func (g *APIGroupVersion) InstallREST(container *restful.Container) ([]apidiscoveryv2beta1.APIResourceDiscovery, []*storageversion.ResourceInfo, error) {
 | 
					func (g *APIGroupVersion) InstallREST(container *restful.Container) ([]apidiscoveryv2.APIResourceDiscovery, []*storageversion.ResourceInfo, error) {
 | 
				
			||||||
	prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)
 | 
						prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)
 | 
				
			||||||
	installer := &APIInstaller{
 | 
						installer := &APIInstaller{
 | 
				
			||||||
		group:             g,
 | 
							group:             g,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ import (
 | 
				
			|||||||
	restful "github.com/emicklei/go-restful/v3"
 | 
						restful "github.com/emicklei/go-restful/v3"
 | 
				
			||||||
	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
 | 
						"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/conversion"
 | 
						"k8s.io/apimachinery/pkg/conversion"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -71,8 +71,8 @@ type action struct {
 | 
				
			|||||||
	AllNamespaces bool // true iff the action is namespaced but works on aggregate result for all namespaces
 | 
						AllNamespaces bool // true iff the action is namespaced but works on aggregate result for all namespaces
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscoveryv2beta1.APIResourceDiscovery, error) {
 | 
					func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscoveryv2.APIResourceDiscovery, error) {
 | 
				
			||||||
	var apiResourceList []apidiscoveryv2beta1.APIResourceDiscovery
 | 
						var apiResourceList []apidiscoveryv2.APIResourceDiscovery
 | 
				
			||||||
	parentResources := make(map[string]int)
 | 
						parentResources := make(map[string]int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Loop through all top-level resources
 | 
						// Loop through all top-level resources
 | 
				
			||||||
@@ -82,14 +82,14 @@ func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscove
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var scope apidiscoveryv2beta1.ResourceScope
 | 
							var scope apidiscoveryv2.ResourceScope
 | 
				
			||||||
		if r.Namespaced {
 | 
							if r.Namespaced {
 | 
				
			||||||
			scope = apidiscoveryv2beta1.ScopeNamespace
 | 
								scope = apidiscoveryv2.ScopeNamespace
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			scope = apidiscoveryv2beta1.ScopeCluster
 | 
								scope = apidiscoveryv2.ScopeCluster
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		resource := apidiscoveryv2beta1.APIResourceDiscovery{
 | 
							resource := apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
			Resource: r.Name,
 | 
								Resource: r.Name,
 | 
				
			||||||
			Scope:    scope,
 | 
								Scope:    scope,
 | 
				
			||||||
			ResponseKind: &metav1.GroupVersionKind{
 | 
								ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
@@ -116,17 +116,17 @@ func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscove
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var scope apidiscoveryv2beta1.ResourceScope
 | 
							var scope apidiscoveryv2.ResourceScope
 | 
				
			||||||
		if r.Namespaced {
 | 
							if r.Namespaced {
 | 
				
			||||||
			scope = apidiscoveryv2beta1.ScopeNamespace
 | 
								scope = apidiscoveryv2.ScopeNamespace
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			scope = apidiscoveryv2beta1.ScopeCluster
 | 
								scope = apidiscoveryv2.ScopeCluster
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		parentidx, exists := parentResources[split[0]]
 | 
							parentidx, exists := parentResources[split[0]]
 | 
				
			||||||
		if !exists {
 | 
							if !exists {
 | 
				
			||||||
			// If a subresource exists without a parent, create a parent
 | 
								// If a subresource exists without a parent, create a parent
 | 
				
			||||||
			apiResourceList = append(apiResourceList, apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								apiResourceList = append(apiResourceList, apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				Resource: split[0],
 | 
									Resource: split[0],
 | 
				
			||||||
				Scope:    scope,
 | 
									Scope:    scope,
 | 
				
			||||||
				// avoid nil panics in v0.26.0-v0.26.3 client-go clients
 | 
									// avoid nil panics in v0.26.0-v0.26.3 client-go clients
 | 
				
			||||||
@@ -142,7 +142,7 @@ func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscove
 | 
				
			|||||||
			//
 | 
								//
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		subresource := apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
							subresource := apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
			Subresource: split[1],
 | 
								Subresource: split[1],
 | 
				
			||||||
			Verbs:       r.Verbs,
 | 
								Verbs:       r.Verbs,
 | 
				
			||||||
			// avoid nil panics in v0.26.0-v0.26.3 client-go clients
 | 
								// avoid nil panics in v0.26.0-v0.26.3 client-go clients
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,7 +106,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name                     string
 | 
							name                     string
 | 
				
			||||||
		resources                []metav1.APIResource
 | 
							resources                []metav1.APIResource
 | 
				
			||||||
		wantAPIResourceDiscovery []apidiscoveryv2beta1.APIResourceDiscovery
 | 
							wantAPIResourceDiscovery []apidiscoveryv2.APIResourceDiscovery
 | 
				
			||||||
		wantErr                  bool
 | 
							wantErr                  bool
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -121,10 +121,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "pods",
 | 
										Resource: "pods",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Kind: "Pod",
 | 
											Kind: "Pod",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -146,10 +146,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "cronjobs",
 | 
										Resource: "cronjobs",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   "batch",
 | 
											Group:   "batch",
 | 
				
			||||||
						Version: "v1",
 | 
											Version: "v1",
 | 
				
			||||||
@@ -182,10 +182,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "cronjobs",
 | 
										Resource: "cronjobs",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   "batch",
 | 
											Group:   "batch",
 | 
				
			||||||
						Version: "v1",
 | 
											Version: "v1",
 | 
				
			||||||
@@ -193,7 +193,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
					ShortNames: []string{"cj"},
 | 
										ShortNames: []string{"cj"},
 | 
				
			||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
					Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
 | 
										Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
 | 
				
			||||||
						Subresource: "status",
 | 
											Subresource: "status",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{
 | 
											ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
							Group:   "batch",
 | 
												Group:   "batch",
 | 
				
			||||||
@@ -245,10 +245,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "cronjobs",
 | 
										Resource: "cronjobs",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   "batch",
 | 
											Group:   "batch",
 | 
				
			||||||
						Version: "v1",
 | 
											Version: "v1",
 | 
				
			||||||
@@ -256,7 +256,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
					ShortNames: []string{"cj"},
 | 
										ShortNames: []string{"cj"},
 | 
				
			||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
					Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
 | 
										Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
 | 
				
			||||||
						Subresource: "status",
 | 
											Subresource: "status",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{
 | 
											ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
							Group:   "batch",
 | 
												Group:   "batch",
 | 
				
			||||||
@@ -267,7 +267,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					}},
 | 
										}},
 | 
				
			||||||
				}, {
 | 
									}, {
 | 
				
			||||||
					Resource: "deployments",
 | 
										Resource: "deployments",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Group:   "apps",
 | 
											Group:   "apps",
 | 
				
			||||||
						Version: "v1",
 | 
											Version: "v1",
 | 
				
			||||||
@@ -275,7 +275,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
					ShortNames: []string{"deploy"},
 | 
										ShortNames: []string{"deploy"},
 | 
				
			||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
					Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
 | 
										Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
 | 
				
			||||||
						Subresource: "status",
 | 
											Subresource: "status",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{
 | 
											ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
							Group:   "apps",
 | 
												Group:   "apps",
 | 
				
			||||||
@@ -298,13 +298,13 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "cronjobs",
 | 
										Resource: "cronjobs",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					// populated to avoid nil panics
 | 
										// populated to avoid nil panics
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{},
 | 
										ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
					Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
 | 
										Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
 | 
				
			||||||
						Subresource: "status",
 | 
											Subresource: "status",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{
 | 
											ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
							Group:   "batch",
 | 
												Group:   "batch",
 | 
				
			||||||
@@ -327,13 +327,13 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "cronjobs",
 | 
										Resource: "cronjobs",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					// populated to avoid nil panics
 | 
										// populated to avoid nil panics
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{},
 | 
										ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
					Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
 | 
										Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
 | 
				
			||||||
						Subresource: "status",
 | 
											Subresource: "status",
 | 
				
			||||||
						// populated to avoid nil panics
 | 
											// populated to avoid nil panics
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{},
 | 
											ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
@@ -364,7 +364,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{},
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{},
 | 
				
			||||||
			wantErr:                  true,
 | 
								wantErr:                  true,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -378,10 +378,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "nodes",
 | 
										Resource: "nodes",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeCluster,
 | 
										Scope:    apidiscoveryv2.ScopeCluster,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Kind: "Node",
 | 
											Kind: "Node",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -401,10 +401,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:      []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource: "nodes",
 | 
										Resource: "nodes",
 | 
				
			||||||
					Scope:    apidiscoveryv2beta1.ScopeNamespace,
 | 
										Scope:    apidiscoveryv2.ScopeNamespace,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Kind: "Node",
 | 
											Kind: "Node",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -424,11 +424,11 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
 | 
				
			|||||||
					Verbs:        []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
										Verbs:        []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
								wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Resource:         "nodes",
 | 
										Resource:         "nodes",
 | 
				
			||||||
					SingularResource: "node",
 | 
										SingularResource: "node",
 | 
				
			||||||
					Scope:            apidiscoveryv2beta1.ScopeCluster,
 | 
										Scope:            apidiscoveryv2.ScopeCluster,
 | 
				
			||||||
					ResponseKind: &metav1.GroupVersionKind{
 | 
										ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
						Kind: "Node",
 | 
											Kind: "Node",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@ const (
 | 
				
			|||||||
	// owner: @jefftree @alexzielenski
 | 
						// owner: @jefftree @alexzielenski
 | 
				
			||||||
	// alpha: v1.26
 | 
						// alpha: v1.26
 | 
				
			||||||
	// beta: v1.27
 | 
						// beta: v1.27
 | 
				
			||||||
 | 
						// stable: v1.30
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// Enables an single HTTP endpoint /discovery/<version> which supports native HTTP
 | 
						// Enables an single HTTP endpoint /discovery/<version> which supports native HTTP
 | 
				
			||||||
	// caching with ETags containing all APIResources known to the apiserver.
 | 
						// caching with ETags containing all APIResources known to the apiserver.
 | 
				
			||||||
@@ -284,7 +285,7 @@ func init() {
 | 
				
			|||||||
// available throughout Kubernetes binaries.
 | 
					// available throughout Kubernetes binaries.
 | 
				
			||||||
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
 | 
					var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.Beta},
 | 
						AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
						AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ import (
 | 
				
			|||||||
	systemd "github.com/coreos/go-systemd/v22/daemon"
 | 
						systemd "github.com/coreos/go-systemd/v22/daemon"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/time/rate"
 | 
						"golang.org/x/time/rate"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						"k8s.io/apimachinery/pkg/api/meta"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -756,8 +756,8 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
 | 
				
			|||||||
			if apiPrefix == APIGroupPrefix {
 | 
								if apiPrefix == APIGroupPrefix {
 | 
				
			||||||
				s.AggregatedDiscoveryGroupManager.AddGroupVersion(
 | 
									s.AggregatedDiscoveryGroupManager.AddGroupVersion(
 | 
				
			||||||
					groupVersion.Group,
 | 
										groupVersion.Group,
 | 
				
			||||||
					apidiscoveryv2beta1.APIVersionDiscovery{
 | 
										apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
						Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
											Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
						Version:   groupVersion.Version,
 | 
											Version:   groupVersion.Version,
 | 
				
			||||||
						Resources: discoveryAPIResources,
 | 
											Resources: discoveryAPIResources,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -766,8 +766,8 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
 | 
				
			|||||||
				// There is only one group version for legacy resources, priority can be defaulted to 0.
 | 
									// There is only one group version for legacy resources, priority can be defaulted to 0.
 | 
				
			||||||
				s.AggregatedLegacyDiscoveryGroupManager.AddGroupVersion(
 | 
									s.AggregatedLegacyDiscoveryGroupManager.AddGroupVersion(
 | 
				
			||||||
					groupVersion.Group,
 | 
										groupVersion.Group,
 | 
				
			||||||
					apidiscoveryv2beta1.APIVersionDiscovery{
 | 
										apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
						Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
											Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
						Version:   groupVersion.Version,
 | 
											Version:   groupVersion.Version,
 | 
				
			||||||
						Resources: discoveryAPIResources,
 | 
											Resources: discoveryAPIResources,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,8 @@ package discovery
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscovery "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -154,3 +155,124 @@ func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubreso
 | 
				
			|||||||
	result.Verbs = in.Verbs
 | 
						result.Verbs = in.Verbs
 | 
				
			||||||
	return result, nil
 | 
						return result, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Please note the functions below will be removed in v1.33. They facilitate conversion
 | 
				
			||||||
 | 
					// between the deprecated type apidiscoveryv2beta1.APIGroupDiscoveryList.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SplitGroupsAndResourcesV2Beta1 transforms "aggregated" discovery top-level structure into
 | 
				
			||||||
 | 
					// the previous "unaggregated" discovery groups and resources.
 | 
				
			||||||
 | 
					// Deprecated: Please use SplitGroupsAndResources
 | 
				
			||||||
 | 
					func SplitGroupsAndResourcesV2Beta1(aggregatedGroups apidiscoveryv2beta1.APIGroupDiscoveryList) (
 | 
				
			||||||
 | 
						*metav1.APIGroupList,
 | 
				
			||||||
 | 
						map[schema.GroupVersion]*metav1.APIResourceList,
 | 
				
			||||||
 | 
						map[schema.GroupVersion]error) {
 | 
				
			||||||
 | 
						// Aggregated group list will contain the entirety of discovery, including
 | 
				
			||||||
 | 
						// groups, versions, and resources. GroupVersions marked "stale" are failed.
 | 
				
			||||||
 | 
						groups := []*metav1.APIGroup{}
 | 
				
			||||||
 | 
						failedGVs := map[schema.GroupVersion]error{}
 | 
				
			||||||
 | 
						resourcesByGV := map[schema.GroupVersion]*metav1.APIResourceList{}
 | 
				
			||||||
 | 
						for _, aggGroup := range aggregatedGroups.Items {
 | 
				
			||||||
 | 
							group, resources, failed := convertAPIGroupv2beta1(aggGroup)
 | 
				
			||||||
 | 
							groups = append(groups, group)
 | 
				
			||||||
 | 
							for gv, resourceList := range resources {
 | 
				
			||||||
 | 
								resourcesByGV[gv] = resourceList
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for gv, err := range failed {
 | 
				
			||||||
 | 
								failedGVs[gv] = err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Transform slice of groups to group list before returning.
 | 
				
			||||||
 | 
						groupList := &metav1.APIGroupList{}
 | 
				
			||||||
 | 
						groupList.Groups = make([]metav1.APIGroup, 0, len(groups))
 | 
				
			||||||
 | 
						for _, group := range groups {
 | 
				
			||||||
 | 
							groupList.Groups = append(groupList.Groups, *group)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return groupList, resourcesByGV, failedGVs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convertAPIGroupv2beta1 tranforms an "aggregated" APIGroupDiscovery to an "legacy" APIGroup,
 | 
				
			||||||
 | 
					// also returning the map of APIResourceList for resources within GroupVersions.
 | 
				
			||||||
 | 
					func convertAPIGroupv2beta1(g apidiscoveryv2beta1.APIGroupDiscovery) (
 | 
				
			||||||
 | 
						*metav1.APIGroup,
 | 
				
			||||||
 | 
						map[schema.GroupVersion]*metav1.APIResourceList,
 | 
				
			||||||
 | 
						map[schema.GroupVersion]error) {
 | 
				
			||||||
 | 
						// Iterate through versions to convert to group and resources.
 | 
				
			||||||
 | 
						group := &metav1.APIGroup{}
 | 
				
			||||||
 | 
						gvResources := map[schema.GroupVersion]*metav1.APIResourceList{}
 | 
				
			||||||
 | 
						failedGVs := map[schema.GroupVersion]error{}
 | 
				
			||||||
 | 
						group.Name = g.ObjectMeta.Name
 | 
				
			||||||
 | 
						for _, v := range g.Versions {
 | 
				
			||||||
 | 
							gv := schema.GroupVersion{Group: g.Name, Version: v.Version}
 | 
				
			||||||
 | 
							if v.Freshness == apidiscoveryv2beta1.DiscoveryFreshnessStale {
 | 
				
			||||||
 | 
								failedGVs[gv] = StaleGroupVersionError{gv: gv}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							version := metav1.GroupVersionForDiscovery{}
 | 
				
			||||||
 | 
							version.GroupVersion = gv.String()
 | 
				
			||||||
 | 
							version.Version = v.Version
 | 
				
			||||||
 | 
							group.Versions = append(group.Versions, version)
 | 
				
			||||||
 | 
							// PreferredVersion is first non-stale Version
 | 
				
			||||||
 | 
							if group.PreferredVersion == (metav1.GroupVersionForDiscovery{}) {
 | 
				
			||||||
 | 
								group.PreferredVersion = version
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							resourceList := &metav1.APIResourceList{}
 | 
				
			||||||
 | 
							resourceList.GroupVersion = gv.String()
 | 
				
			||||||
 | 
							for _, r := range v.Resources {
 | 
				
			||||||
 | 
								resource, err := convertAPIResourcev2beta1(r)
 | 
				
			||||||
 | 
								if err == nil {
 | 
				
			||||||
 | 
									resourceList.APIResources = append(resourceList.APIResources, resource)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Subresources field in new format get transformed into full APIResources.
 | 
				
			||||||
 | 
								// It is possible a partial result with an error was returned to be used
 | 
				
			||||||
 | 
								// as the parent resource for the subresource.
 | 
				
			||||||
 | 
								for _, subresource := range r.Subresources {
 | 
				
			||||||
 | 
									sr, err := convertAPISubresourcev2beta1(resource, subresource)
 | 
				
			||||||
 | 
									if err == nil {
 | 
				
			||||||
 | 
										resourceList.APIResources = append(resourceList.APIResources, sr)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							gvResources[gv] = resourceList
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return group, gvResources, failedGVs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convertAPIResource tranforms a APIResourceDiscovery to an APIResource. We are
 | 
				
			||||||
 | 
					// resilient to missing GVK, since this resource might be the parent resource
 | 
				
			||||||
 | 
					// for a subresource. If the parent is missing a GVK, it is not returned in
 | 
				
			||||||
 | 
					// discovery, and the subresource MUST have the GVK.
 | 
				
			||||||
 | 
					func convertAPIResourcev2beta1(in apidiscoveryv2beta1.APIResourceDiscovery) (metav1.APIResource, error) {
 | 
				
			||||||
 | 
						result := metav1.APIResource{
 | 
				
			||||||
 | 
							Name:         in.Resource,
 | 
				
			||||||
 | 
							SingularName: in.SingularResource,
 | 
				
			||||||
 | 
							Namespaced:   in.Scope == apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
							Verbs:        in.Verbs,
 | 
				
			||||||
 | 
							ShortNames:   in.ShortNames,
 | 
				
			||||||
 | 
							Categories:   in.Categories,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Can return partial result with error, which can be the parent for a
 | 
				
			||||||
 | 
						// subresource. Do not add this result to the returned discovery resources.
 | 
				
			||||||
 | 
						if in.ResponseKind == nil || (*in.ResponseKind) == emptyKind {
 | 
				
			||||||
 | 
							return result, fmt.Errorf("discovery resource %s missing GVK", in.Resource)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result.Group = in.ResponseKind.Group
 | 
				
			||||||
 | 
						result.Version = in.ResponseKind.Version
 | 
				
			||||||
 | 
						result.Kind = in.ResponseKind.Kind
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convertAPISubresource tranforms a APISubresourceDiscovery to an APIResource.
 | 
				
			||||||
 | 
					func convertAPISubresourcev2beta1(parent metav1.APIResource, in apidiscoveryv2beta1.APISubresourceDiscovery) (metav1.APIResource, error) {
 | 
				
			||||||
 | 
						result := metav1.APIResource{}
 | 
				
			||||||
 | 
						if in.ResponseKind == nil || (*in.ResponseKind) == emptyKind {
 | 
				
			||||||
 | 
							return result, fmt.Errorf("subresource %s/%s missing GVK", parent.Name, in.Subresource)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result.Name = fmt.Sprintf("%s/%s", parent.Name, in.Subresource)
 | 
				
			||||||
 | 
						result.SingularName = parent.SingularName
 | 
				
			||||||
 | 
						result.Namespaced = parent.Namespaced
 | 
				
			||||||
 | 
						result.Group = in.ResponseKind.Group
 | 
				
			||||||
 | 
						result.Version = in.ResponseKind.Version
 | 
				
			||||||
 | 
						result.Kind = in.ResponseKind.Kind
 | 
				
			||||||
 | 
						result.Verbs = in.Verbs
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,8 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscovery "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -961,3 +962,941 @@ func TestSplitGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
		assert.Equal(t, test.expectedGVResources, resourcesByGV)
 | 
							assert.Equal(t, test.expectedGVResources, resourcesByGV)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Duplicated from test above. Remove after 1.33
 | 
				
			||||||
 | 
					func TestSplitGroupsAndResourcesV2Beta1(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name                string
 | 
				
			||||||
 | 
							agg                 apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
 | 
							expectedGroups      metav1.APIGroupList
 | 
				
			||||||
 | 
							expectedGVResources map[schema.GroupVersion]*metav1.APIResourceList
 | 
				
			||||||
 | 
							expectedFailedGVs   map[schema.GroupVersion]error
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: core/v1 group and pod resource",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "pods",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Pod",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: 1 group/1 resources at /api, 1 group/2 versions/1 resources at /apis",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v2",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "apps",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v2",
 | 
				
			||||||
 | 
													Version:      "v2",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "apps/v2",
 | 
				
			||||||
 | 
												Version:      "v2",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "deployments",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "apps",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Deployment",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v2"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v2",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "deployments",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "apps",
 | 
				
			||||||
 | 
												Version:    "v2",
 | 
				
			||||||
 | 
												Kind:       "Deployment",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: 1 group/2 resources at /api, 1 group/2 resources at /apis",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "services",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Service",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "StatefulSet",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "apps",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "pods",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Pod",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "services",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Service",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "deployments",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "apps",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Deployment",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "statefulsets",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "apps",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "StatefulSet",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: multiple groups with cluster-scoped resources",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "namespaces",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Namespace",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeCluster,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "roles",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Role",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeCluster,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "clusterroles",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "ClusterRole",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeCluster,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "rbac.authorization.k8s.io/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "rbac.authorization.k8s.io/v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "pods",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Pod",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "namespaces",
 | 
				
			||||||
 | 
												Namespaced: false,
 | 
				
			||||||
 | 
												Group:      "",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Namespace",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{Group: "rbac.authorization.k8s.io", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "rbac.authorization.k8s.io/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "roles",
 | 
				
			||||||
 | 
												Namespaced: false,
 | 
				
			||||||
 | 
												Group:      "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Role",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "clusterroles",
 | 
				
			||||||
 | 
												Namespaced: false,
 | 
				
			||||||
 | 
												Group:      "rbac.authorization.k8s.io",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "ClusterRole",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery with single subresource",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope:            apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
															SingularResource: "deployment",
 | 
				
			||||||
 | 
															ShortNames:       []string{"deploy"},
 | 
				
			||||||
 | 
															Verbs:            []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"},
 | 
				
			||||||
 | 
															Categories:       []string{"all", "testcategory"},
 | 
				
			||||||
 | 
															Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
				
			||||||
 | 
																{
 | 
				
			||||||
 | 
																	Subresource: "scale",
 | 
				
			||||||
 | 
																	ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																		Group:   "apps",
 | 
				
			||||||
 | 
																		Version: "v1",
 | 
				
			||||||
 | 
																		Kind:    "Deployment",
 | 
				
			||||||
 | 
																	},
 | 
				
			||||||
 | 
																	Verbs: []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
																},
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "apps",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "deployments",
 | 
				
			||||||
 | 
												SingularName: "deployment",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "apps",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
												Kind:         "Deployment",
 | 
				
			||||||
 | 
												Verbs:        []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"},
 | 
				
			||||||
 | 
												ShortNames:   []string{"deploy"},
 | 
				
			||||||
 | 
												Categories:   []string{"all", "testcategory"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "deployments/scale",
 | 
				
			||||||
 | 
												SingularName: "deployment",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "apps",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
												Kind:         "Deployment",
 | 
				
			||||||
 | 
												Verbs:        []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery with single subresource and parent missing GVK",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "external.metrics.k8s.io",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1beta1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															// resilient to nil GVK for parent
 | 
				
			||||||
 | 
															Resource:         "*",
 | 
				
			||||||
 | 
															Scope:            apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
															SingularResource: "",
 | 
				
			||||||
 | 
															Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
				
			||||||
 | 
																{
 | 
				
			||||||
 | 
																	Subresource: "other-external-metric",
 | 
				
			||||||
 | 
																	ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																		Kind: "MetricValueList",
 | 
				
			||||||
 | 
																	},
 | 
				
			||||||
 | 
																	Verbs: []string{"get"},
 | 
				
			||||||
 | 
																},
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "external.metrics.k8s.io",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
													Version:      "v1beta1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
												Version:      "v1beta1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "external.metrics.k8s.io", Version: "v1beta1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											// Since parent GVK was nil, it is NOT returned--only the subresource.
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "*/other-external-metric",
 | 
				
			||||||
 | 
												SingularName: "",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "",
 | 
				
			||||||
 | 
												Version:      "",
 | 
				
			||||||
 | 
												Kind:         "MetricValueList",
 | 
				
			||||||
 | 
												Verbs:        []string{"get"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery with single subresource and parent empty GVK",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "external.metrics.k8s.io",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1beta1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															// resilient to empty GVK for parent
 | 
				
			||||||
 | 
															Resource:         "*",
 | 
				
			||||||
 | 
															Scope:            apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
															SingularResource: "",
 | 
				
			||||||
 | 
															ResponseKind:     &metav1.GroupVersionKind{},
 | 
				
			||||||
 | 
															Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
				
			||||||
 | 
																{
 | 
				
			||||||
 | 
																	Subresource: "other-external-metric",
 | 
				
			||||||
 | 
																	ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																		Kind: "MetricValueList",
 | 
				
			||||||
 | 
																	},
 | 
				
			||||||
 | 
																	Verbs: []string{"get"},
 | 
				
			||||||
 | 
																},
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "external.metrics.k8s.io",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
													Version:      "v1beta1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
												Version:      "v1beta1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "external.metrics.k8s.io", Version: "v1beta1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "external.metrics.k8s.io/v1beta1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											// Since parent GVK was nil, it is NOT returned--only the subresource.
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "*/other-external-metric",
 | 
				
			||||||
 | 
												SingularName: "",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "",
 | 
				
			||||||
 | 
												Version:      "",
 | 
				
			||||||
 | 
												Kind:         "MetricValueList",
 | 
				
			||||||
 | 
												Verbs:        []string{"get"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery with multiple subresources",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope:            apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
															SingularResource: "deployment",
 | 
				
			||||||
 | 
															Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
				
			||||||
 | 
																{
 | 
				
			||||||
 | 
																	Subresource: "scale",
 | 
				
			||||||
 | 
																	ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																		Group:   "apps",
 | 
				
			||||||
 | 
																		Version: "v1",
 | 
				
			||||||
 | 
																		Kind:    "Deployment",
 | 
				
			||||||
 | 
																	},
 | 
				
			||||||
 | 
																	Verbs: []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
																},
 | 
				
			||||||
 | 
																{
 | 
				
			||||||
 | 
																	Subresource: "status",
 | 
				
			||||||
 | 
																	ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																		Group:   "apps",
 | 
				
			||||||
 | 
																		Version: "v1",
 | 
				
			||||||
 | 
																		Kind:    "Deployment",
 | 
				
			||||||
 | 
																	},
 | 
				
			||||||
 | 
																	Verbs: []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
																},
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "apps",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "deployments",
 | 
				
			||||||
 | 
												SingularName: "deployment",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "apps",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
												Kind:         "Deployment",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "deployments/scale",
 | 
				
			||||||
 | 
												SingularName: "deployment",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "apps",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
												Kind:         "Deployment",
 | 
				
			||||||
 | 
												Verbs:        []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:         "deployments/status",
 | 
				
			||||||
 | 
												SingularName: "deployment",
 | 
				
			||||||
 | 
												Namespaced:   true,
 | 
				
			||||||
 | 
												Group:        "apps",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
												Kind:         "Deployment",
 | 
				
			||||||
 | 
												Verbs:        []string{"get", "patch", "update"},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: single failed GV at /api",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "services",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Service",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Single core Group/Version is stale, so no Version within Group.
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{{Name: ""}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Single core Group/Version is stale, so there are no expected resources.
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{
 | 
				
			||||||
 | 
									{Group: "", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "", Version: "v1"}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: single failed GV at /apis",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "StatefulSets",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Single apps/v1 Group/Version is stale, so no Version within Group.
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{{Name: "apps"}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Single apps/v1 Group/Version is stale, so there are no expected resources.
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v1"}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Aggregated discovery: 1 group/2 versions/1 failed GV at /apis",
 | 
				
			||||||
 | 
								agg: apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												// Stale v2 should report failed GV.
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v2",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "daemonsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "DaemonSets",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Only apps/v1 is non-stale expected Group/Version
 | 
				
			||||||
 | 
								expectedGroups: metav1.APIGroupList{
 | 
				
			||||||
 | 
									Groups: []metav1.APIGroup{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name: "apps",
 | 
				
			||||||
 | 
											Versions: []metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
													Version:      "v1",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											// PreferredVersion must be apps/v1
 | 
				
			||||||
 | 
											PreferredVersion: metav1.GroupVersionForDiscovery{
 | 
				
			||||||
 | 
												GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
												Version:      "v1",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Only apps/v1 resources expected.
 | 
				
			||||||
 | 
								expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v1"}: {
 | 
				
			||||||
 | 
										GroupVersion: "apps/v1",
 | 
				
			||||||
 | 
										APIResources: []metav1.APIResource{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:       "deployments",
 | 
				
			||||||
 | 
												Namespaced: true,
 | 
				
			||||||
 | 
												Group:      "apps",
 | 
				
			||||||
 | 
												Version:    "v1",
 | 
				
			||||||
 | 
												Kind:       "Deployment",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedFailedGVs: map[schema.GroupVersion]error{
 | 
				
			||||||
 | 
									{Group: "apps", Version: "v2"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v2"}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							apiGroups, resourcesByGV, failedGVs := SplitGroupsAndResourcesV2Beta1(test.agg)
 | 
				
			||||||
 | 
							assert.Equal(t, test.expectedFailedGVs, failedGVs)
 | 
				
			||||||
 | 
							assert.Equal(t, test.expectedGroups, *apiGroups)
 | 
				
			||||||
 | 
							assert.Equal(t, test.expectedGVResources, resourcesByGV)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscovery "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -643,7 +643,7 @@ func TestCachedDiscoveryClientAggregatedServerGroups(t *testing.T) {
 | 
				
			|||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// Content-type is "aggregated" discovery format.
 | 
								// Content-type is "aggregated" discovery format.
 | 
				
			||||||
			w.Header().Set("Content-Type", discovery.AcceptV2Beta1)
 | 
								w.Header().Set("Content-Type", discovery.AcceptV2)
 | 
				
			||||||
			w.WriteHeader(http.StatusOK)
 | 
								w.WriteHeader(http.StatusOK)
 | 
				
			||||||
			w.Write(output)
 | 
								w.Write(output)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscovery "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	errorsutil "k8s.io/apimachinery/pkg/api/errors"
 | 
						errorsutil "k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -1118,7 +1118,7 @@ func TestAggregatedMemCacheGroupsAndMaybeResources(t *testing.T) {
 | 
				
			|||||||
			output, err := json.Marshal(agg)
 | 
								output, err := json.Marshal(agg)
 | 
				
			||||||
			require.NoError(t, err)
 | 
								require.NoError(t, err)
 | 
				
			||||||
			// Content-type is "aggregated" discovery format.
 | 
								// Content-type is "aggregated" discovery format.
 | 
				
			||||||
			w.Header().Set("Content-Type", discovery.AcceptV2Beta1)
 | 
								w.Header().Set("Content-Type", discovery.AcceptV2)
 | 
				
			||||||
			w.WriteHeader(http.StatusOK)
 | 
								w.WriteHeader(http.StatusOK)
 | 
				
			||||||
			w.Write(output)
 | 
								w.Write(output)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
@@ -1161,6 +1161,7 @@ func TestAggregatedMemCacheGroupsAndMaybeResources(t *testing.T) {
 | 
				
			|||||||
		memClient.Invalidate()
 | 
							memClient.Invalidate()
 | 
				
			||||||
		assert.False(t, memClient.Fresh())
 | 
							assert.False(t, memClient.Fresh())
 | 
				
			||||||
		apiGroupList, _, _, err = memClient.GroupsAndMaybeResources()
 | 
							apiGroupList, _, _, err = memClient.GroupsAndMaybeResources()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		require.NoError(t, err)
 | 
							require.NoError(t, err)
 | 
				
			||||||
		// Test the expected groups are returned for the aggregated format.
 | 
							// Test the expected groups are returned for the aggregated format.
 | 
				
			||||||
		actualGroupNames = sets.NewString(groupNamesFromList(apiGroupList)...)
 | 
							actualGroupNames = sets.NewString(groupNamesFromList(apiGroupList)...)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,8 @@ import (
 | 
				
			|||||||
	"github.com/golang/protobuf/proto"
 | 
						"github.com/golang/protobuf/proto"
 | 
				
			||||||
	openapi_v2 "github.com/google/gnostic-models/openapiv2"
 | 
						openapi_v2 "github.com/google/gnostic-models/openapiv2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -64,12 +65,14 @@ const (
 | 
				
			|||||||
	// MUST be ordered (g, v, as) for server in "Accept" header (BUT we are resilient
 | 
						// MUST be ordered (g, v, as) for server in "Accept" header (BUT we are resilient
 | 
				
			||||||
	// to ordering when comparing returned values in "Content-Type" header).
 | 
						// to ordering when comparing returned values in "Content-Type" header).
 | 
				
			||||||
	AcceptV2Beta1 = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
						AcceptV2Beta1 = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
						AcceptV2      = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList"
 | 
				
			||||||
	// Prioritize aggregated discovery by placing first in the order of discovery accept types.
 | 
						// Prioritize aggregated discovery by placing first in the order of discovery accept types.
 | 
				
			||||||
	acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
 | 
						acceptDiscoveryFormats = AcceptV2 + "," + AcceptV2Beta1 + "," + AcceptV1
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Aggregated discovery content-type GVK.
 | 
					// Aggregated discovery content-type GVK.
 | 
				
			||||||
var v2Beta1GVK = schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
 | 
					var v2Beta1GVK = schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
 | 
				
			||||||
 | 
					var v2GVK = schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2", Kind: "APIGroupDiscoveryList"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DiscoveryInterface holds the methods that discover server-supported API groups,
 | 
					// DiscoveryInterface holds the methods that discover server-supported API groups,
 | 
				
			||||||
// versions and resources.
 | 
					// versions and resources.
 | 
				
			||||||
@@ -265,13 +268,20 @@ func (d *DiscoveryClient) downloadLegacy() (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
 | 
						var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
 | 
				
			||||||
	// Based on the content-type server responded with: aggregated or unaggregated.
 | 
						// Based on the content-type server responded with: aggregated or unaggregated.
 | 
				
			||||||
	if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
 | 
						if isGVK, _ := ContentTypeIsGVK(responseContentType, v2GVK); isGVK {
 | 
				
			||||||
		var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
 | 
							var aggregatedDiscovery apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
		err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
							err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, nil, nil, err
 | 
								return nil, nil, nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
 | 
							apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
 | 
				
			||||||
 | 
						} else if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
 | 
				
			||||||
 | 
							var aggregatedDiscovery apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
 | 
							err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, nil, nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResourcesV2Beta1(aggregatedDiscovery)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Default is unaggregated discovery v1.
 | 
							// Default is unaggregated discovery v1.
 | 
				
			||||||
		var v metav1.APIVersions
 | 
							var v metav1.APIVersions
 | 
				
			||||||
@@ -317,13 +327,20 @@ func (d *DiscoveryClient) downloadAPIs() (
 | 
				
			|||||||
	failedGVs := map[schema.GroupVersion]error{}
 | 
						failedGVs := map[schema.GroupVersion]error{}
 | 
				
			||||||
	var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
 | 
						var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
 | 
				
			||||||
	// Based on the content-type server responded with: aggregated or unaggregated.
 | 
						// Based on the content-type server responded with: aggregated or unaggregated.
 | 
				
			||||||
	if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
 | 
						if isGVK, _ := ContentTypeIsGVK(responseContentType, v2GVK); isGVK {
 | 
				
			||||||
		var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
 | 
							var aggregatedDiscovery apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
		err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
							err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, nil, nil, err
 | 
								return nil, nil, nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
 | 
							apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
 | 
				
			||||||
 | 
						} else if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
 | 
				
			||||||
 | 
							var aggregatedDiscovery apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
 | 
							err = json.Unmarshal(body, &aggregatedDiscovery)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, nil, nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResourcesV2Beta1(aggregatedDiscovery)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Default is unaggregated discovery v1.
 | 
							// Default is unaggregated discovery v1.
 | 
				
			||||||
		err = json.Unmarshal(body, apiGroupList)
 | 
							err = json.Unmarshal(body, apiGroupList)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,8 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	golangproto "google.golang.org/protobuf/proto"
 | 
						golangproto "google.golang.org/protobuf/proto"
 | 
				
			||||||
	apidiscovery "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscovery "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
@@ -58,7 +59,8 @@ func TestGetServerVersion(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		w.Header().Set("Content-Type", "application/json")
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		w.Write(output)
 | 
							_, err = w.Write(output)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer server.Close()
 | 
						defer server.Close()
 | 
				
			||||||
	client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
						client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -104,7 +106,8 @@ func TestGetServerGroupsWithV1Server(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		w.Header().Set("Content-Type", "application/json")
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		w.Write(output)
 | 
							_, err = w.Write(output)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer server.Close()
 | 
						defer server.Close()
 | 
				
			||||||
	client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
						client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -144,7 +147,8 @@ func TestDiscoveryToleratesMissingCoreGroup(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		w.Header().Set("Content-Type", "application/json")
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		w.Write(output)
 | 
							_, err = w.Write(output)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer server.Close()
 | 
						defer server.Close()
 | 
				
			||||||
	client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
						client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -180,7 +184,8 @@ func TestDiscoveryFailsWhenNonCoreGroupsMissing(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		w.Header().Set("Content-Type", "application/json")
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		w.Write(output)
 | 
							_, err = w.Write(output)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer server.Close()
 | 
						defer server.Close()
 | 
				
			||||||
	client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
						client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -380,7 +385,8 @@ func TestGetServerResourcesForGroupVersion(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		w.Header().Set("Content-Type", "application/json")
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		w.Write(output)
 | 
							_, err = w.Write(output)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer server.Close()
 | 
						defer server.Close()
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
@@ -1294,6 +1300,8 @@ func TestAggregatedServerGroups(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
							server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
 | 
								var output []byte
 | 
				
			||||||
 | 
								var err error
 | 
				
			||||||
			var agg *apidiscovery.APIGroupDiscoveryList
 | 
								var agg *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
			switch req.URL.Path {
 | 
								switch req.URL.Path {
 | 
				
			||||||
			case "/api":
 | 
								case "/api":
 | 
				
			||||||
@@ -1304,13 +1312,14 @@ func TestAggregatedServerGroups(t *testing.T) {
 | 
				
			|||||||
				w.WriteHeader(http.StatusNotFound)
 | 
									w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			output, err := json.Marshal(agg)
 | 
								output, err = json.Marshal(agg)
 | 
				
			||||||
			require.NoError(t, err)
 | 
								require.NoError(t, err)
 | 
				
			||||||
			// Content-Type is "aggregated" discovery format. Add extra parameter
 | 
								// Content-Type is "aggregated" discovery format. Add extra parameter
 | 
				
			||||||
			// to ensure we are resilient to these extra parameters.
 | 
								// to ensure we are resilient to these extra parameters.
 | 
				
			||||||
			w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
 | 
								w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
 | 
				
			||||||
			w.WriteHeader(http.StatusOK)
 | 
								w.WriteHeader(http.StatusOK)
 | 
				
			||||||
			w.Write(output)
 | 
								_, err = w.Write(output)
 | 
				
			||||||
 | 
								require.NoError(t, err)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
		defer server.Close()
 | 
							defer server.Close()
 | 
				
			||||||
		client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
							client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -1338,7 +1347,9 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name                  string
 | 
							name                  string
 | 
				
			||||||
		corev1                *apidiscovery.APIGroupDiscoveryList
 | 
							corev1                *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
 | 
							corev1DiscoveryBeta   *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
		apis                  *apidiscovery.APIGroupDiscoveryList
 | 
							apis                  *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
 | 
							apisDiscoveryBeta     *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
		expectedGroupNames    []string
 | 
							expectedGroupNames    []string
 | 
				
			||||||
		expectedGroupVersions []string
 | 
							expectedGroupVersions []string
 | 
				
			||||||
		expectedGVKs          []string
 | 
							expectedGVKs          []string
 | 
				
			||||||
@@ -1368,6 +1379,28 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1393,6 +1426,31 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"", "apps"},
 | 
								expectedGroupNames:    []string{"", "apps"},
 | 
				
			||||||
			expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
								expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1424,6 +1482,28 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1463,6 +1543,45 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v2",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"", "apps"},
 | 
								expectedGroupNames:    []string{"", "apps"},
 | 
				
			||||||
			expectedGroupVersions: []string{"v1", "apps/v1", "apps/v2"},
 | 
								expectedGroupVersions: []string{"v1", "apps/v1", "apps/v2"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1495,6 +1614,28 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1535,6 +1676,46 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v2",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"", "apps"},
 | 
								expectedGroupNames:    []string{"", "apps"},
 | 
				
			||||||
			expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
								expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1576,6 +1757,37 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "services",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Service",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1635,6 +1847,65 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												// Stale "v2" version not included.
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v2",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v2",
 | 
				
			||||||
 | 
																Kind:    "StatefulSet",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "StatefulSet",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"", "apps"},
 | 
								expectedGroupNames:    []string{"", "apps"},
 | 
				
			||||||
			expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
								expectedGroupVersions: []string{"v1", "apps/v1"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1678,6 +1949,37 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "pods",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Pod",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "services",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Service",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1767,6 +2069,95 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "StatefulSet",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "batch",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												// Stale Group/Version is not included
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "jobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Job",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "cronjobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "CronJob",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1beta1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "jobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1beta1",
 | 
				
			||||||
 | 
																Kind:    "Job",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "cronjobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1beta1",
 | 
				
			||||||
 | 
																Kind:    "CronJob",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"", "apps", "batch"},
 | 
								expectedGroupNames:    []string{"", "apps", "batch"},
 | 
				
			||||||
			expectedGroupVersions: []string{"v1", "apps/v1", "batch/v1beta1"},
 | 
								expectedGroupVersions: []string{"v1", "apps/v1", "batch/v1beta1"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1782,6 +2173,7 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			name:                "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
 | 
								name:                "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
 | 
				
			||||||
			corev1:              &apidiscovery.APIGroupDiscoveryList{},
 | 
								corev1:              &apidiscovery.APIGroupDiscoveryList{},
 | 
				
			||||||
 | 
								corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{},
 | 
				
			||||||
			apis: &apidiscovery.APIGroupDiscoveryList{
 | 
								apis: &apidiscovery.APIGroupDiscoveryList{
 | 
				
			||||||
				Items: []apidiscovery.APIGroupDiscovery{
 | 
									Items: []apidiscovery.APIGroupDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -1871,6 +2263,95 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								apisDiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
				
			||||||
 | 
									Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "apps",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "deployments",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Deployment",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "statefulsets",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "apps",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "StatefulSet",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
												Name: "batch",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Version: "v1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "jobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "Job",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "cronjobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1",
 | 
				
			||||||
 | 
																Kind:    "CronJob",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													// Stale "v1beta1" not included.
 | 
				
			||||||
 | 
													Version: "v1beta1",
 | 
				
			||||||
 | 
													Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "jobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1beta1",
 | 
				
			||||||
 | 
																Kind:    "Job",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
														{
 | 
				
			||||||
 | 
															Resource: "cronjobs",
 | 
				
			||||||
 | 
															ResponseKind: &metav1.GroupVersionKind{
 | 
				
			||||||
 | 
																Group:   "batch",
 | 
				
			||||||
 | 
																Version: "v1beta1",
 | 
				
			||||||
 | 
																Kind:    "CronJob",
 | 
				
			||||||
 | 
															},
 | 
				
			||||||
 | 
															Scope: apidiscoveryv2beta1.ScopeNamespace,
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
													Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedGroupNames:    []string{"apps", "batch"},
 | 
								expectedGroupNames:    []string{"apps", "batch"},
 | 
				
			||||||
			expectedGroupVersions: []string{"apps/v1", "batch/v1"},
 | 
								expectedGroupVersions: []string{"apps/v1", "batch/v1"},
 | 
				
			||||||
			expectedGVKs: []string{
 | 
								expectedGVKs: []string{
 | 
				
			||||||
@@ -1883,8 +2364,14 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Ensure that client can parse both V2Beta1 and V2 types from server
 | 
				
			||||||
 | 
						serverAccepts := []string{AcceptV2Beta1, AcceptV2}
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							for _, accept := range serverAccepts {
 | 
				
			||||||
			server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
								server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
 | 
									var output []byte
 | 
				
			||||||
 | 
									var err error
 | 
				
			||||||
 | 
									if accept == AcceptV2 {
 | 
				
			||||||
					var agg *apidiscovery.APIGroupDiscoveryList
 | 
										var agg *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
					switch req.URL.Path {
 | 
										switch req.URL.Path {
 | 
				
			||||||
					case "/api":
 | 
										case "/api":
 | 
				
			||||||
@@ -1895,13 +2382,29 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
						w.WriteHeader(http.StatusNotFound)
 | 
											w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
						return
 | 
											return
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
			output, err := json.Marshal(agg)
 | 
										output, err = json.Marshal(agg)
 | 
				
			||||||
					require.NoError(t, err)
 | 
										require.NoError(t, err)
 | 
				
			||||||
			// Content-type is "aggregated" discovery format. Add extra parameter
 | 
									} else {
 | 
				
			||||||
 | 
										var agg *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
				
			||||||
 | 
										switch req.URL.Path {
 | 
				
			||||||
 | 
										case "/api":
 | 
				
			||||||
 | 
											agg = test.corev1DiscoveryBeta
 | 
				
			||||||
 | 
										case "/apis":
 | 
				
			||||||
 | 
											agg = test.apisDiscoveryBeta
 | 
				
			||||||
 | 
										default:
 | 
				
			||||||
 | 
											w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										output, err = json.Marshal(&agg)
 | 
				
			||||||
 | 
										require.NoError(t, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// Content-Type is "aggregated" discovery format. Add extra parameter
 | 
				
			||||||
				// to ensure we are resilient to these extra parameters.
 | 
									// to ensure we are resilient to these extra parameters.
 | 
				
			||||||
			w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
 | 
									w.Header().Set("Content-Type", accept+"; charset=utf-8")
 | 
				
			||||||
				w.WriteHeader(http.StatusOK)
 | 
									w.WriteHeader(http.StatusOK)
 | 
				
			||||||
			w.Write(output)
 | 
									_, err = w.Write(output)
 | 
				
			||||||
 | 
									require.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}))
 | 
								}))
 | 
				
			||||||
			defer server.Close()
 | 
								defer server.Close()
 | 
				
			||||||
			client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
								client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -1939,6 +2442,7 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
 | 
				
			|||||||
			assert.True(t, expectedGVKs.Equal(actualGVKs),
 | 
								assert.True(t, expectedGVKs.Equal(actualGVKs),
 | 
				
			||||||
				"%s: Expected GVKs (%s), got (%s)", test.name, expectedGVKs.List(), actualGVKs.List())
 | 
									"%s: Expected GVKs (%s), got (%s)", test.name, expectedGVKs.List(), actualGVKs.List())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
 | 
					func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
 | 
				
			||||||
@@ -2023,8 +2527,10 @@ func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
							server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
			var agg *apidiscovery.APIGroupDiscoveryList
 | 
								var output []byte
 | 
				
			||||||
 | 
								var err error
 | 
				
			||||||
			var status int
 | 
								var status int
 | 
				
			||||||
 | 
								var agg *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
			switch req.URL.Path {
 | 
								switch req.URL.Path {
 | 
				
			||||||
			case "/api":
 | 
								case "/api":
 | 
				
			||||||
				agg = test.corev1
 | 
									agg = test.corev1
 | 
				
			||||||
@@ -2036,15 +2542,17 @@ func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
 | 
				
			|||||||
				w.WriteHeader(http.StatusNotFound)
 | 
									w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			output, err := json.Marshal(agg)
 | 
								output, err = json.Marshal(agg)
 | 
				
			||||||
			require.NoError(t, err)
 | 
								require.NoError(t, err)
 | 
				
			||||||
			// Content-type is "aggregated" discovery format. Add extra parameter
 | 
								// Content-Type is "aggregated" discovery format. Add extra parameter
 | 
				
			||||||
			// to ensure we are resilient to these extra parameters.
 | 
								// to ensure we are resilient to these extra parameters.
 | 
				
			||||||
			w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
 | 
								w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
 | 
				
			||||||
			w.WriteHeader(status)
 | 
								w.WriteHeader(status)
 | 
				
			||||||
			w.Write(output)
 | 
								_, err = w.Write(output)
 | 
				
			||||||
 | 
								require.NoError(t, err)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
		defer server.Close()
 | 
							defer server.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
							client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
		apiGroups, resources, err := client.ServerGroupsAndResources()
 | 
							apiGroups, resources, err := client.ServerGroupsAndResources()
 | 
				
			||||||
		if test.expectedErr {
 | 
							if test.expectedErr {
 | 
				
			||||||
@@ -2635,6 +3143,8 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
							server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
 | 
								var output []byte
 | 
				
			||||||
 | 
								var err error
 | 
				
			||||||
			var agg *apidiscovery.APIGroupDiscoveryList
 | 
								var agg *apidiscovery.APIGroupDiscoveryList
 | 
				
			||||||
			switch req.URL.Path {
 | 
								switch req.URL.Path {
 | 
				
			||||||
			case "/api":
 | 
								case "/api":
 | 
				
			||||||
@@ -2645,13 +3155,14 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
 | 
				
			|||||||
				w.WriteHeader(http.StatusNotFound)
 | 
									w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			output, err := json.Marshal(agg)
 | 
								output, err = json.Marshal(agg)
 | 
				
			||||||
			require.NoError(t, err)
 | 
								require.NoError(t, err)
 | 
				
			||||||
			// Content-type is "aggregated" discovery format. Add extra parameter
 | 
								// Content-Type is "aggregated" discovery format. Add extra parameter
 | 
				
			||||||
			// to ensure we are resilient to these extra parameters.
 | 
								// to ensure we are resilient to these extra parameters.
 | 
				
			||||||
			w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
 | 
								w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
 | 
				
			||||||
			w.WriteHeader(http.StatusOK)
 | 
								w.WriteHeader(http.StatusOK)
 | 
				
			||||||
			w.Write(output)
 | 
								_, err = w.Write(output)
 | 
				
			||||||
 | 
								require.NoError(t, err)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
		defer server.Close()
 | 
							defer server.Close()
 | 
				
			||||||
		client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
							client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
 | 
				
			||||||
@@ -2674,7 +3185,7 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDiscoveryContentTypeVersion(t *testing.T) {
 | 
					func TestDiscoveryContentTypeVersion(t *testing.T) {
 | 
				
			||||||
	v2beta1 := schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
 | 
						v2 := schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2", Kind: "APIGroupDiscoveryList"}
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		contentType string
 | 
							contentType string
 | 
				
			||||||
		gvk         schema.GroupVersionKind
 | 
							gvk         schema.GroupVersionKind
 | 
				
			||||||
@@ -2682,59 +3193,59 @@ func TestDiscoveryContentTypeVersion(t *testing.T) {
 | 
				
			|||||||
		expectErr   bool
 | 
							expectErr   bool
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList",
 | 
								contentType: "application/json; g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       true,
 | 
								match:       true,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// content-type parameters are not in correct order, but comparison ignores order.
 | 
								// content-type parameters are not in correct order, but comparison ignores order.
 | 
				
			||||||
			contentType: "application/json; v=v2beta1;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
 | 
								contentType: "application/json; v=v2;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       true,
 | 
								match:       true,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// content-type parameters are not in correct order, but comparison ignores order.
 | 
								// content-type parameters are not in correct order, but comparison ignores order.
 | 
				
			||||||
			contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2beta1",
 | 
								contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       true,
 | 
								match:       true,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// Ignores extra parameter "charset=utf-8"
 | 
								// Ignores extra parameter "charset=utf-8"
 | 
				
			||||||
			contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList;charset=utf-8",
 | 
								contentType: "application/json; g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList;charset=utf-8",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       true,
 | 
								match:       true,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "application/json",
 | 
								contentType: "application/json",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       false,
 | 
								match:       false,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "application/json; charset=UTF-8",
 | 
								contentType: "application/json; charset=UTF-8",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       false,
 | 
								match:       false,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "text/json",
 | 
								contentType: "text/json",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       false,
 | 
								match:       false,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "text/html",
 | 
								contentType: "text/html",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       false,
 | 
								match:       false,
 | 
				
			||||||
			expectErr:   false,
 | 
								expectErr:   false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			contentType: "",
 | 
								contentType: "",
 | 
				
			||||||
			gvk:         v2beta1,
 | 
								gvk:         v2,
 | 
				
			||||||
			match:       false,
 | 
								match:       false,
 | 
				
			||||||
			expectErr:   true,
 | 
								expectErr:   true,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,15 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
 | 
						apidiscoveryv2conversion "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
				
			||||||
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/authentication/user"
 | 
						"k8s.io/apiserver/pkg/authentication/user"
 | 
				
			||||||
@@ -34,11 +39,11 @@ import (
 | 
				
			|||||||
	discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
						discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/request"
 | 
						"k8s.io/apiserver/pkg/endpoints/request"
 | 
				
			||||||
	"k8s.io/client-go/discovery"
 | 
						"k8s.io/client-go/discovery"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes/scheme"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/util/workqueue"
 | 
						"k8s.io/client-go/util/workqueue"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
						apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
				
			||||||
	"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper"
 | 
						"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper"
 | 
				
			||||||
 | 
						"k8s.io/kube-aggregator/pkg/apiserver/scheme"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var APIRegistrationGroupVersion metav1.GroupVersion = metav1.GroupVersion{Group: "apiregistration.k8s.io", Version: "v1"}
 | 
					var APIRegistrationGroupVersion metav1.GroupVersion = metav1.GroupVersion{Group: "apiregistration.k8s.io", Version: "v1"}
 | 
				
			||||||
@@ -54,6 +59,12 @@ var v2Beta1GVK = schema.GroupVersionKind{
 | 
				
			|||||||
	Kind:    "APIGroupDiscoveryList",
 | 
						Kind:    "APIGroupDiscoveryList",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var v2GVK = schema.GroupVersionKind{
 | 
				
			||||||
 | 
						Group:   "apidiscovery.k8s.io",
 | 
				
			||||||
 | 
						Version: "v2",
 | 
				
			||||||
 | 
						Kind:    "APIGroupDiscoveryList",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Given a list of APIServices and proxyHandlers for contacting them,
 | 
					// Given a list of APIServices and proxyHandlers for contacting them,
 | 
				
			||||||
// DiscoveryManager caches a list of discovery documents for each server
 | 
					// DiscoveryManager caches a list of discovery documents for each server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,6 +107,9 @@ type discoveryManager struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Merged handler which stores all known groupversions
 | 
						// Merged handler which stores all known groupversions
 | 
				
			||||||
	mergedDiscoveryHandler discoveryendpoint.ResourceManager
 | 
						mergedDiscoveryHandler discoveryendpoint.ResourceManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Codecs is the serializer used for decoding aggregated apiserver responses
 | 
				
			||||||
 | 
						codecs serializer.CodecFactory
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Version of Service/Spec with relevant fields for use as a cache key
 | 
					// Version of Service/Spec with relevant fields for use as a cache key
 | 
				
			||||||
@@ -129,7 +143,7 @@ func newServiceKey(service apiregistrationv1.ServiceReference) serviceKey {
 | 
				
			|||||||
type cachedResult struct {
 | 
					type cachedResult struct {
 | 
				
			||||||
	// Currently cached discovery document for this service
 | 
						// Currently cached discovery document for this service
 | 
				
			||||||
	// Map from group name to version name to
 | 
						// Map from group name to version name to
 | 
				
			||||||
	discovery map[metav1.GroupVersion]apidiscoveryv2beta1.APIVersionDiscovery
 | 
						discovery map[metav1.GroupVersion]apidiscoveryv2.APIVersionDiscovery
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ETag hash of the cached discoveryDocument
 | 
						// ETag hash of the cached discoveryDocument
 | 
				
			||||||
	etag string
 | 
						etag string
 | 
				
			||||||
@@ -172,11 +186,19 @@ var _ DiscoveryAggregationController = &discoveryManager{}
 | 
				
			|||||||
func NewDiscoveryManager(
 | 
					func NewDiscoveryManager(
 | 
				
			||||||
	target discoveryendpoint.ResourceManager,
 | 
						target discoveryendpoint.ResourceManager,
 | 
				
			||||||
) DiscoveryAggregationController {
 | 
					) DiscoveryAggregationController {
 | 
				
			||||||
 | 
						discoveryScheme := runtime.NewScheme()
 | 
				
			||||||
 | 
						// Register conversion for apidiscovery
 | 
				
			||||||
 | 
						apidiscoveryv2.SchemeBuilder.Register(apidiscoveryv2conversion.RegisterConversions)
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2.AddToScheme(discoveryScheme))
 | 
				
			||||||
 | 
						utilruntime.Must(apidiscoveryv2beta1.AddToScheme(discoveryScheme))
 | 
				
			||||||
 | 
						codecs := serializer.NewCodecFactory(discoveryScheme)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &discoveryManager{
 | 
						return &discoveryManager{
 | 
				
			||||||
		mergedDiscoveryHandler: target,
 | 
							mergedDiscoveryHandler: target,
 | 
				
			||||||
		apiServices:            make(map[string]groupVersionInfo),
 | 
							apiServices:            make(map[string]groupVersionInfo),
 | 
				
			||||||
		cachedResults:          make(map[serviceKey]cachedResult),
 | 
							cachedResults:          make(map[serviceKey]cachedResult),
 | 
				
			||||||
		dirtyAPIServiceQueue:   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "discovery-manager"),
 | 
							dirtyAPIServiceQueue:   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "discovery-manager"),
 | 
				
			||||||
 | 
							codecs:                 codecs,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -214,7 +236,7 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
 | 
				
			|||||||
		Path:              req.URL.Path,
 | 
							Path:              req.URL.Path,
 | 
				
			||||||
		IsResourceRequest: false,
 | 
							IsResourceRequest: false,
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	req.Header.Add("Accept", discovery.AcceptV2Beta1)
 | 
						req.Header.Add("Accept", discovery.AcceptV2+","+discovery.AcceptV2Beta1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if exists && len(cached.etag) > 0 {
 | 
						if exists && len(cached.etag) > 0 {
 | 
				
			||||||
		req.Header.Add("If-None-Match", cached.etag)
 | 
							req.Header.Add("If-None-Match", cached.etag)
 | 
				
			||||||
@@ -228,6 +250,8 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
 | 
				
			|||||||
	handler.ServeHTTP(writer, req)
 | 
						handler.ServeHTTP(writer, req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	isV2Beta1GVK, _ := discovery.ContentTypeIsGVK(writer.Header().Get("Content-Type"), v2Beta1GVK)
 | 
						isV2Beta1GVK, _ := discovery.ContentTypeIsGVK(writer.Header().Get("Content-Type"), v2Beta1GVK)
 | 
				
			||||||
 | 
						isV2GVK, _ := discovery.ContentTypeIsGVK(writer.Header().Get("Content-Type"), v2GVK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case writer.respCode == http.StatusNotModified:
 | 
						case writer.respCode == http.StatusNotModified:
 | 
				
			||||||
		// Keep old entry, update timestamp
 | 
							// Keep old entry, update timestamp
 | 
				
			||||||
@@ -242,16 +266,16 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
 | 
				
			|||||||
	case writer.respCode == http.StatusServiceUnavailable:
 | 
						case writer.respCode == http.StatusServiceUnavailable:
 | 
				
			||||||
		return nil, fmt.Errorf("service %s returned non-success response code: %v",
 | 
							return nil, fmt.Errorf("service %s returned non-success response code: %v",
 | 
				
			||||||
			info.service.String(), writer.respCode)
 | 
								info.service.String(), writer.respCode)
 | 
				
			||||||
	case writer.respCode == http.StatusOK && isV2Beta1GVK:
 | 
						case writer.respCode == http.StatusOK && (isV2GVK || isV2Beta1GVK):
 | 
				
			||||||
		parsed := &apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
							parsed := &apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
		if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), writer.data, parsed); err != nil {
 | 
							if err := runtime.DecodeInto(dm.codecs.UniversalDecoder(), writer.data, parsed); err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		klog.V(3).Infof("DiscoveryManager: Successfully downloaded discovery for %s", info.service.String())
 | 
							klog.V(3).Infof("DiscoveryManager: Successfully downloaded discovery for %s", info.service.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Convert discovery info into a map for convenient lookup later
 | 
							// Convert discovery info into a map for convenient lookup later
 | 
				
			||||||
		discoMap := map[metav1.GroupVersion]apidiscoveryv2beta1.APIVersionDiscovery{}
 | 
							discoMap := map[metav1.GroupVersion]apidiscoveryv2.APIVersionDiscovery{}
 | 
				
			||||||
		for _, g := range parsed.Items {
 | 
							for _, g := range parsed.Items {
 | 
				
			||||||
			for _, v := range g.Versions {
 | 
								for _, v := range g.Versions {
 | 
				
			||||||
				discoMap[metav1.GroupVersion{Group: g.Name, Version: v.Version}] = v
 | 
									discoMap[metav1.GroupVersion{Group: g.Name, Version: v.Version}] = v
 | 
				
			||||||
@@ -330,7 +354,7 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		klog.V(3).Infof("DiscoveryManager: Successfully downloaded legacy discovery for %s", info.service.String())
 | 
							klog.V(3).Infof("DiscoveryManager: Successfully downloaded legacy discovery for %s", info.service.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		discoMap := map[metav1.GroupVersion]apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							discoMap := map[metav1.GroupVersion]apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			// Convert old-style APIGroupList to new information
 | 
								// Convert old-style APIGroupList to new information
 | 
				
			||||||
			gv: {
 | 
								gv: {
 | 
				
			||||||
				Version:   gv.Version,
 | 
									Version:   gv.Version,
 | 
				
			||||||
@@ -366,7 +390,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
 | 
				
			|||||||
	// Lookup last cached result for this apiservice's service.
 | 
						// Lookup last cached result for this apiservice's service.
 | 
				
			||||||
	cached, err := dm.fetchFreshDiscoveryForService(mgv, info)
 | 
						cached, err := dm.fetchFreshDiscoveryForService(mgv, info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var entry apidiscoveryv2beta1.APIVersionDiscovery
 | 
						var entry apidiscoveryv2.APIVersionDiscovery
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Extract the APIService's specific resource information from the
 | 
						// Extract the APIService's specific resource information from the
 | 
				
			||||||
	// groupversion
 | 
						// groupversion
 | 
				
			||||||
@@ -377,7 +401,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
 | 
				
			|||||||
		// Just use empty GV to mark that GV exists, but no resources.
 | 
							// Just use empty GV to mark that GV exists, but no resources.
 | 
				
			||||||
		// Also mark that it is stale to indicate the fetch failed
 | 
							// Also mark that it is stale to indicate the fetch failed
 | 
				
			||||||
		// TODO: Maybe also stick in a status for the version the error?
 | 
							// TODO: Maybe also stick in a status for the version the error?
 | 
				
			||||||
		entry = apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							entry = apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			Version: gv.Version,
 | 
								Version: gv.Version,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -388,7 +412,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// Successfully fetched discovery information from the server, but
 | 
								// Successfully fetched discovery information from the server, but
 | 
				
			||||||
			// the server did not include this groupversion?
 | 
								// the server did not include this groupversion?
 | 
				
			||||||
			entry = apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								entry = apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				Version: gv.Version,
 | 
									Version: gv.Version,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -397,9 +421,9 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
 | 
				
			|||||||
	// The entry's staleness depends upon if `fetchFreshDiscoveryForService`
 | 
						// The entry's staleness depends upon if `fetchFreshDiscoveryForService`
 | 
				
			||||||
	// returned an error or not.
 | 
						// returned an error or not.
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		entry.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessCurrent
 | 
							entry.Freshness = apidiscoveryv2.DiscoveryFreshnessCurrent
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		entry.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessStale
 | 
							entry.Freshness = apidiscoveryv2.DiscoveryFreshnessStale
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm.mergedDiscoveryHandler.AddGroupVersion(gv.Group, entry)
 | 
						dm.mergedDiscoveryHandler.AddGroupVersion(gv.Group, entry)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,10 +33,12 @@ import (
 | 
				
			|||||||
	fuzz "github.com/google/gofuzz"
 | 
						fuzz "github.com/google/gofuzz"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
						apidiscoveryv2scheme "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints"
 | 
						"k8s.io/apiserver/pkg/endpoints"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/discovery"
 | 
						"k8s.io/apiserver/pkg/endpoints/discovery"
 | 
				
			||||||
	discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
						discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
 | 
				
			||||||
@@ -68,31 +70,31 @@ func TestBasic(t *testing.T) {
 | 
				
			|||||||
	service3 := discoveryendpoint.NewResourceManager("apis")
 | 
						service3 := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
	apiGroup1 := fuzzAPIGroups(2, 5, 25)
 | 
						apiGroup1 := fuzzAPIGroups(2, 5, 25)
 | 
				
			||||||
	apiGroup2 := fuzzAPIGroups(2, 5, 50)
 | 
						apiGroup2 := fuzzAPIGroups(2, 5, 50)
 | 
				
			||||||
	apiGroup3 := apidiscoveryv2beta1.APIGroupDiscoveryList{Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						apiGroup3 := apidiscoveryv2.APIGroupDiscoveryList{Items: []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{Name: "weird.example.com"},
 | 
								ObjectMeta: metav1.ObjectMeta{Name: "weird.example.com"},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Version:   "v1",
 | 
										Version:   "v1",
 | 
				
			||||||
					Freshness: "Current",
 | 
										Freshness: "Current",
 | 
				
			||||||
					Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
										Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource: "parent-missing-kind",
 | 
												Resource: "parent-missing-kind",
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-missing-kind"},
 | 
													{Subresource: "subresource-missing-kind"},
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource:     "parent-empty-kind",
 | 
												Resource:     "parent-empty-kind",
 | 
				
			||||||
							ResponseKind: &metav1.GroupVersionKind{},
 | 
												ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
 | 
													{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource:     "parent-with-kind",
 | 
												Resource:     "parent-with-kind",
 | 
				
			||||||
							ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
 | 
												ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
 | 
													{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
@@ -101,32 +103,32 @@ func TestBasic(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}}
 | 
						}}
 | 
				
			||||||
	apiGroup3WithFixup := apidiscoveryv2beta1.APIGroupDiscoveryList{Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						apiGroup3WithFixup := apidiscoveryv2.APIGroupDiscoveryList{Items: []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{Name: "weird.example.com"},
 | 
								ObjectMeta: metav1.ObjectMeta{Name: "weird.example.com"},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Version:   "v1",
 | 
										Version:   "v1",
 | 
				
			||||||
					Freshness: "Current",
 | 
										Freshness: "Current",
 | 
				
			||||||
					Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
										Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource:     "parent-missing-kind",
 | 
												Resource:     "parent-missing-kind",
 | 
				
			||||||
							ResponseKind: &metav1.GroupVersionKind{}, // defaulted by aggregator
 | 
												ResponseKind: &metav1.GroupVersionKind{}, // defaulted by aggregator
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-missing-kind", ResponseKind: &metav1.GroupVersionKind{}}, // defaulted by aggregator
 | 
													{Subresource: "subresource-missing-kind", ResponseKind: &metav1.GroupVersionKind{}}, // defaulted by aggregator
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource:     "parent-empty-kind",
 | 
												Resource:     "parent-empty-kind",
 | 
				
			||||||
							ResponseKind: &metav1.GroupVersionKind{},
 | 
												ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
 | 
													{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							Resource:     "parent-with-kind",
 | 
												Resource:     "parent-with-kind",
 | 
				
			||||||
							ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
 | 
												ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
 | 
				
			||||||
							Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
								{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
 | 
													{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
@@ -217,7 +219,7 @@ func TestBasic(t *testing.T) {
 | 
				
			|||||||
	checkAPIGroups(t, apiGroup3WithFixup, parsed)
 | 
						checkAPIGroups(t, apiGroup3WithFixup, parsed)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkAPIGroups(t *testing.T, api apidiscoveryv2beta1.APIGroupDiscoveryList, response *apidiscoveryv2beta1.APIGroupDiscoveryList) {
 | 
					func checkAPIGroups(t *testing.T, api apidiscoveryv2.APIGroupDiscoveryList, response *apidiscoveryv2.APIGroupDiscoveryList) {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
	if len(response.Items) < len(api.Items) {
 | 
						if len(response.Items) < len(api.Items) {
 | 
				
			||||||
		t.Errorf("expected to check for at least %d groups, only have %d groups in response", len(api.Items), len(response.Items))
 | 
							t.Errorf("expected to check for at least %d groups, only have %d groups in response", len(api.Items), len(response.Items))
 | 
				
			||||||
@@ -281,10 +283,10 @@ func TestInitialRunHasAllAPIServices(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("unexpected status code %d", response.StatusCode)
 | 
							t.Fatalf("unexpected status code %d", response.StatusCode)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiGroup := apidiscoveryv2beta1.APIGroupDiscoveryList{Items: []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						apiGroup := apidiscoveryv2.APIGroupDiscoveryList{Items: []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{Name: "stable.example.com"},
 | 
								ObjectMeta: metav1.ObjectMeta{Name: "stable.example.com"},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Version:   "v1",
 | 
										Version:   "v1",
 | 
				
			||||||
					Freshness: "Stale",
 | 
										Freshness: "Stale",
 | 
				
			||||||
@@ -348,6 +350,71 @@ func TestServiceGC(t *testing.T) {
 | 
				
			|||||||
	require.Equal(t, 1, getCacheLen())
 | 
						require.Equal(t, 1, getCacheLen())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TestV2Beta1Skew tests that aggregated apiservers that only serve V2Beta1
 | 
				
			||||||
 | 
					// are still supported
 | 
				
			||||||
 | 
					func TestV2Beta1Skew(t *testing.T) {
 | 
				
			||||||
 | 
						apiGroup := apidiscoveryv2.APIGroupDiscoveryList{Items: []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ObjectMeta: metav1.ObjectMeta{Name: "stable.example.com"},
 | 
				
			||||||
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Version:   "v1",
 | 
				
			||||||
 | 
										Freshness: "Current",
 | 
				
			||||||
 | 
										Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Resource:     "parent-with-kind",
 | 
				
			||||||
 | 
												ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
 | 
				
			||||||
 | 
												Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
 | 
													{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aggregatedResourceManager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aggregatedManager := newDiscoveryManager(aggregatedResourceManager)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aggregatedManager.AddAPIService(&apiregistrationv1.APIService{
 | 
				
			||||||
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
								Name: "v1.stable.example.com",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Spec: apiregistrationv1.APIServiceSpec{
 | 
				
			||||||
 | 
								Group:   "stable.example.com",
 | 
				
			||||||
 | 
								Version: "v1",
 | 
				
			||||||
 | 
								Service: &apiregistrationv1.ServiceReference{
 | 
				
			||||||
 | 
									Name: "test-service",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							// Force a v2beta1 response from the aggregated apiserver
 | 
				
			||||||
 | 
							v2b := apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
							err := apidiscoveryv2scheme.Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(&apiGroup, &v2b, nil)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							converted, err := json.Marshal(v2b)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
							w.Header().Set("Content-Type", "application/json;"+"g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList")
 | 
				
			||||||
 | 
							w.WriteHeader(200)
 | 
				
			||||||
 | 
							_, err = w.Write(converted)
 | 
				
			||||||
 | 
							require.NoError(t, err)
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						testCtx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go aggregatedManager.Run(testCtx.Done(), nil)
 | 
				
			||||||
 | 
						require.True(t, waitForQueueComplete(testCtx.Done(), aggregatedManager))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response, _, parsed := fetchPath(aggregatedResourceManager, "")
 | 
				
			||||||
 | 
						if response.StatusCode != 200 {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected status code %d", response.StatusCode)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						checkAPIGroups(t, apiGroup, parsed)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test that a handler associated with an APIService gets pinged after the
 | 
					// Test that a handler associated with an APIService gets pinged after the
 | 
				
			||||||
// APIService has been marked as dirty
 | 
					// APIService has been marked as dirty
 | 
				
			||||||
func TestDirty(t *testing.T) {
 | 
					func TestDirty(t *testing.T) {
 | 
				
			||||||
@@ -642,34 +709,34 @@ func TestLegacyFallbackNoCache(t *testing.T) {
 | 
				
			|||||||
	// includes the legacy resources
 | 
						// includes the legacy resources
 | 
				
			||||||
	_, _, doc := fetchPath(aggregatedResourceManager, "")
 | 
						_, _, doc := fetchPath(aggregatedResourceManager, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mustConvert := func(r []metav1.APIResource) []apidiscoveryv2beta1.APIResourceDiscovery {
 | 
						mustConvert := func(r []metav1.APIResource) []apidiscoveryv2.APIResourceDiscovery {
 | 
				
			||||||
		converted, err := endpoints.ConvertGroupVersionIntoToDiscovery(r)
 | 
							converted, err := endpoints.ConvertGroupVersionIntoToDiscovery(r)
 | 
				
			||||||
		require.NoError(t, err)
 | 
							require.NoError(t, err)
 | 
				
			||||||
		return converted
 | 
							return converted
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	expectAggregatedDiscovery := []apidiscoveryv2beta1.APIGroupDiscovery{{
 | 
						expectAggregatedDiscovery := []apidiscoveryv2.APIGroupDiscovery{{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Name: "stable.example.com",
 | 
								Name: "stable.example.com",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version:   "v1",
 | 
									Version:   "v1",
 | 
				
			||||||
				Resources: mustConvert([]metav1.APIResource{resources["v1"]}),
 | 
									Resources: mustConvert([]metav1.APIResource{resources["v1"]}),
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version:   "v1beta1",
 | 
									Version:   "v1beta1",
 | 
				
			||||||
				Resources: mustConvert([]metav1.APIResource{resources["v1beta1"]}),
 | 
									Resources: mustConvert([]metav1.APIResource{resources["v1beta1"]}),
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version: "v2alpha1",
 | 
									Version: "v2alpha1",
 | 
				
			||||||
				Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
									Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Resource:     "parent-without-kind",
 | 
											Resource:     "parent-without-kind",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{}, // defaulted
 | 
											ResponseKind: &metav1.GroupVersionKind{}, // defaulted
 | 
				
			||||||
						Scope:        "Cluster",
 | 
											Scope:        "Cluster",
 | 
				
			||||||
						Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
											Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Subresource:  "subresource",
 | 
													Subresource:  "subresource",
 | 
				
			||||||
								ResponseKind: &metav1.GroupVersionKind{Kind: "Subresource"},
 | 
													ResponseKind: &metav1.GroupVersionKind{Kind: "Subresource"},
 | 
				
			||||||
@@ -684,7 +751,7 @@ func TestLegacyFallbackNoCache(t *testing.T) {
 | 
				
			|||||||
						Resource:     "missing-parent",
 | 
											Resource:     "missing-parent",
 | 
				
			||||||
						ResponseKind: &metav1.GroupVersionKind{}, // defaulted
 | 
											ResponseKind: &metav1.GroupVersionKind{}, // defaulted
 | 
				
			||||||
						Scope:        "Cluster",
 | 
											Scope:        "Cluster",
 | 
				
			||||||
						Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
 | 
											Subresources: []apidiscoveryv2.APISubresourceDiscovery{
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Subresource:  "subresource-without-parent",
 | 
													Subresource:  "subresource-without-parent",
 | 
				
			||||||
								ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithoutParent"},
 | 
													ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithoutParent"},
 | 
				
			||||||
@@ -692,12 +759,12 @@ func TestLegacyFallbackNoCache(t *testing.T) {
 | 
				
			|||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version:   "v1alpha1",
 | 
									Version:   "v1alpha1",
 | 
				
			||||||
				Resources: mustConvert([]metav1.APIResource{resources["v1alpha1"]}),
 | 
									Resources: mustConvert([]metav1.APIResource{resources["v1alpha1"]}),
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}}
 | 
						}}
 | 
				
			||||||
@@ -782,16 +849,16 @@ func testLegacyFallbackWithCustomRootHandler(t *testing.T, rootHandlerFn func(ht
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	converted, err := endpoints.ConvertGroupVersionIntoToDiscovery([]metav1.APIResource{resource})
 | 
						converted, err := endpoints.ConvertGroupVersionIntoToDiscovery([]metav1.APIResource{resource})
 | 
				
			||||||
	require.NoError(t, err)
 | 
						require.NoError(t, err)
 | 
				
			||||||
	require.Equal(t, []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						require.Equal(t, []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
				Name: resource.Group,
 | 
									Name: resource.Group,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Version:   resource.Version,
 | 
										Version:   resource.Version,
 | 
				
			||||||
					Resources: converted,
 | 
										Resources: converted,
 | 
				
			||||||
					Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
										Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -859,15 +926,15 @@ func TestAPIServiceStale(t *testing.T) {
 | 
				
			|||||||
	// At this point external services have synced. Check if discovery document
 | 
						// At this point external services have synced. Check if discovery document
 | 
				
			||||||
	// lists the APIService group version as Stale.
 | 
						// lists the APIService group version as Stale.
 | 
				
			||||||
	_, _, doc := fetchPath(aggregatedResourceManager, "")
 | 
						_, _, doc := fetchPath(aggregatedResourceManager, "")
 | 
				
			||||||
	require.Equal(t, []apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						require.Equal(t, []apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
				Name: "stable.example.com",
 | 
									Name: "stable.example.com",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
								Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Version:   "v1",
 | 
										Version:   "v1",
 | 
				
			||||||
					Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
										Freshness: apidiscoveryv2.DiscoveryFreshnessStale,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -934,16 +1001,16 @@ func TestNotModified(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// copied from staging/src/k8s.io/apiserver/pkg/endpoints/discovery/v2/handler_test.go
 | 
					// copied from staging/src/k8s.io/apiserver/pkg/endpoints/discovery/v2/handler_test.go
 | 
				
			||||||
func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2beta1.APIGroupDiscoveryList {
 | 
					func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2.APIGroupDiscoveryList {
 | 
				
			||||||
	fuzzer := fuzz.NewWithSeed(seed)
 | 
						fuzzer := fuzz.NewWithSeed(seed)
 | 
				
			||||||
	fuzzer.NumElements(atLeastNumGroups, maxNumGroups)
 | 
						fuzzer.NumElements(atLeastNumGroups, maxNumGroups)
 | 
				
			||||||
	fuzzer.NilChance(0)
 | 
						fuzzer.NilChance(0)
 | 
				
			||||||
	fuzzer.Funcs(func(o *apidiscoveryv2beta1.APIGroupDiscovery, c fuzz.Continue) {
 | 
						fuzzer.Funcs(func(o *apidiscoveryv2.APIGroupDiscovery, c fuzz.Continue) {
 | 
				
			||||||
		c.FuzzNoCustom(o)
 | 
							c.FuzzNoCustom(o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The ResourceManager will just not serve the group if its versions
 | 
							// The ResourceManager will just not serve the group if its versions
 | 
				
			||||||
		// list is empty
 | 
							// list is empty
 | 
				
			||||||
		atLeastOne := apidiscoveryv2beta1.APIVersionDiscovery{}
 | 
							atLeastOne := apidiscoveryv2.APIVersionDiscovery{}
 | 
				
			||||||
		c.Fuzz(&atLeastOne)
 | 
							c.Fuzz(&atLeastOne)
 | 
				
			||||||
		o.Versions = append(o.Versions, atLeastOne)
 | 
							o.Versions = append(o.Versions, atLeastOne)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -958,10 +1025,10 @@ func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var apis []apidiscoveryv2beta1.APIGroupDiscovery
 | 
						var apis []apidiscoveryv2.APIGroupDiscovery
 | 
				
			||||||
	fuzzer.Fuzz(&apis)
 | 
						fuzzer.Fuzz(&apis)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return apidiscoveryv2beta1.APIGroupDiscoveryList{
 | 
						return apidiscoveryv2.APIGroupDiscoveryList{
 | 
				
			||||||
		TypeMeta: metav1.TypeMeta{
 | 
							TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
			Kind:       "APIGroupDiscoveryList",
 | 
								Kind:       "APIGroupDiscoveryList",
 | 
				
			||||||
			APIVersion: "v1",
 | 
								APIVersion: "v1",
 | 
				
			||||||
@@ -972,13 +1039,13 @@ func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// copied from staging/src/k8s.io/apiserver/pkg/endpoints/discovery/v2/handler_test.go
 | 
					// copied from staging/src/k8s.io/apiserver/pkg/endpoints/discovery/v2/handler_test.go
 | 
				
			||||||
func fetchPath(handler http.Handler, etag string) (*http.Response, []byte, *apidiscoveryv2beta1.APIGroupDiscoveryList) {
 | 
					func fetchPath(handler http.Handler, etag string) (*http.Response, []byte, *apidiscoveryv2.APIGroupDiscoveryList) {
 | 
				
			||||||
	// Expect json-formatted apis group list
 | 
						// Expect json-formatted apis group list
 | 
				
			||||||
	w := httptest.NewRecorder()
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
	req := httptest.NewRequest("GET", "/apis", nil)
 | 
						req := httptest.NewRequest("GET", "/apis", nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Ask for JSON response
 | 
						// Ask for JSON response
 | 
				
			||||||
	req.Header.Set("Accept", runtime.ContentTypeJSON+";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList")
 | 
						req.Header.Set("Accept", runtime.ContentTypeJSON+";g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList,"+runtime.ContentTypeJSON+";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if etag != "" {
 | 
						if etag != "" {
 | 
				
			||||||
		// Quote provided etag if unquoted
 | 
							// Quote provided etag if unquoted
 | 
				
			||||||
@@ -992,9 +1059,9 @@ func fetchPath(handler http.Handler, etag string) (*http.Response, []byte, *apid
 | 
				
			|||||||
	handler.ServeHTTP(w, req)
 | 
						handler.ServeHTTP(w, req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bytes := w.Body.Bytes()
 | 
						bytes := w.Body.Bytes()
 | 
				
			||||||
	var decoded *apidiscoveryv2beta1.APIGroupDiscoveryList
 | 
						var decoded *apidiscoveryv2.APIGroupDiscoveryList
 | 
				
			||||||
	if len(bytes) > 0 {
 | 
						if len(bytes) > 0 {
 | 
				
			||||||
		decoded = &apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
							decoded = &apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
		runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), bytes, decoded)
 | 
							runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), bytes, decoded)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
						apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
				
			||||||
	apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
						apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/test/integration/fixtures"
 | 
						"k8s.io/apiextensions-apiserver/test/integration/fixtures"
 | 
				
			||||||
@@ -143,7 +143,7 @@ var _ = SIGDescribe("AggregatedDiscovery", func() {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const aggregatedAccept = "application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
						const aggregatedAccept = "application/json;g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
		Release : v1.30
 | 
							Release : v1.30
 | 
				
			||||||
@@ -156,7 +156,7 @@ var _ = SIGDescribe("AggregatedDiscovery", func() {
 | 
				
			|||||||
			framework.Failf("Failed to get raw aggregated discovery document")
 | 
								framework.Failf("Failed to get raw aggregated discovery document")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		groupList := apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
							groupList := apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
		err = json.Unmarshal(d, &groupList)
 | 
							err = json.Unmarshal(d, &groupList)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			framework.Failf("Failed to parse discovery: %v", err)
 | 
								framework.Failf("Failed to parse discovery: %v", err)
 | 
				
			||||||
@@ -174,7 +174,7 @@ var _ = SIGDescribe("AggregatedDiscovery", func() {
 | 
				
			|||||||
			framework.Failf("Failed to get raw aggregated discovery document")
 | 
								framework.Failf("Failed to get raw aggregated discovery document")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		groupListLegacy := apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
							groupListLegacy := apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
		err = json.Unmarshal(d2, &groupListLegacy)
 | 
							err = json.Unmarshal(d2, &groupListLegacy)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			framework.Failf("Failed to parse discovery: %v", err)
 | 
								framework.Failf("Failed to parse discovery: %v", err)
 | 
				
			||||||
@@ -238,7 +238,7 @@ var _ = SIGDescribe("AggregatedDiscovery", func() {
 | 
				
			|||||||
				framework.Failf("Failed to get raw aggregated discovery document")
 | 
									framework.Failf("Failed to get raw aggregated discovery document")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			groupList := apidiscoveryv2beta1.APIGroupDiscoveryList{}
 | 
								groupList := apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
			err = json.Unmarshal(d, &groupList)
 | 
								err = json.Unmarshal(d, &groupList)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				framework.Failf("Failed to parse discovery: %v", err)
 | 
									framework.Failf("Failed to parse discovery: %v", err)
 | 
				
			||||||
@@ -392,7 +392,7 @@ func isGVPresent(gvs *metav1.APIGroupList, gv schema.GroupVersion) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func isGVRPresentAPIDiscovery(apidiscovery apidiscoveryv2beta1.APIGroupDiscoveryList, gvr schema.GroupVersionResource) bool {
 | 
					func isGVRPresentAPIDiscovery(apidiscovery apidiscoveryv2.APIGroupDiscoveryList, gvr schema.GroupVersionResource) bool {
 | 
				
			||||||
	for _, group := range apidiscovery.Items {
 | 
						for _, group := range apidiscovery.Items {
 | 
				
			||||||
		if gvr.Group == group.Name {
 | 
							if gvr.Group == group.Name {
 | 
				
			||||||
			for _, version := range group.Versions {
 | 
								for _, version := range group.Versions {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ import (
 | 
				
			|||||||
	"github.com/google/go-cmp/cmp"
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
						apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
				
			||||||
	apiextensions "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
						apiextensions "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						"k8s.io/apimachinery/pkg/api/meta"
 | 
				
			||||||
@@ -79,14 +79,14 @@ var (
 | 
				
			|||||||
	codecs    = runtimeserializer.NewCodecFactory(scheme)
 | 
						codecs    = runtimeserializer.NewCodecFactory(scheme)
 | 
				
			||||||
	serialize runtime.NegotiatedSerializer
 | 
						serialize runtime.NegotiatedSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	basicTestGroup = apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						basicTestGroup = apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Name: "stable.example.com",
 | 
								Name: "stable.example.com",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version: "v1",
 | 
									Version: "v1",
 | 
				
			||||||
				Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
									Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Resource:   "jobs",
 | 
											Resource:   "jobs",
 | 
				
			||||||
						Verbs:      []string{"create", "list", "watch", "delete"},
 | 
											Verbs:      []string{"create", "list", "watch", "delete"},
 | 
				
			||||||
@@ -94,19 +94,19 @@ var (
 | 
				
			|||||||
						Categories: []string{"all"},
 | 
											Categories: []string{"all"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	basicTestGroupWithFixup = apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						basicTestGroupWithFixup = apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Name: "stable.example.com",
 | 
								Name: "stable.example.com",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version: "v1",
 | 
									Version: "v1",
 | 
				
			||||||
				Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
 | 
									Resources: []apidiscoveryv2.APIResourceDiscovery{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Resource:   "jobs",
 | 
											Resource:   "jobs",
 | 
				
			||||||
						Verbs:      []string{"create", "list", "watch", "delete"},
 | 
											Verbs:      []string{"create", "list", "watch", "delete"},
 | 
				
			||||||
@@ -116,19 +116,19 @@ var (
 | 
				
			|||||||
						ResponseKind: &metav1.GroupVersionKind{},
 | 
											ResponseKind: &metav1.GroupVersionKind{},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	basicTestGroupStale = apidiscoveryv2beta1.APIGroupDiscovery{
 | 
						basicTestGroupStale = apidiscoveryv2.APIGroupDiscovery{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Name: "stable.example.com",
 | 
								Name: "stable.example.com",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
 | 
							Versions: []apidiscoveryv2.APIVersionDiscovery{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Version:   "v1",
 | 
									Version:   "v1",
 | 
				
			||||||
				Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale,
 | 
									Freshness: apidiscoveryv2.DiscoveryFreshnessStale,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -193,7 +193,7 @@ func TestReadinessAggregatedAPIServiceDiscovery(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Create a resource manager whichs serves our GroupVersion
 | 
						// Create a resource manager whichs serves our GroupVersion
 | 
				
			||||||
	resourceManager := discoveryendpoint.NewResourceManager("apis")
 | 
						resourceManager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
	resourceManager.SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery{basicTestGroup})
 | 
						resourceManager.SetGroups([]apidiscoveryv2.APIGroupDiscovery{basicTestGroup})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiServiceWaitCh := make(chan struct{})
 | 
						apiServiceWaitCh := make(chan struct{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -290,7 +290,7 @@ func TestAggregatedAPIServiceDiscovery(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Create a resource manager whichs serves our GroupVersion
 | 
						// Create a resource manager whichs serves our GroupVersion
 | 
				
			||||||
	resourceManager := discoveryendpoint.NewResourceManager("apis")
 | 
						resourceManager := discoveryendpoint.NewResourceManager("apis")
 | 
				
			||||||
	resourceManager.SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery{basicTestGroup})
 | 
						resourceManager.SetGroups([]apidiscoveryv2.APIGroupDiscovery{basicTestGroup})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Install our ResourceManager as an Aggregated APIService to the
 | 
						// Install our ResourceManager as an Aggregated APIService to the
 | 
				
			||||||
	// test server
 | 
						// test server
 | 
				
			||||||
@@ -371,7 +371,7 @@ func runTestCases(t *testing.T, cases []testCase) {
 | 
				
			|||||||
			})
 | 
								})
 | 
				
			||||||
			require.NoError(t, err, "v1 discovery must reset between tests: "+diff)
 | 
								require.NoError(t, err, "v1 discovery must reset between tests: "+diff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			err = WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
								err = WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
				diff = cmp.Diff(originalV2, result)
 | 
									diff = cmp.Diff(originalV2, result)
 | 
				
			||||||
				return reflect.DeepEqual(result, originalV2)
 | 
									return reflect.DeepEqual(result, originalV2)
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
@@ -393,6 +393,7 @@ func TestCRD(t *testing.T) {
 | 
				
			|||||||
				applyCRD(makeCRDSpec(stableGroup, "Foo", false, []string{"v1", "v1alpha1", "v1beta1", "v2"})),
 | 
									applyCRD(makeCRDSpec(stableGroup, "Foo", false, []string{"v1", "v1alpha1", "v1beta1", "v2"})),
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -402,6 +403,7 @@ func TestCRD(t *testing.T) {
 | 
				
			|||||||
				applyCRD(makeCRDSpec(stableGroup, "Foo", false, []string{"v1", "v1alpha1", "v1beta1", "v2"})),
 | 
									applyCRD(makeCRDSpec(stableGroup, "Foo", false, []string{"v1", "v1alpha1", "v1beta1", "v2"})),
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
 | 
				
			||||||
				deleteObject{
 | 
									deleteObject{
 | 
				
			||||||
					GroupVersionResource: metav1.GroupVersionResource(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions")),
 | 
										GroupVersionResource: metav1.GroupVersionResource(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions")),
 | 
				
			||||||
					Name:                 "foos.stable.example.com",
 | 
										Name:                 "foos.stable.example.com",
 | 
				
			||||||
@@ -469,6 +471,7 @@ func TestCRD(t *testing.T) {
 | 
				
			|||||||
				// Wait for GV to appear in both discovery documents
 | 
									// Wait for GV to appear in both discovery documents
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				applyAPIService(
 | 
									applyAPIService(
 | 
				
			||||||
					apiregistrationv1.APIServiceSpec{
 | 
										apiregistrationv1.APIServiceSpec{
 | 
				
			||||||
@@ -487,11 +490,13 @@ func TestCRD(t *testing.T) {
 | 
				
			|||||||
				// We should now have stable v1 available
 | 
									// We should now have stable v1 available
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV1}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV1}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// The CRD group-versions not served by the aggregated
 | 
									// The CRD group-versions not served by the aggregated
 | 
				
			||||||
				// apiservice should still be availablee
 | 
									// apiservice should still be availablee
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Remove API service. Show we have switched to CRD
 | 
									// Remove API service. Show we have switched to CRD
 | 
				
			||||||
				deleteObject{
 | 
									deleteObject{
 | 
				
			||||||
@@ -502,9 +507,11 @@ func TestCRD(t *testing.T) {
 | 
				
			|||||||
				// Show that we still have stable v1 since it is in the CRD
 | 
									// Show that we still have stable v1 since it is in the CRD
 | 
				
			||||||
				waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
				waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
									waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
									waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				waitForAbsentGroupVersionsV1([]metav1.GroupVersion{stableV1}),
 | 
									waitForAbsentGroupVersionsV1([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
				waitForAbsentGroupVersionsV2([]metav1.GroupVersion{stableV1}),
 | 
									waitForAbsentGroupVersionsV2([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
 | 
									waitForAbsentGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1}),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -635,9 +642,9 @@ func TestFreshness(t *testing.T) {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				switch entry.Freshness {
 | 
									switch entry.Freshness {
 | 
				
			||||||
				case apidiscoveryv2beta1.DiscoveryFreshnessCurrent:
 | 
									case apidiscoveryv2.DiscoveryFreshnessCurrent:
 | 
				
			||||||
					// Skip
 | 
										// Skip
 | 
				
			||||||
				case apidiscoveryv2beta1.DiscoveryFreshnessStale:
 | 
									case apidiscoveryv2.DiscoveryFreshnessStale:
 | 
				
			||||||
					staleGVs = append(staleGVs, targetGv)
 | 
										staleGVs = append(staleGVs, targetGv)
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return fmt.Errorf("unrecognized freshness '%v' on gv '%v'", entry.Freshness, targetGv)
 | 
										return fmt.Errorf("unrecognized freshness '%v' on gv '%v'", entry.Freshness, targetGv)
 | 
				
			||||||
@@ -704,7 +711,7 @@ func TestFreshness(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Shows a group for which multiple APIServices specify a GroupPriorityMinimum,
 | 
					// Shows a group for which multiple APIServices specify a GroupPriorityMinimum,
 | 
				
			||||||
// it is sorted the same in both versions of discovery
 | 
					// it is sorted the same in both versions of discovery
 | 
				
			||||||
func TestGroupPriorty(t *testing.T) {
 | 
					func TestGroupPriority(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.AggregatedDiscoveryEndpoint, true)()
 | 
						defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.AggregatedDiscoveryEndpoint, true)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	makeApiServiceSpec := func(gv metav1.GroupVersion, groupPriorityMin, versionPriority int) apiregistrationv1.APIServiceSpec {
 | 
						makeApiServiceSpec := func(gv metav1.GroupVersion, groupPriorityMin, versionPriority int) apiregistrationv1.APIServiceSpec {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/kubernetes"
 | 
						"k8s.io/client-go/kubernetes"
 | 
				
			||||||
	aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
						aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
 | 
				
			||||||
	apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
						apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
 | 
				
			||||||
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
						apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
@@ -43,7 +44,8 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const acceptV1JSON = "application/json"
 | 
					const acceptV1JSON = "application/json"
 | 
				
			||||||
const acceptV2JSON = "application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
					const acceptV2Beta1JSON = "application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
					const acceptV2JSON = "application/json;g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const maxTimeout = 10 * time.Second
 | 
					const maxTimeout = 10 * time.Second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,9 +95,15 @@ type waitForAbsentGroupVersionsV1 []metav1.GroupVersion
 | 
				
			|||||||
// Wait for groupversions to appear in v2 discovery
 | 
					// Wait for groupversions to appear in v2 discovery
 | 
				
			||||||
type waitForGroupVersionsV2 []metav1.GroupVersion
 | 
					type waitForGroupVersionsV2 []metav1.GroupVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Wait for groupversions to appear in v2beta1 discovery
 | 
				
			||||||
 | 
					type waitForGroupVersionsV2Beta1 []metav1.GroupVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wait for groupversions to disappear from v2 discovery
 | 
					// Wait for groupversions to disappear from v2 discovery
 | 
				
			||||||
type waitForAbsentGroupVersionsV2 []metav1.GroupVersion
 | 
					type waitForAbsentGroupVersionsV2 []metav1.GroupVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Wait for groupversions to disappear from v2beta1 discovery
 | 
				
			||||||
 | 
					type waitForAbsentGroupVersionsV2Beta1 []metav1.GroupVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type waitForStaleGroupVersionsV2 []metav1.GroupVersion
 | 
					type waitForStaleGroupVersionsV2 []metav1.GroupVersion
 | 
				
			||||||
type waitForFreshGroupVersionsV2 []metav1.GroupVersion
 | 
					type waitForFreshGroupVersionsV2 []metav1.GroupVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,10 +152,11 @@ func (a applyAPIService) Cleanup(ctx context.Context, client testClient) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = wait.PollWithContext(
 | 
						err = wait.PollUntilContextTimeout(
 | 
				
			||||||
		ctx,
 | 
							ctx,
 | 
				
			||||||
		250*time.Millisecond,
 | 
							250*time.Millisecond,
 | 
				
			||||||
		maxTimeout,
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
		func(ctx context.Context) (done bool, err error) {
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
			_, err = client.ApiregistrationV1().APIServices().Get(ctx, name, metav1.GetOptions{})
 | 
								_, err = client.ApiregistrationV1().APIServices().Get(ctx, name, metav1.GetOptions{})
 | 
				
			||||||
			if err == nil {
 | 
								if err == nil {
 | 
				
			||||||
@@ -212,10 +221,11 @@ func (a applyCRD) Cleanup(ctx context.Context, client testClient) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = wait.PollWithContext(
 | 
						err = wait.PollUntilContextTimeout(
 | 
				
			||||||
		ctx,
 | 
							ctx,
 | 
				
			||||||
		250*time.Millisecond,
 | 
							250*time.Millisecond,
 | 
				
			||||||
		maxTimeout,
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
		func(ctx context.Context) (done bool, err error) {
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
			_, err = client.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, name, metav1.GetOptions{})
 | 
								_, err = client.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, name, metav1.GetOptions{})
 | 
				
			||||||
			if err == nil {
 | 
								if err == nil {
 | 
				
			||||||
@@ -248,9 +258,9 @@ func (d deleteObject) Do(ctx context.Context, client testClient) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForStaleGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForStaleGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gv := range w {
 | 
							for _, gv := range w {
 | 
				
			||||||
			if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2beta1.DiscoveryFreshnessStale {
 | 
								if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2.DiscoveryFreshnessStale {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -265,9 +275,9 @@ func (w waitForStaleGroupVersionsV2) Do(ctx context.Context, client testClient)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForFreshGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForFreshGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gv := range w {
 | 
							for _, gv := range w {
 | 
				
			||||||
			if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2beta1.DiscoveryFreshnessCurrent {
 | 
								if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2.DiscoveryFreshnessCurrent {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -282,7 +292,7 @@ func (w waitForFreshGroupVersionsV2) Do(ctx context.Context, client testClient)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gv := range w {
 | 
							for _, gv := range w {
 | 
				
			||||||
			if FindGroupVersionV2(result, gv) == nil {
 | 
								if FindGroupVersionV2(result, gv) == nil {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
@@ -298,8 +308,25 @@ func (w waitForGroupVersionsV2) Do(ctx context.Context, client testClient) error
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w waitForGroupVersionsV2Beta1) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
 | 
						err := WaitForV2Beta1ResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
				
			||||||
 | 
							for _, gv := range w {
 | 
				
			||||||
 | 
								if FindGroupVersionV2Beta1(result, gv) == nil {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("waiting for groupversions v2 (%v): %w", w, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForAbsentGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForAbsentGroupVersionsV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gv := range w {
 | 
							for _, gv := range w {
 | 
				
			||||||
			if FindGroupVersionV2(result, gv) != nil {
 | 
								if FindGroupVersionV2(result, gv) != nil {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
@@ -315,6 +342,23 @@ func (w waitForAbsentGroupVersionsV2) Do(ctx context.Context, client testClient)
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w waitForAbsentGroupVersionsV2Beta1) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
 | 
						err := WaitForV2Beta1ResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
				
			||||||
 | 
							for _, gv := range w {
 | 
				
			||||||
 | 
								if FindGroupVersionV2Beta1(result, gv) != nil {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("waiting for absent groupversions v2 (%v): %w", w, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForGroupVersionsV1) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForGroupVersionsV1) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForV1GroupsWithCondition(ctx, client, func(result metav1.APIGroupList) bool {
 | 
						err := WaitForV1GroupsWithCondition(ctx, client, func(result metav1.APIGroupList) bool {
 | 
				
			||||||
		for _, gv := range w {
 | 
							for _, gv := range w {
 | 
				
			||||||
@@ -429,7 +473,7 @@ func (w waitForResourcesAbsentV1) Do(ctx context.Context, client testClient) err
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForResourcesV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForResourcesV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gvr := range w {
 | 
							for _, gvr := range w {
 | 
				
			||||||
			if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
 | 
								if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
@@ -458,7 +502,7 @@ func (w waitForResourcesV2) Do(ctx context.Context, client testClient) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w waitForResourcesAbsentV2) Do(ctx context.Context, client testClient) error {
 | 
					func (w waitForResourcesAbsentV2) Do(ctx context.Context, client testClient) error {
 | 
				
			||||||
	err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, gvr := range w {
 | 
							for _, gvr := range w {
 | 
				
			||||||
			if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
 | 
								if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
@@ -484,7 +528,7 @@ func (i inlineAction) Do(ctx context.Context, client testClient) error {
 | 
				
			|||||||
	return i(ctx, client)
 | 
						return i(ctx, client)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FetchV2Discovery(ctx context.Context, client testClient) (apidiscoveryv2beta1.APIGroupDiscoveryList, error) {
 | 
					func FetchV2Discovery(ctx context.Context, client testClient) (apidiscoveryv2.APIGroupDiscoveryList, error) {
 | 
				
			||||||
	result, err := client.
 | 
						result, err := client.
 | 
				
			||||||
		Discovery().
 | 
							Discovery().
 | 
				
			||||||
		RESTClient().
 | 
							RESTClient().
 | 
				
			||||||
@@ -494,6 +538,29 @@ func FetchV2Discovery(ctx context.Context, client testClient) (apidiscoveryv2bet
 | 
				
			|||||||
		Do(ctx).
 | 
							Do(ctx).
 | 
				
			||||||
		Raw()
 | 
							Raw()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return apidiscoveryv2.APIGroupDiscoveryList{}, fmt.Errorf("failed to fetch v2 discovery: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						groupList := apidiscoveryv2.APIGroupDiscoveryList{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(result, &groupList)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return apidiscoveryv2.APIGroupDiscoveryList{}, fmt.Errorf("failed to parse v2 discovery: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return groupList, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FetchV2Beta1Discovery(ctx context.Context, client testClient) (apidiscoveryv2beta1.APIGroupDiscoveryList, error) {
 | 
				
			||||||
 | 
						result, err := client.
 | 
				
			||||||
 | 
							Discovery().
 | 
				
			||||||
 | 
							RESTClient().
 | 
				
			||||||
 | 
							Get().
 | 
				
			||||||
 | 
							AbsPath("/apis").
 | 
				
			||||||
 | 
							SetHeader("Accept", acceptV2Beta1JSON).
 | 
				
			||||||
 | 
							Do(ctx).
 | 
				
			||||||
 | 
							Raw()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return apidiscoveryv2beta1.APIGroupDiscoveryList{}, fmt.Errorf("failed to fetch v2 discovery: %w", err)
 | 
							return apidiscoveryv2beta1.APIGroupDiscoveryList{}, fmt.Errorf("failed to fetch v2 discovery: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -562,7 +629,7 @@ func FetchV1DiscoveryResource(ctx context.Context, client testClient, gv metav1.
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WaitForGroupsAbsent(ctx context.Context, client testClient, groups ...string) error {
 | 
					func WaitForGroupsAbsent(ctx context.Context, client testClient, groups ...string) error {
 | 
				
			||||||
	return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, searchGroup := range groups {
 | 
							for _, searchGroup := range groups {
 | 
				
			||||||
			for _, docGroup := range groupList.Items {
 | 
								for _, docGroup := range groupList.Items {
 | 
				
			||||||
				if docGroup.Name == searchGroup {
 | 
									if docGroup.Name == searchGroup {
 | 
				
			||||||
@@ -598,8 +665,8 @@ func WaitForRootPaths(t *testing.T, ctx context.Context, client testClient, requ
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WaitForGroups(ctx context.Context, client testClient, groups ...apidiscoveryv2beta1.APIGroupDiscovery) error {
 | 
					func WaitForGroups(ctx context.Context, client testClient, groups ...apidiscoveryv2.APIGroupDiscovery) error {
 | 
				
			||||||
	return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
 | 
						return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2.APIGroupDiscoveryList) bool {
 | 
				
			||||||
		for _, searchGroup := range groups {
 | 
							for _, searchGroup := range groups {
 | 
				
			||||||
			found := false
 | 
								found := false
 | 
				
			||||||
			for _, docGroup := range groupList.Items {
 | 
								for _, docGroup := range groupList.Items {
 | 
				
			||||||
@@ -616,13 +683,14 @@ func WaitForGroups(ctx context.Context, client testClient, groups ...apidiscover
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WaitForResultWithCondition(ctx context.Context, client testClient, condition func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool) error {
 | 
					func WaitForResultWithCondition(ctx context.Context, client testClient, condition func(result apidiscoveryv2.APIGroupDiscoveryList) bool) error {
 | 
				
			||||||
	// Keep repeatedly fetching document from aggregator.
 | 
						// Keep repeatedly fetching document from aggregator.
 | 
				
			||||||
	// Check to see if it contains our service within a reasonable amount of time
 | 
						// Check to see if it contains our service within a reasonable amount of time
 | 
				
			||||||
	return wait.PollWithContext(
 | 
						return wait.PollUntilContextTimeout(
 | 
				
			||||||
		ctx,
 | 
							ctx,
 | 
				
			||||||
		250*time.Millisecond,
 | 
							250*time.Millisecond,
 | 
				
			||||||
		maxTimeout,
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
		func(ctx context.Context) (done bool, err error) {
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
			groupList, err := FetchV2Discovery(ctx, client)
 | 
								groupList, err := FetchV2Discovery(ctx, client)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -637,13 +705,36 @@ func WaitForResultWithCondition(ctx context.Context, client testClient, conditio
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func WaitForV2Beta1ResultWithCondition(ctx context.Context, client testClient, condition func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool) error {
 | 
				
			||||||
 | 
						// Keep repeatedly fetching document from aggregator.
 | 
				
			||||||
 | 
						// Check to see if it contains our service within a reasonable amount of time
 | 
				
			||||||
 | 
						return wait.PollUntilContextTimeout(
 | 
				
			||||||
 | 
							ctx,
 | 
				
			||||||
 | 
							250*time.Millisecond,
 | 
				
			||||||
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
 | 
								groupList, err := FetchV2Beta1Discovery(ctx, client)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return false, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if condition(groupList) {
 | 
				
			||||||
 | 
									return true, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return false, nil
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WaitForV1GroupsWithCondition(ctx context.Context, client testClient, condition func(result metav1.APIGroupList) bool) error {
 | 
					func WaitForV1GroupsWithCondition(ctx context.Context, client testClient, condition func(result metav1.APIGroupList) bool) error {
 | 
				
			||||||
	// Keep repeatedly fetching document from aggregator.
 | 
						// Keep repeatedly fetching document from aggregator.
 | 
				
			||||||
	// Check to see if it contains our service within a reasonable amount of time
 | 
						// Check to see if it contains our service within a reasonable amount of time
 | 
				
			||||||
	return wait.PollWithContext(
 | 
						return wait.PollUntilContextTimeout(
 | 
				
			||||||
		ctx,
 | 
							ctx,
 | 
				
			||||||
		250*time.Millisecond,
 | 
							250*time.Millisecond,
 | 
				
			||||||
		maxTimeout,
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
		func(ctx context.Context) (done bool, err error) {
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
			groupList, err := FetchV1DiscoveryGroups(ctx, client)
 | 
								groupList, err := FetchV1DiscoveryGroups(ctx, client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -662,10 +753,11 @@ func WaitForV1GroupsWithCondition(ctx context.Context, client testClient, condit
 | 
				
			|||||||
func WaitForV1ResourcesWithCondition(ctx context.Context, client testClient, gv metav1.GroupVersion, condition func(result metav1.APIResourceList) bool) error {
 | 
					func WaitForV1ResourcesWithCondition(ctx context.Context, client testClient, gv metav1.GroupVersion, condition func(result metav1.APIResourceList) bool) error {
 | 
				
			||||||
	// Keep repeatedly fetching document from aggregator.
 | 
						// Keep repeatedly fetching document from aggregator.
 | 
				
			||||||
	// Check to see if it contains our service within a reasonable amount of time
 | 
						// Check to see if it contains our service within a reasonable amount of time
 | 
				
			||||||
	return wait.PollWithContext(
 | 
						return wait.PollUntilContextTimeout(
 | 
				
			||||||
		ctx,
 | 
							ctx,
 | 
				
			||||||
		250*time.Millisecond,
 | 
							250*time.Millisecond,
 | 
				
			||||||
		maxTimeout,
 | 
							maxTimeout,
 | 
				
			||||||
 | 
							true,
 | 
				
			||||||
		func(ctx context.Context) (done bool, err error) {
 | 
							func(ctx context.Context) (done bool, err error) {
 | 
				
			||||||
			resourceList, err := FetchV1DiscoveryResource(ctx, client, gv)
 | 
								resourceList, err := FetchV1DiscoveryResource(ctx, client, gv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -697,7 +789,23 @@ func FindGroupVersionV1(discovery metav1.APIGroupList, gv metav1.GroupVersion) b
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FindGroupVersionV2(discovery apidiscoveryv2beta1.APIGroupDiscoveryList, gv metav1.GroupVersion) *apidiscoveryv2beta1.APIVersionDiscovery {
 | 
					func FindGroupVersionV2(discovery apidiscoveryv2.APIGroupDiscoveryList, gv metav1.GroupVersion) *apidiscoveryv2.APIVersionDiscovery {
 | 
				
			||||||
 | 
						for _, documentGroup := range discovery.Items {
 | 
				
			||||||
 | 
							if documentGroup.Name != gv.Group {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, documentVersion := range documentGroup.Versions {
 | 
				
			||||||
 | 
								if documentVersion.Version == gv.Version {
 | 
				
			||||||
 | 
									return &documentVersion
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FindGroupVersionV2Beta1(discovery apidiscoveryv2beta1.APIGroupDiscoveryList, gv metav1.GroupVersion) *apidiscoveryv2beta1.APIVersionDiscovery {
 | 
				
			||||||
	for _, documentGroup := range discovery.Items {
 | 
						for _, documentGroup := range discovery.Items {
 | 
				
			||||||
		if documentGroup.Name != gv.Group {
 | 
							if documentGroup.Name != gv.Group {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user