Use v2 types with agg discovery
This commit is contained in:
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
autoscaling "k8s.io/api/autoscaling/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -87,7 +87,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
|
||||
apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{}
|
||||
apiResourcesForDiscovery := []metav1.APIResource{}
|
||||
aggregatedApiResourcesForDiscovery := []apidiscoveryv2beta1.APIResourceDiscovery{}
|
||||
aggregatedAPIResourcesForDiscovery := []apidiscoveryv2.APIResourceDiscovery{}
|
||||
versionsForDiscoveryMap := map[metav1.GroupVersion]bool{}
|
||||
|
||||
crds, err := c.crdLister.List(labels.Everything())
|
||||
@@ -158,13 +158,13 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
}
|
||||
|
||||
if c.resourceManager != nil {
|
||||
var scope apidiscoveryv2beta1.ResourceScope
|
||||
var scope apidiscoveryv2.ResourceScope
|
||||
if crd.Spec.Scope == apiextensionsv1.NamespaceScoped {
|
||||
scope = apidiscoveryv2beta1.ScopeNamespace
|
||||
scope = apidiscoveryv2.ScopeNamespace
|
||||
} else {
|
||||
scope = apidiscoveryv2beta1.ScopeCluster
|
||||
scope = apidiscoveryv2.ScopeCluster
|
||||
}
|
||||
apiResourceDiscovery := apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
apiResourceDiscovery := apidiscoveryv2.APIResourceDiscovery{
|
||||
Resource: crd.Status.AcceptedNames.Plural,
|
||||
SingularResource: crd.Status.AcceptedNames.Singular,
|
||||
Scope: scope,
|
||||
@@ -178,7 +178,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
Categories: crd.Status.AcceptedNames.Categories,
|
||||
}
|
||||
if subresources != nil && subresources.Status != nil {
|
||||
apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2.APISubresourceDiscovery{
|
||||
Subresource: "status",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: version.Group,
|
||||
@@ -189,7 +189,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
})
|
||||
}
|
||||
if subresources != nil && subresources.Scale != nil {
|
||||
apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
apiResourceDiscovery.Subresources = append(apiResourceDiscovery.Subresources, apidiscoveryv2.APISubresourceDiscovery{
|
||||
Subresource: "scale",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
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 {
|
||||
@@ -260,14 +260,14 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
return apiResourcesForDiscovery
|
||||
})))
|
||||
|
||||
sort.Slice(aggregatedApiResourcesForDiscovery[:], func(i, j int) bool {
|
||||
return aggregatedApiResourcesForDiscovery[i].Resource < aggregatedApiResourcesForDiscovery[j].Resource
|
||||
sort.Slice(aggregatedAPIResourcesForDiscovery, func(i, j int) bool {
|
||||
return aggregatedAPIResourcesForDiscovery[i].Resource < aggregatedAPIResourcesForDiscovery[j].Resource
|
||||
})
|
||||
if c.resourceManager != nil {
|
||||
c.resourceManager.AddGroupVersion(version.Group, apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
c.resourceManager.AddGroupVersion(version.Group, apidiscoveryv2.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
Version: version.Version,
|
||||
Resources: aggregatedApiResourcesForDiscovery,
|
||||
Resources: aggregatedAPIResourcesForDiscovery,
|
||||
})
|
||||
// Default priority for CRDs
|
||||
c.resourceManager.SetGroupVersionPriority(metav1.GroupVersion(version), 1000, 100)
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"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",
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "coolfoos",
|
||||
Scope: apidiscoveryv2beta1.ScopeCluster,
|
||||
Scope: apidiscoveryv2.ScopeCluster,
|
||||
SingularResource: "coolfoo",
|
||||
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
||||
ShortNames: []string{"foo"},
|
||||
@@ -141,7 +141,7 @@ var coolFooDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2bet
|
||||
Version: "v1",
|
||||
Kind: "CoolFoo",
|
||||
},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{
|
||||
Subresource: "status",
|
||||
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",
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "coolbars",
|
||||
Scope: apidiscoveryv2beta1.ScopeCluster,
|
||||
Scope: apidiscoveryv2.ScopeCluster,
|
||||
SingularResource: "coolbar",
|
||||
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
||||
ShortNames: []string{"bar"},
|
||||
@@ -175,7 +175,7 @@ var mergedDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta
|
||||
},
|
||||
}, {
|
||||
Resource: "coolfoos",
|
||||
Scope: apidiscoveryv2beta1.ScopeCluster,
|
||||
Scope: apidiscoveryv2.ScopeCluster,
|
||||
SingularResource: "coolfoo",
|
||||
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
||||
ShortNames: []string{"foo"},
|
||||
@@ -185,7 +185,7 @@ var mergedDiscovery apidiscoveryv2beta1.APIVersionDiscovery = apidiscoveryv2beta
|
||||
Version: "v1",
|
||||
Kind: "CoolFoo",
|
||||
},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{
|
||||
Subresource: "status",
|
||||
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"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
)
|
||||
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
func ServeHTTPWithETag(
|
||||
object runtime.Object,
|
||||
hash string,
|
||||
targetGV schema.GroupVersion,
|
||||
serializer runtime.NegotiatedSerializer,
|
||||
w http.ResponseWriter,
|
||||
req *http.Request,
|
||||
@@ -64,7 +66,7 @@ func ServeHTTPWithETag(
|
||||
responsewriters.WriteObjectNegotiated(
|
||||
serializer,
|
||||
DiscoveryEndpointRestrictions,
|
||||
AggregatedDiscoveryGV,
|
||||
targetGV,
|
||||
w,
|
||||
req,
|
||||
http.StatusOK,
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"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"
|
||||
"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()
|
||||
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()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
|
@@ -17,15 +17,22 @@ limitations under the License.
|
||||
package aggregated
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"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/negotiation"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
|
||||
"sync/atomic"
|
||||
@@ -51,7 +58,7 @@ type ResourceManager interface {
|
||||
// Adds knowledge of the given groupversion to the discovery document
|
||||
// If it was already being tracked, updates the stored APIVersionDiscovery
|
||||
// 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
|
||||
// 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
|
||||
// with the given groups
|
||||
// Thread-Safe
|
||||
SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery)
|
||||
SetGroups([]apidiscoveryv2.APIGroupDiscovery)
|
||||
|
||||
// Returns the same resource manager using a different source
|
||||
// The source is used to decide how to de-duplicate groups.
|
||||
@@ -87,7 +94,7 @@ type resourceManager struct {
|
||||
*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)
|
||||
}
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -133,7 +140,7 @@ type resourceDiscoveryManager struct {
|
||||
// Writes protected by the lock.
|
||||
// List of all apigroups & resources indexed by the resource manager
|
||||
lock sync.RWMutex
|
||||
apiGroups map[groupKey]*apidiscoveryv2beta1.APIGroupDiscovery
|
||||
apiGroups map[groupKey]*apidiscoveryv2.APIGroupDiscovery
|
||||
versionPriorities map[groupVersionKey]priorityInfo
|
||||
}
|
||||
|
||||
@@ -144,8 +151,12 @@ type priorityInfo struct {
|
||||
|
||||
func NewResourceManager(path string) ResourceManager {
|
||||
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))
|
||||
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
rdm := &resourceDiscoveryManager{
|
||||
serializer: codecs,
|
||||
versionPriorities: make(map[groupVersionKey]priorityInfo),
|
||||
@@ -181,7 +192,7 @@ func (rdm *resourceDiscoveryManager) SetGroupVersionPriority(source Source, gv m
|
||||
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()
|
||||
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()
|
||||
defer rdm.lock.Unlock()
|
||||
|
||||
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 {
|
||||
rdm.apiGroups = make(map[groupKey]*apidiscoveryv2beta1.APIGroupDiscovery)
|
||||
rdm.apiGroups = make(map[groupKey]*apidiscoveryv2.APIGroupDiscovery)
|
||||
}
|
||||
|
||||
key := groupKey{
|
||||
@@ -264,11 +275,11 @@ func (rdm *resourceDiscoveryManager) addGroupVersionLocked(source Source, groupN
|
||||
}
|
||||
|
||||
} else {
|
||||
group := &apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
group := &apidiscoveryv2.APIGroupDiscovery{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: groupName,
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{value},
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{value},
|
||||
}
|
||||
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
|
||||
// list and sorting them according to insertion order
|
||||
func (rdm *resourceDiscoveryManager) calculateAPIGroupsLocked() []apidiscoveryv2beta1.APIGroupDiscovery {
|
||||
func (rdm *resourceDiscoveryManager) calculateAPIGroupsLocked() []apidiscoveryv2.APIGroupDiscovery {
|
||||
regenerationCounter.Inc()
|
||||
// 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{}
|
||||
|
||||
for key, group := range rdm.apiGroups {
|
||||
@@ -475,7 +486,7 @@ func (rdm *resourceDiscoveryManager) fetchFromCache() *cachedGroupList {
|
||||
if cacheLoad != nil {
|
||||
return cacheLoad
|
||||
}
|
||||
response := apidiscoveryv2beta1.APIGroupDiscoveryList{
|
||||
response := apidiscoveryv2.APIGroupDiscoveryList{
|
||||
Items: rdm.calculateAPIGroupsLocked(),
|
||||
}
|
||||
etag, err := calculateETag(response)
|
||||
@@ -492,7 +503,13 @@ func (rdm *resourceDiscoveryManager) fetchFromCache() *cachedGroupList {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -505,11 +522,30 @@ func (rdm *resourceDiscoveryManager) serveHTTP(resp http.ResponseWriter, req *ht
|
||||
response := cache.cachedResponse
|
||||
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 {
|
||||
// Use proper e-tag headers if one is available
|
||||
ServeHTTPWithETag(
|
||||
&response,
|
||||
etag,
|
||||
targetGV,
|
||||
rdm.serializer,
|
||||
resp,
|
||||
req,
|
||||
@@ -520,7 +556,7 @@ func (rdm *resourceDiscoveryManager) serveHTTP(resp http.ResponseWriter, req *ht
|
||||
responsewriters.WriteObjectNegotiated(
|
||||
rdm.serializer,
|
||||
DiscoveryEndpointRestrictions,
|
||||
AggregatedDiscoveryGV,
|
||||
targetGV,
|
||||
resp,
|
||||
req,
|
||||
http.StatusOK,
|
||||
|
@@ -32,11 +32,15 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
apidiscoveryv2conversion "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
)
|
||||
|
||||
@@ -46,21 +50,23 @@ var codecs = runtimeserializer.NewCodecFactory(scheme)
|
||||
const discoveryPath = "/apis"
|
||||
|
||||
func init() {
|
||||
// Add all builtin types to scheme
|
||||
apidiscoveryv2beta1.AddToScheme(scheme)
|
||||
// Register conversion for apidiscovery
|
||||
apidiscoveryv2.SchemeBuilder.Register(apidiscoveryv2conversion.RegisterConversions)
|
||||
utilruntime.Must(apidiscoveryv2.AddToScheme(scheme))
|
||||
utilruntime.Must(apidiscoveryv2beta1.AddToScheme(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.NumElements(atLeastNumGroups, maxNumGroups)
|
||||
fuzzer.NilChance(0)
|
||||
fuzzer.Funcs(func(o *apidiscoveryv2beta1.APIGroupDiscovery, c fuzz.Continue) {
|
||||
fuzzer.Funcs(func(o *apidiscoveryv2.APIGroupDiscovery, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(o)
|
||||
|
||||
// The ResourceManager will just not serve the group if its versions
|
||||
// list is empty
|
||||
atLeastOne := apidiscoveryv2beta1.APIVersionDiscovery{}
|
||||
atLeastOne := apidiscoveryv2.APIVersionDiscovery{}
|
||||
c.Fuzz(&atLeastOne)
|
||||
o.Versions = append(o.Versions, atLeastOne)
|
||||
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)
|
||||
sort.Slice(apis[:], func(i, j int) bool {
|
||||
return apis[i].Name < apis[j].Name
|
||||
})
|
||||
|
||||
return apidiscoveryv2beta1.APIGroupDiscoveryList{
|
||||
return apidiscoveryv2.APIGroupDiscoveryList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "APIGroupDiscoveryList",
|
||||
APIVersion: "apidiscovery.k8s.io/v2beta1",
|
||||
APIVersion: "apidiscovery.k8s.io/v2",
|
||||
},
|
||||
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
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", discoveryPath, nil)
|
||||
|
||||
// Ask for JSON response
|
||||
req.Header.Set("Accept", acceptPrefix+";g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList")
|
||||
req.Header.Set("Accept", accept)
|
||||
|
||||
if etag != "" {
|
||||
// Quote provided etag if unquoted
|
||||
@@ -110,13 +146,7 @@ func fetchPath(handler http.Handler, acceptPrefix string, path string, etag stri
|
||||
handler.ServeHTTP(w, req)
|
||||
|
||||
bytes := w.Body.Bytes()
|
||||
var decoded *apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
if len(bytes) > 0 {
|
||||
decoded = &apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
runtime.DecodeInto(codecs.UniversalDecoder(), bytes, decoded)
|
||||
}
|
||||
|
||||
return w.Result(), bytes, decoded
|
||||
return w.Result(), bytes
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
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.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, "")
|
||||
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.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
|
||||
// e.g.: Multiple services with the same contents should have the same etag.
|
||||
func TestEtagConsistent(t *testing.T) {
|
||||
@@ -348,7 +406,7 @@ func TestUpdateService(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
var newapis apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
var newapis apidiscoveryv2.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(b, &newapis)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -369,7 +427,7 @@ func TestUpdateService(t *testing.T) {
|
||||
func TestMultipleSources(t *testing.T) {
|
||||
type pair struct {
|
||||
manager discoveryendpoint.ResourceManager
|
||||
apis apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
apis apidiscoveryv2.APIGroupDiscoveryList
|
||||
}
|
||||
|
||||
pairs := []pair{}
|
||||
@@ -388,7 +446,7 @@ func TestMultipleSources(t *testing.T) {
|
||||
pairs = append(pairs, pair{manager, apis})
|
||||
}
|
||||
|
||||
expectedResult := []apidiscoveryv2beta1.APIGroupDiscovery{}
|
||||
expectedResult := []apidiscoveryv2.APIGroupDiscovery{}
|
||||
|
||||
groupCounter := 0
|
||||
for _, p := range pairs {
|
||||
@@ -422,7 +480,7 @@ func TestSourcePrecedence(t *testing.T) {
|
||||
apis := fuzzAPIGroups(1, 3, int64(15))
|
||||
for _, g := range apis.Items {
|
||||
for i, v := range g.Versions {
|
||||
v.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessCurrent
|
||||
v.Freshness = apidiscoveryv2.DiscoveryFreshnessCurrent
|
||||
g.Versions[i] = v
|
||||
otherManager.AddGroupVersion(g.Name, v)
|
||||
}
|
||||
@@ -434,12 +492,12 @@ func TestSourcePrecedence(t *testing.T) {
|
||||
// Add the first groupversion under default.
|
||||
// No versions should appear in discovery document except this one
|
||||
overrideVersion := initialDocument.Items[0].Versions[0]
|
||||
overrideVersion.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessStale
|
||||
overrideVersion.Freshness = apidiscoveryv2.DiscoveryFreshnessStale
|
||||
defaultManager.AddGroupVersion(initialDocument.Items[0].Name, overrideVersion)
|
||||
|
||||
_, _, maskedDocument := fetchPath(defaultManager, "application/json", discoveryPath, "")
|
||||
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)
|
||||
|
||||
@@ -593,19 +651,19 @@ func TestAbuse(t *testing.T) {
|
||||
func TestVersionSortingNoPriority(t *testing.T) {
|
||||
manager := discoveryendpoint.NewResourceManager("apis")
|
||||
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1alpha1",
|
||||
})
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v2beta1",
|
||||
})
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1",
|
||||
})
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1beta1",
|
||||
})
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v2",
|
||||
})
|
||||
|
||||
@@ -625,11 +683,11 @@ func TestVersionSortingNoPriority(t *testing.T) {
|
||||
func TestVersionSortingWithPriority(t *testing.T) {
|
||||
manager := discoveryendpoint.NewResourceManager("apis")
|
||||
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1alpha1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1alpha1"}, 1000, 200)
|
||||
@@ -648,15 +706,15 @@ func TestVersionSortingWithPriority(t *testing.T) {
|
||||
func TestGroupVersionSortingConflictingPriority(t *testing.T) {
|
||||
manager := discoveryendpoint.NewResourceManager("apis")
|
||||
|
||||
manager.AddGroupVersion("default", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("default", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "default", Version: "v1"}, 1000, 100)
|
||||
manager.AddGroupVersion("test", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("test", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1alpha1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 500, 100)
|
||||
manager.AddGroupVersion("test", apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion("test", apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1alpha2",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: "test", Version: "v1alpha1"}, 2000, 100)
|
||||
@@ -679,17 +737,17 @@ func TestStatelessGroupPriorityMinimum(t *testing.T) {
|
||||
stableGroup := "stable.example.com"
|
||||
experimentalGroup := "experimental.example.com"
|
||||
|
||||
manager.AddGroupVersion(stableGroup, apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion(stableGroup, apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: stableGroup, Version: "v1"}, 1000, 100)
|
||||
|
||||
manager.AddGroupVersion(experimentalGroup, apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion(experimentalGroup, apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1"}, 100, 100)
|
||||
|
||||
manager.AddGroupVersion(experimentalGroup, apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
manager.AddGroupVersion(experimentalGroup, apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: "v1alpha1",
|
||||
})
|
||||
manager.SetGroupVersionPriority(metav1.GroupVersion{Group: experimentalGroup, Version: "v1alpha1"}, 10000, 100)
|
||||
|
@@ -20,8 +20,6 @@ import (
|
||||
"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"
|
||||
|
||||
// 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.
|
||||
func IsAggregatedDiscoveryGVK(gvk *schema.GroupVersionKind) bool {
|
||||
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
|
||||
}
|
||||
|
@@ -19,8 +19,10 @@ package aggregated
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"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
|
||||
// emit the aggregated discovery by passing in the aggregated
|
||||
// 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 {
|
||||
scheme := runtime.NewScheme()
|
||||
apidiscoveryv2beta1.AddToScheme(scheme)
|
||||
utilruntime.Must(apidiscoveryv2.AddToScheme(scheme))
|
||||
utilruntime.Must(apidiscoveryv2beta1.AddToScheme(scheme))
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
return &WrappedHandler{codecs, handler, aggHandler}
|
||||
}
|
||||
|
@@ -32,8 +32,11 @@ import (
|
||||
const discoveryPath = "/apis"
|
||||
const jsonAccept = "application/json"
|
||||
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 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
|
||||
accept: "",
|
||||
expected: "unaggregated",
|
||||
}, {
|
||||
accept: aggregatedV2Beta1JSONAccept,
|
||||
expected: "aggregated",
|
||||
}, {
|
||||
accept: aggregatedV2Beta1ProtoAccept,
|
||||
expected: "aggregated",
|
||||
}, {
|
||||
accept: aggregatedJSONAccept,
|
||||
expected: "aggregated",
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
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"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"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.
|
||||
// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
|
||||
// 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)
|
||||
installer := &APIInstaller{
|
||||
group: g,
|
||||
|
@@ -28,7 +28,7 @@ import (
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
"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"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"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
|
||||
}
|
||||
|
||||
func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscoveryv2beta1.APIResourceDiscovery, error) {
|
||||
var apiResourceList []apidiscoveryv2beta1.APIResourceDiscovery
|
||||
func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscoveryv2.APIResourceDiscovery, error) {
|
||||
var apiResourceList []apidiscoveryv2.APIResourceDiscovery
|
||||
parentResources := make(map[string]int)
|
||||
|
||||
// Loop through all top-level resources
|
||||
@@ -82,14 +82,14 @@ func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscove
|
||||
continue
|
||||
}
|
||||
|
||||
var scope apidiscoveryv2beta1.ResourceScope
|
||||
var scope apidiscoveryv2.ResourceScope
|
||||
if r.Namespaced {
|
||||
scope = apidiscoveryv2beta1.ScopeNamespace
|
||||
scope = apidiscoveryv2.ScopeNamespace
|
||||
} else {
|
||||
scope = apidiscoveryv2beta1.ScopeCluster
|
||||
scope = apidiscoveryv2.ScopeCluster
|
||||
}
|
||||
|
||||
resource := apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
resource := apidiscoveryv2.APIResourceDiscovery{
|
||||
Resource: r.Name,
|
||||
Scope: scope,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
@@ -116,17 +116,17 @@ func ConvertGroupVersionIntoToDiscovery(list []metav1.APIResource) ([]apidiscove
|
||||
continue
|
||||
}
|
||||
|
||||
var scope apidiscoveryv2beta1.ResourceScope
|
||||
var scope apidiscoveryv2.ResourceScope
|
||||
if r.Namespaced {
|
||||
scope = apidiscoveryv2beta1.ScopeNamespace
|
||||
scope = apidiscoveryv2.ScopeNamespace
|
||||
} else {
|
||||
scope = apidiscoveryv2beta1.ScopeCluster
|
||||
scope = apidiscoveryv2.ScopeCluster
|
||||
}
|
||||
|
||||
parentidx, exists := parentResources[split[0]]
|
||||
if !exists {
|
||||
// If a subresource exists without a parent, create a parent
|
||||
apiResourceList = append(apiResourceList, apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
apiResourceList = append(apiResourceList, apidiscoveryv2.APIResourceDiscovery{
|
||||
Resource: split[0],
|
||||
Scope: scope,
|
||||
// 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],
|
||||
Verbs: r.Verbs,
|
||||
// avoid nil panics in v0.26.0-v0.26.3 client-go clients
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resources []metav1.APIResource
|
||||
wantAPIResourceDiscovery []apidiscoveryv2beta1.APIResourceDiscovery
|
||||
wantAPIResourceDiscovery []apidiscoveryv2.APIResourceDiscovery
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
@@ -121,10 +121,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "pods",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Kind: "Pod",
|
||||
},
|
||||
@@ -146,10 +146,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "cronjobs",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
Version: "v1",
|
||||
@@ -182,10 +182,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "cronjobs",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
Version: "v1",
|
||||
@@ -193,7 +193,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
},
|
||||
ShortNames: []string{"cj"},
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
|
||||
Subresource: "status",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
@@ -245,10 +245,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "cronjobs",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
Version: "v1",
|
||||
@@ -256,7 +256,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
},
|
||||
ShortNames: []string{"cj"},
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
|
||||
Subresource: "status",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
@@ -267,7 +267,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
}},
|
||||
}, {
|
||||
Resource: "deployments",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
@@ -275,7 +275,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
},
|
||||
ShortNames: []string{"deploy"},
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
|
||||
Subresource: "status",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "apps",
|
||||
@@ -298,13 +298,13 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "cronjobs",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
// populated to avoid nil panics
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
|
||||
Subresource: "status",
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Group: "batch",
|
||||
@@ -327,13 +327,13 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "cronjobs",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
// populated to avoid nil panics
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{{
|
||||
Subresource: "status",
|
||||
// populated to avoid nil panics
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
@@ -364,7 +364,7 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
@@ -378,10 +378,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "nodes",
|
||||
Scope: apidiscoveryv2beta1.ScopeCluster,
|
||||
Scope: apidiscoveryv2.ScopeCluster,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Kind: "Node",
|
||||
},
|
||||
@@ -401,10 +401,10 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "nodes",
|
||||
Scope: apidiscoveryv2beta1.ScopeNamespace,
|
||||
Scope: apidiscoveryv2.ScopeNamespace,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Kind: "Node",
|
||||
},
|
||||
@@ -424,11 +424,11 @@ func TestConvertAPIResourceToDiscovery(t *testing.T) {
|
||||
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"},
|
||||
},
|
||||
},
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
wantAPIResourceDiscovery: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "nodes",
|
||||
SingularResource: "node",
|
||||
Scope: apidiscoveryv2beta1.ScopeCluster,
|
||||
Scope: apidiscoveryv2.ScopeCluster,
|
||||
ResponseKind: &metav1.GroupVersionKind{
|
||||
Kind: "Node",
|
||||
},
|
||||
|
@@ -29,7 +29,7 @@ import (
|
||||
systemd "github.com/coreos/go-systemd/v22/daemon"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -756,8 +756,8 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
if apiPrefix == APIGroupPrefix {
|
||||
s.AggregatedDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
apidiscoveryv2.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
Version: groupVersion.Version,
|
||||
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.
|
||||
s.AggregatedLegacyDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
apidiscoveryv2.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
Version: groupVersion.Version,
|
||||
Resources: discoveryAPIResources,
|
||||
},
|
||||
|
@@ -19,7 +19,8 @@ package discovery
|
||||
import (
|
||||
"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"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
@@ -154,3 +155,124 @@ func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubreso
|
||||
result.Verbs = in.Verbs
|
||||
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"
|
||||
|
||||
"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"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
@@ -961,3 +962,941 @@ func TestSplitGroupsAndResources(t *testing.T) {
|
||||
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/require"
|
||||
|
||||
apidiscovery "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscovery "k8s.io/api/apidiscovery/v2"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -643,7 +643,7 @@ func TestCachedDiscoveryClientAggregatedServerGroups(t *testing.T) {
|
||||
return
|
||||
}
|
||||
// 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.Write(output)
|
||||
}))
|
||||
|
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
apidiscovery "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscovery "k8s.io/api/apidiscovery/v2"
|
||||
errorsutil "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -1118,7 +1118,7 @@ func TestAggregatedMemCacheGroupsAndMaybeResources(t *testing.T) {
|
||||
output, err := json.Marshal(agg)
|
||||
require.NoError(t, err)
|
||||
// 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.Write(output)
|
||||
}))
|
||||
@@ -1161,6 +1161,7 @@ func TestAggregatedMemCacheGroupsAndMaybeResources(t *testing.T) {
|
||||
memClient.Invalidate()
|
||||
assert.False(t, memClient.Fresh())
|
||||
apiGroupList, _, _, err = memClient.GroupsAndMaybeResources()
|
||||
|
||||
require.NoError(t, err)
|
||||
// Test the expected groups are returned for the aggregated format.
|
||||
actualGroupNames = sets.NewString(groupNamesFromList(apiGroupList)...)
|
||||
|
@@ -33,7 +33,8 @@ import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"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
|
||||
// to ordering when comparing returned values in "Content-Type" header).
|
||||
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.
|
||||
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
|
||||
acceptDiscoveryFormats = AcceptV2 + "," + AcceptV2Beta1 + "," + AcceptV1
|
||||
)
|
||||
|
||||
// Aggregated discovery content-type GVK.
|
||||
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,
|
||||
// versions and resources.
|
||||
@@ -265,13 +268,20 @@ func (d *DiscoveryClient) downloadLegacy() (
|
||||
|
||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||
// Based on the content-type server responded with: aggregated or unaggregated.
|
||||
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
|
||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2GVK); isGVK {
|
||||
var aggregatedDiscovery apidiscoveryv2.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
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 {
|
||||
// Default is unaggregated discovery v1.
|
||||
var v metav1.APIVersions
|
||||
@@ -317,13 +327,20 @@ func (d *DiscoveryClient) downloadAPIs() (
|
||||
failedGVs := map[schema.GroupVersion]error{}
|
||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||
// Based on the content-type server responded with: aggregated or unaggregated.
|
||||
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
|
||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2GVK); isGVK {
|
||||
var aggregatedDiscovery apidiscoveryv2.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
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 {
|
||||
// Default is unaggregated discovery v1.
|
||||
err = json.Unmarshal(body, apiGroupList)
|
||||
|
@@ -32,7 +32,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
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"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -58,7 +59,8 @@ func TestGetServerVersion(t *testing.T) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -104,7 +106,8 @@ func TestGetServerGroupsWithV1Server(t *testing.T) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -144,7 +147,8 @@ func TestDiscoveryToleratesMissingCoreGroup(t *testing.T) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -180,7 +184,8 @@ func TestDiscoveryFailsWhenNonCoreGroupsMissing(t *testing.T) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -380,7 +385,8 @@ func TestGetServerResourcesForGroupVersion(t *testing.T) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
for _, test := range tests {
|
||||
@@ -1294,6 +1300,8 @@ func TestAggregatedServerGroups(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var output []byte
|
||||
var err error
|
||||
var agg *apidiscovery.APIGroupDiscoveryList
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
@@ -1304,13 +1312,14 @@ func TestAggregatedServerGroups(t *testing.T) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(agg)
|
||||
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.
|
||||
w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
|
||||
w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -1338,7 +1347,9 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
corev1 *apidiscovery.APIGroupDiscoveryList
|
||||
corev1DiscoveryBeta *apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
apis *apidiscovery.APIGroupDiscoveryList
|
||||
apisDiscoveryBeta *apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
expectedGroupNames []string
|
||||
expectedGroupVersions []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{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"v1", "apps/v1"},
|
||||
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{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"v1", "apps/v1", "apps/v2"},
|
||||
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{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"v1", "apps/v1"},
|
||||
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{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"v1", "apps/v1"},
|
||||
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{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"v1", "apps/v1", "batch/v1beta1"},
|
||||
expectedGVKs: []string{
|
||||
@@ -1780,8 +2171,9 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
|
||||
expectedFailedGVs: []string{"batch/v1"},
|
||||
},
|
||||
{
|
||||
name: "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
|
||||
corev1: &apidiscovery.APIGroupDiscoveryList{},
|
||||
name: "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
|
||||
corev1: &apidiscovery.APIGroupDiscoveryList{},
|
||||
corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{},
|
||||
apis: &apidiscovery.APIGroupDiscoveryList{
|
||||
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"},
|
||||
expectedGroupVersions: []string{"apps/v1", "batch/v1"},
|
||||
expectedGVKs: []string{
|
||||
@@ -1883,61 +2364,84 @@ 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 {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var agg *apidiscovery.APIGroupDiscoveryList
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
agg = test.corev1
|
||||
case "/apis":
|
||||
agg = test.apis
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
for _, accept := range serverAccepts {
|
||||
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
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
agg = test.corev1
|
||||
case "/apis":
|
||||
agg = test.apis
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err = json.Marshal(agg)
|
||||
require.NoError(t, err)
|
||||
} 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.
|
||||
w.Header().Set("Content-Type", accept+"; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
apiGroups, resources, err := client.ServerGroupsAndResources()
|
||||
if len(test.expectedFailedGVs) > 0 {
|
||||
require.Error(t, err)
|
||||
expectedFailedGVs := sets.NewString(test.expectedFailedGVs...)
|
||||
actualFailedGVs := sets.NewString(failedGroupVersions(err)...)
|
||||
assert.True(t, expectedFailedGVs.Equal(actualFailedGVs),
|
||||
"%s: Expected Failed GVs (%s), got (%s)", test.name, expectedFailedGVs, actualFailedGVs)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
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.
|
||||
w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
apiGroups, resources, err := client.ServerGroupsAndResources()
|
||||
if len(test.expectedFailedGVs) > 0 {
|
||||
require.Error(t, err)
|
||||
expectedFailedGVs := sets.NewString(test.expectedFailedGVs...)
|
||||
actualFailedGVs := sets.NewString(failedGroupVersions(err)...)
|
||||
assert.True(t, expectedFailedGVs.Equal(actualFailedGVs),
|
||||
"%s: Expected Failed GVs (%s), got (%s)", test.name, expectedFailedGVs, actualFailedGVs)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
// Test the expected groups are returned for the aggregated format.
|
||||
expectedGroupNames := sets.NewString(test.expectedGroupNames...)
|
||||
actualGroupNames := sets.NewString(groupNames(apiGroups)...)
|
||||
assert.True(t, expectedGroupNames.Equal(actualGroupNames),
|
||||
"%s: Expected GVKs (%s), got (%s)", test.name, expectedGroupNames.List(), actualGroupNames.List())
|
||||
// If the core V1 group is returned from /api, it should be the first group.
|
||||
if expectedGroupNames.Has("") {
|
||||
assert.True(t, len(apiGroups) > 0)
|
||||
actualFirstGroup := apiGroups[0]
|
||||
assert.True(t, len(actualFirstGroup.Versions) > 0)
|
||||
actualFirstGroupVersion := actualFirstGroup.Versions[0].GroupVersion
|
||||
assert.Equal(t, "v1", actualFirstGroupVersion)
|
||||
}
|
||||
// Test the expected group/versions are returned from the aggregated discovery.
|
||||
expectedGroupVersions := sets.NewString(test.expectedGroupVersions...)
|
||||
actualGroupVersions := sets.NewString(groupVersions(resources)...)
|
||||
assert.True(t, expectedGroupVersions.Equal(actualGroupVersions),
|
||||
"%s: Expected GroupVersions(%s), got (%s)", test.name, expectedGroupVersions.List(), actualGroupVersions.List())
|
||||
// Test the expected GVKs are returned from the aggregated discovery.
|
||||
expectedGVKs := sets.NewString(test.expectedGVKs...)
|
||||
actualGVKs := sets.NewString(groupVersionKinds(resources)...)
|
||||
assert.True(t, expectedGVKs.Equal(actualGVKs),
|
||||
"%s: Expected GVKs (%s), got (%s)", test.name, expectedGVKs.List(), actualGVKs.List())
|
||||
}
|
||||
// Test the expected groups are returned for the aggregated format.
|
||||
expectedGroupNames := sets.NewString(test.expectedGroupNames...)
|
||||
actualGroupNames := sets.NewString(groupNames(apiGroups)...)
|
||||
assert.True(t, expectedGroupNames.Equal(actualGroupNames),
|
||||
"%s: Expected GVKs (%s), got (%s)", test.name, expectedGroupNames.List(), actualGroupNames.List())
|
||||
// If the core V1 group is returned from /api, it should be the first group.
|
||||
if expectedGroupNames.Has("") {
|
||||
assert.True(t, len(apiGroups) > 0)
|
||||
actualFirstGroup := apiGroups[0]
|
||||
assert.True(t, len(actualFirstGroup.Versions) > 0)
|
||||
actualFirstGroupVersion := actualFirstGroup.Versions[0].GroupVersion
|
||||
assert.Equal(t, "v1", actualFirstGroupVersion)
|
||||
}
|
||||
// Test the expected group/versions are returned from the aggregated discovery.
|
||||
expectedGroupVersions := sets.NewString(test.expectedGroupVersions...)
|
||||
actualGroupVersions := sets.NewString(groupVersions(resources)...)
|
||||
assert.True(t, expectedGroupVersions.Equal(actualGroupVersions),
|
||||
"%s: Expected GroupVersions(%s), got (%s)", test.name, expectedGroupVersions.List(), actualGroupVersions.List())
|
||||
// Test the expected GVKs are returned from the aggregated discovery.
|
||||
expectedGVKs := sets.NewString(test.expectedGVKs...)
|
||||
actualGVKs := sets.NewString(groupVersionKinds(resources)...)
|
||||
assert.True(t, expectedGVKs.Equal(actualGVKs),
|
||||
"%s: Expected GVKs (%s), got (%s)", test.name, expectedGVKs.List(), actualGVKs.List())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2023,8 +2527,10 @@ func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
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 agg *apidiscovery.APIGroupDiscoveryList
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
agg = test.corev1
|
||||
@@ -2036,15 +2542,17 @@ func TestAggregatedServerGroupsAndResourcesWithErrors(t *testing.T) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(agg)
|
||||
output, err = json.Marshal(agg)
|
||||
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.
|
||||
w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
|
||||
w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
apiGroups, resources, err := client.ServerGroupsAndResources()
|
||||
if test.expectedErr {
|
||||
@@ -2635,6 +3143,8 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var output []byte
|
||||
var err error
|
||||
var agg *apidiscovery.APIGroupDiscoveryList
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
@@ -2645,13 +3155,14 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(agg)
|
||||
output, err = json.Marshal(agg)
|
||||
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.
|
||||
w.Header().Set("Content-Type", AcceptV2Beta1+"; charset=utf-8")
|
||||
w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
_, err = w.Write(output)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
@@ -2674,7 +3185,7 @@ func TestAggregatedServerPreferredResources(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 {
|
||||
contentType string
|
||||
gvk schema.GroupVersionKind
|
||||
@@ -2682,59 +3193,59 @@ func TestDiscoveryContentTypeVersion(t *testing.T) {
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList",
|
||||
gvk: v2beta1,
|
||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList",
|
||||
gvk: v2,
|
||||
match: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
// content-type parameters are not in correct order, but comparison ignores order.
|
||||
contentType: "application/json; v=v2beta1;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
|
||||
gvk: v2beta1,
|
||||
contentType: "application/json; v=v2;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
|
||||
gvk: v2,
|
||||
match: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
// content-type parameters are not in correct order, but comparison ignores order.
|
||||
contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2beta1",
|
||||
gvk: v2beta1,
|
||||
contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2",
|
||||
gvk: v2,
|
||||
match: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
// Ignores extra parameter "charset=utf-8"
|
||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList;charset=utf-8",
|
||||
gvk: v2beta1,
|
||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList;charset=utf-8",
|
||||
gvk: v2,
|
||||
match: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
contentType: "application/json",
|
||||
gvk: v2beta1,
|
||||
gvk: v2,
|
||||
match: false,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
gvk: v2beta1,
|
||||
gvk: v2,
|
||||
match: false,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
contentType: "text/json",
|
||||
gvk: v2beta1,
|
||||
gvk: v2,
|
||||
match: false,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
contentType: "text/html",
|
||||
gvk: v2beta1,
|
||||
gvk: v2,
|
||||
match: false,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
contentType: "",
|
||||
gvk: v2beta1,
|
||||
gvk: v2,
|
||||
match: false,
|
||||
expectErr: true,
|
||||
},
|
||||
|
@@ -23,10 +23,15 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscoveryv2conversion "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"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/wait"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
@@ -34,11 +39,11 @@ import (
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
||||
"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"}
|
||||
@@ -54,6 +59,12 @@ var v2Beta1GVK = schema.GroupVersionKind{
|
||||
Kind: "APIGroupDiscoveryList",
|
||||
}
|
||||
|
||||
var v2GVK = schema.GroupVersionKind{
|
||||
Group: "apidiscovery.k8s.io",
|
||||
Version: "v2",
|
||||
Kind: "APIGroupDiscoveryList",
|
||||
}
|
||||
|
||||
// Given a list of APIServices and proxyHandlers for contacting them,
|
||||
// DiscoveryManager caches a list of discovery documents for each server
|
||||
|
||||
@@ -96,6 +107,9 @@ type discoveryManager struct {
|
||||
|
||||
// Merged handler which stores all known groupversions
|
||||
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
|
||||
@@ -129,7 +143,7 @@ func newServiceKey(service apiregistrationv1.ServiceReference) serviceKey {
|
||||
type cachedResult struct {
|
||||
// Currently cached discovery document for this service
|
||||
// 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 string
|
||||
@@ -172,11 +186,19 @@ var _ DiscoveryAggregationController = &discoveryManager{}
|
||||
func NewDiscoveryManager(
|
||||
target discoveryendpoint.ResourceManager,
|
||||
) 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{
|
||||
mergedDiscoveryHandler: target,
|
||||
apiServices: make(map[string]groupVersionInfo),
|
||||
cachedResults: make(map[serviceKey]cachedResult),
|
||||
dirtyAPIServiceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "discovery-manager"),
|
||||
codecs: codecs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +236,7 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
|
||||
Path: req.URL.Path,
|
||||
IsResourceRequest: false,
|
||||
}))
|
||||
req.Header.Add("Accept", discovery.AcceptV2Beta1)
|
||||
req.Header.Add("Accept", discovery.AcceptV2+","+discovery.AcceptV2Beta1)
|
||||
|
||||
if exists && len(cached.etag) > 0 {
|
||||
req.Header.Add("If-None-Match", cached.etag)
|
||||
@@ -228,6 +250,8 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
|
||||
handler.ServeHTTP(writer, req)
|
||||
|
||||
isV2Beta1GVK, _ := discovery.ContentTypeIsGVK(writer.Header().Get("Content-Type"), v2Beta1GVK)
|
||||
isV2GVK, _ := discovery.ContentTypeIsGVK(writer.Header().Get("Content-Type"), v2GVK)
|
||||
|
||||
switch {
|
||||
case writer.respCode == http.StatusNotModified:
|
||||
// Keep old entry, update timestamp
|
||||
@@ -242,16 +266,16 @@ func (dm *discoveryManager) fetchFreshDiscoveryForService(gv metav1.GroupVersion
|
||||
case writer.respCode == http.StatusServiceUnavailable:
|
||||
return nil, fmt.Errorf("service %s returned non-success response code: %v",
|
||||
info.service.String(), writer.respCode)
|
||||
case writer.respCode == http.StatusOK && isV2Beta1GVK:
|
||||
parsed := &apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), writer.data, parsed); err != nil {
|
||||
case writer.respCode == http.StatusOK && (isV2GVK || isV2Beta1GVK):
|
||||
parsed := &apidiscoveryv2.APIGroupDiscoveryList{}
|
||||
if err := runtime.DecodeInto(dm.codecs.UniversalDecoder(), writer.data, parsed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.V(3).Infof("DiscoveryManager: Successfully downloaded discovery for %s", info.service.String())
|
||||
|
||||
// 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 _, v := range g.Versions {
|
||||
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())
|
||||
|
||||
discoMap := map[metav1.GroupVersion]apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
discoMap := map[metav1.GroupVersion]apidiscoveryv2.APIVersionDiscovery{
|
||||
// Convert old-style APIGroupList to new information
|
||||
gv: {
|
||||
Version: gv.Version,
|
||||
@@ -366,7 +390,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
|
||||
// Lookup last cached result for this apiservice's service.
|
||||
cached, err := dm.fetchFreshDiscoveryForService(mgv, info)
|
||||
|
||||
var entry apidiscoveryv2beta1.APIVersionDiscovery
|
||||
var entry apidiscoveryv2.APIVersionDiscovery
|
||||
|
||||
// Extract the APIService's specific resource information from the
|
||||
// groupversion
|
||||
@@ -377,7 +401,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
|
||||
// Just use empty GV to mark that GV exists, but no resources.
|
||||
// Also mark that it is stale to indicate the fetch failed
|
||||
// TODO: Maybe also stick in a status for the version the error?
|
||||
entry = apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
entry = apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: gv.Version,
|
||||
}
|
||||
} else {
|
||||
@@ -388,7 +412,7 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
|
||||
} else {
|
||||
// Successfully fetched discovery information from the server, but
|
||||
// the server did not include this groupversion?
|
||||
entry = apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
entry = apidiscoveryv2.APIVersionDiscovery{
|
||||
Version: gv.Version,
|
||||
}
|
||||
}
|
||||
@@ -397,9 +421,9 @@ func (dm *discoveryManager) syncAPIService(apiServiceName string) error {
|
||||
// The entry's staleness depends upon if `fetchFreshDiscoveryForService`
|
||||
// returned an error or not.
|
||||
if err == nil {
|
||||
entry.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessCurrent
|
||||
entry.Freshness = apidiscoveryv2.DiscoveryFreshnessCurrent
|
||||
} else {
|
||||
entry.Freshness = apidiscoveryv2beta1.DiscoveryFreshnessStale
|
||||
entry.Freshness = apidiscoveryv2.DiscoveryFreshnessStale
|
||||
}
|
||||
|
||||
dm.mergedDiscoveryHandler.AddGroupVersion(gv.Group, entry)
|
||||
|
@@ -33,10 +33,12 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
apidiscoveryv2scheme "k8s.io/apiserver/pkg/apis/apidiscovery/v2"
|
||||
"k8s.io/apiserver/pkg/endpoints"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
@@ -68,31 +70,31 @@ func TestBasic(t *testing.T) {
|
||||
service3 := discoveryendpoint.NewResourceManager("apis")
|
||||
apiGroup1 := fuzzAPIGroups(2, 5, 25)
|
||||
apiGroup2 := fuzzAPIGroups(2, 5, 50)
|
||||
apiGroup3 := apidiscoveryv2beta1.APIGroupDiscoveryList{Items: []apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
apiGroup3 := apidiscoveryv2.APIGroupDiscoveryList{Items: []apidiscoveryv2.APIGroupDiscovery{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "weird.example.com"},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Freshness: "Current",
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "parent-missing-kind",
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{Subresource: "subresource-missing-kind"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Resource: "parent-empty-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Resource: "parent-with-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{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"},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Freshness: "Current",
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "parent-missing-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{}, // defaulted by aggregator
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{Subresource: "subresource-missing-kind", ResponseKind: &metav1.GroupVersionKind{}}, // defaulted by aggregator
|
||||
},
|
||||
},
|
||||
{
|
||||
Resource: "parent-empty-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{Subresource: "subresource-empty-kind", ResponseKind: &metav1.GroupVersionKind{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Resource: "parent-with-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{Kind: "ParentWithKind"},
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{Subresource: "subresource-with-kind", ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithKind"}},
|
||||
},
|
||||
},
|
||||
@@ -217,7 +219,7 @@ func TestBasic(t *testing.T) {
|
||||
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()
|
||||
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))
|
||||
@@ -281,10 +283,10 @@ func TestInitialRunHasAllAPIServices(t *testing.T) {
|
||||
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"},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Freshness: "Stale",
|
||||
@@ -348,6 +350,71 @@ func TestServiceGC(t *testing.T) {
|
||||
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
|
||||
// APIService has been marked as dirty
|
||||
func TestDirty(t *testing.T) {
|
||||
@@ -642,34 +709,34 @@ func TestLegacyFallbackNoCache(t *testing.T) {
|
||||
// includes the legacy resources
|
||||
_, _, doc := fetchPath(aggregatedResourceManager, "")
|
||||
|
||||
mustConvert := func(r []metav1.APIResource) []apidiscoveryv2beta1.APIResourceDiscovery {
|
||||
mustConvert := func(r []metav1.APIResource) []apidiscoveryv2.APIResourceDiscovery {
|
||||
converted, err := endpoints.ConvertGroupVersionIntoToDiscovery(r)
|
||||
require.NoError(t, err)
|
||||
return converted
|
||||
}
|
||||
expectAggregatedDiscovery := []apidiscoveryv2beta1.APIGroupDiscovery{{
|
||||
expectAggregatedDiscovery := []apidiscoveryv2.APIGroupDiscovery{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stable.example.com",
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Resources: mustConvert([]metav1.APIResource{resources["v1"]}),
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
},
|
||||
{
|
||||
Version: "v1beta1",
|
||||
Resources: mustConvert([]metav1.APIResource{resources["v1beta1"]}),
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
},
|
||||
{
|
||||
Version: "v2alpha1",
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "parent-without-kind",
|
||||
ResponseKind: &metav1.GroupVersionKind{}, // defaulted
|
||||
Scope: "Cluster",
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{
|
||||
Subresource: "subresource",
|
||||
ResponseKind: &metav1.GroupVersionKind{Kind: "Subresource"},
|
||||
@@ -684,7 +751,7 @@ func TestLegacyFallbackNoCache(t *testing.T) {
|
||||
Resource: "missing-parent",
|
||||
ResponseKind: &metav1.GroupVersionKind{}, // defaulted
|
||||
Scope: "Cluster",
|
||||
Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{
|
||||
Subresources: []apidiscoveryv2.APISubresourceDiscovery{
|
||||
{
|
||||
Subresource: "subresource-without-parent",
|
||||
ResponseKind: &metav1.GroupVersionKind{Kind: "SubresourceWithoutParent"},
|
||||
@@ -692,12 +759,12 @@ func TestLegacyFallbackNoCache(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
},
|
||||
{
|
||||
Version: "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})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
require.Equal(t, []apidiscoveryv2.APIGroupDiscovery{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: resource.Group,
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: resource.Version,
|
||||
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
|
||||
// lists the APIService group version as Stale.
|
||||
_, _, doc := fetchPath(aggregatedResourceManager, "")
|
||||
require.Equal(t, []apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
require.Equal(t, []apidiscoveryv2.APIGroupDiscovery{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stable.example.com",
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
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
|
||||
func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2beta1.APIGroupDiscoveryList {
|
||||
func fuzzAPIGroups(atLeastNumGroups, maxNumGroups int, seed int64) apidiscoveryv2.APIGroupDiscoveryList {
|
||||
fuzzer := fuzz.NewWithSeed(seed)
|
||||
fuzzer.NumElements(atLeastNumGroups, maxNumGroups)
|
||||
fuzzer.NilChance(0)
|
||||
fuzzer.Funcs(func(o *apidiscoveryv2beta1.APIGroupDiscovery, c fuzz.Continue) {
|
||||
fuzzer.Funcs(func(o *apidiscoveryv2.APIGroupDiscovery, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(o)
|
||||
|
||||
// The ResourceManager will just not serve the group if its versions
|
||||
// list is empty
|
||||
atLeastOne := apidiscoveryv2beta1.APIVersionDiscovery{}
|
||||
atLeastOne := apidiscoveryv2.APIVersionDiscovery{}
|
||||
c.Fuzz(&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)
|
||||
|
||||
return apidiscoveryv2beta1.APIGroupDiscoveryList{
|
||||
return apidiscoveryv2.APIGroupDiscoveryList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "APIGroupDiscoveryList",
|
||||
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
|
||||
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
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/apis", nil)
|
||||
|
||||
// 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 != "" {
|
||||
// Quote provided etag if unquoted
|
||||
@@ -992,9 +1059,9 @@ func fetchPath(handler http.Handler, etag string) (*http.Response, []byte, *apid
|
||||
handler.ServeHTTP(w, req)
|
||||
|
||||
bytes := w.Body.Bytes()
|
||||
var decoded *apidiscoveryv2beta1.APIGroupDiscoveryList
|
||||
var decoded *apidiscoveryv2.APIGroupDiscoveryList
|
||||
if len(bytes) > 0 {
|
||||
decoded = &apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
decoded = &apidiscoveryv2.APIGroupDiscoveryList{}
|
||||
runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), bytes, decoded)
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"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
|
||||
@@ -156,7 +156,7 @@ var _ = SIGDescribe("AggregatedDiscovery", func() {
|
||||
framework.Failf("Failed to get raw aggregated discovery document")
|
||||
}
|
||||
|
||||
groupList := apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
groupList := apidiscoveryv2.APIGroupDiscoveryList{}
|
||||
err = json.Unmarshal(d, &groupList)
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
groupListLegacy := apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
groupListLegacy := apidiscoveryv2.APIGroupDiscoveryList{}
|
||||
err = json.Unmarshal(d2, &groupListLegacy)
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
groupList := apidiscoveryv2beta1.APIGroupDiscoveryList{}
|
||||
groupList := apidiscoveryv2.APIGroupDiscoveryList{}
|
||||
err = json.Unmarshal(d, &groupList)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to parse discovery: %v", err)
|
||||
@@ -392,7 +392,7 @@ func isGVPresent(gvs *metav1.APIGroupList, gv schema.GroupVersion) bool {
|
||||
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 {
|
||||
if gvr.Group == group.Name {
|
||||
for _, version := range group.Versions {
|
||||
|
@@ -28,7 +28,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"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"
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@@ -79,14 +79,14 @@ var (
|
||||
codecs = runtimeserializer.NewCodecFactory(scheme)
|
||||
serialize runtime.NegotiatedSerializer
|
||||
|
||||
basicTestGroup = apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
basicTestGroup = apidiscoveryv2.APIGroupDiscovery{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stable.example.com",
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "jobs",
|
||||
Verbs: []string{"create", "list", "watch", "delete"},
|
||||
@@ -94,19 +94,19 @@ var (
|
||||
Categories: []string{"all"},
|
||||
},
|
||||
},
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
basicTestGroupWithFixup = apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
basicTestGroupWithFixup = apidiscoveryv2.APIGroupDiscovery{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stable.example.com",
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
Version: "v1",
|
||||
Resources: []apidiscoveryv2beta1.APIResourceDiscovery{
|
||||
Resources: []apidiscoveryv2.APIResourceDiscovery{
|
||||
{
|
||||
Resource: "jobs",
|
||||
Verbs: []string{"create", "list", "watch", "delete"},
|
||||
@@ -116,19 +116,19 @@ var (
|
||||
ResponseKind: &metav1.GroupVersionKind{},
|
||||
},
|
||||
},
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Freshness: apidiscoveryv2.DiscoveryFreshnessCurrent,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
basicTestGroupStale = apidiscoveryv2beta1.APIGroupDiscovery{
|
||||
basicTestGroupStale = apidiscoveryv2.APIGroupDiscovery{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stable.example.com",
|
||||
},
|
||||
Versions: []apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Versions: []apidiscoveryv2.APIVersionDiscovery{
|
||||
{
|
||||
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
|
||||
resourceManager := discoveryendpoint.NewResourceManager("apis")
|
||||
resourceManager.SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery{basicTestGroup})
|
||||
resourceManager.SetGroups([]apidiscoveryv2.APIGroupDiscovery{basicTestGroup})
|
||||
|
||||
apiServiceWaitCh := make(chan struct{})
|
||||
|
||||
@@ -290,7 +290,7 @@ func TestAggregatedAPIServiceDiscovery(t *testing.T) {
|
||||
|
||||
// Create a resource manager whichs serves our GroupVersion
|
||||
resourceManager := discoveryendpoint.NewResourceManager("apis")
|
||||
resourceManager.SetGroups([]apidiscoveryv2beta1.APIGroupDiscovery{basicTestGroup})
|
||||
resourceManager.SetGroups([]apidiscoveryv2.APIGroupDiscovery{basicTestGroup})
|
||||
|
||||
// Install our ResourceManager as an Aggregated APIService to the
|
||||
// test server
|
||||
@@ -371,7 +371,7 @@ func runTestCases(t *testing.T, cases []testCase) {
|
||||
})
|
||||
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)
|
||||
return reflect.DeepEqual(result, originalV2)
|
||||
})
|
||||
@@ -393,6 +393,7 @@ func TestCRD(t *testing.T) {
|
||||
applyCRD(makeCRDSpec(stableGroup, "Foo", false, []string{"v1", "v1alpha1", "v1beta1", "v2"})),
|
||||
waitForGroupVersionsV1([]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"})),
|
||||
waitForGroupVersionsV1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
|
||||
waitForGroupVersionsV2([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
|
||||
waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1, stableV1alpha1, stableV1beta1, stableV2}),
|
||||
deleteObject{
|
||||
GroupVersionResource: metav1.GroupVersionResource(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions")),
|
||||
Name: "foos.stable.example.com",
|
||||
@@ -469,6 +471,7 @@ func TestCRD(t *testing.T) {
|
||||
// Wait for GV to appear in both discovery documents
|
||||
waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
|
||||
applyAPIService(
|
||||
apiregistrationv1.APIServiceSpec{
|
||||
@@ -487,11 +490,13 @@ func TestCRD(t *testing.T) {
|
||||
// We should now have stable v1 available
|
||||
waitForGroupVersionsV1([]metav1.GroupVersion{stableV1}),
|
||||
waitForGroupVersionsV2([]metav1.GroupVersion{stableV1}),
|
||||
waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1}),
|
||||
|
||||
// The CRD group-versions not served by the aggregated
|
||||
// apiservice should still be availablee
|
||||
waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
|
||||
// Remove API service. Show we have switched to CRD
|
||||
deleteObject{
|
||||
@@ -502,9 +507,11 @@ func TestCRD(t *testing.T) {
|
||||
// Show that we still have stable v1 since it is in the CRD
|
||||
waitForGroupVersionsV1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
waitForGroupVersionsV2Beta1([]metav1.GroupVersion{stableV2, stableV1alpha1}),
|
||||
|
||||
waitForAbsentGroupVersionsV1([]metav1.GroupVersion{stableV1}),
|
||||
waitForAbsentGroupVersionsV2([]metav1.GroupVersion{stableV1}),
|
||||
waitForAbsentGroupVersionsV2Beta1([]metav1.GroupVersion{stableV1}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -635,9 +642,9 @@ func TestFreshness(t *testing.T) {
|
||||
}
|
||||
|
||||
switch entry.Freshness {
|
||||
case apidiscoveryv2beta1.DiscoveryFreshnessCurrent:
|
||||
case apidiscoveryv2.DiscoveryFreshnessCurrent:
|
||||
// Skip
|
||||
case apidiscoveryv2beta1.DiscoveryFreshnessStale:
|
||||
case apidiscoveryv2.DiscoveryFreshnessStale:
|
||||
staleGVs = append(staleGVs, targetGv)
|
||||
default:
|
||||
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,
|
||||
// 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)()
|
||||
|
||||
makeApiServiceSpec := func(gv metav1.GroupVersion, groupPriorityMin, versionPriority int) apiregistrationv1.APIServiceSpec {
|
||||
|
@@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
|
||||
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -43,7 +44,8 @@ import (
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
@@ -93,9 +95,15 @@ type waitForAbsentGroupVersionsV1 []metav1.GroupVersion
|
||||
// Wait for groupversions to appear in v2 discovery
|
||||
type waitForGroupVersionsV2 []metav1.GroupVersion
|
||||
|
||||
// Wait for groupversions to appear in v2beta1 discovery
|
||||
type waitForGroupVersionsV2Beta1 []metav1.GroupVersion
|
||||
|
||||
// Wait for groupversions to disappear from v2 discovery
|
||||
type waitForAbsentGroupVersionsV2 []metav1.GroupVersion
|
||||
|
||||
// Wait for groupversions to disappear from v2beta1 discovery
|
||||
type waitForAbsentGroupVersionsV2Beta1 []metav1.GroupVersion
|
||||
|
||||
type waitForStaleGroupVersionsV2 []metav1.GroupVersion
|
||||
type waitForFreshGroupVersionsV2 []metav1.GroupVersion
|
||||
|
||||
@@ -144,10 +152,11 @@ func (a applyAPIService) Cleanup(ctx context.Context, client testClient) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = wait.PollWithContext(
|
||||
err = wait.PollUntilContextTimeout(
|
||||
ctx,
|
||||
250*time.Millisecond,
|
||||
maxTimeout,
|
||||
true,
|
||||
func(ctx context.Context) (done bool, err error) {
|
||||
_, err = client.ApiregistrationV1().APIServices().Get(ctx, name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
@@ -212,10 +221,11 @@ func (a applyCRD) Cleanup(ctx context.Context, client testClient) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = wait.PollWithContext(
|
||||
err = wait.PollUntilContextTimeout(
|
||||
ctx,
|
||||
250*time.Millisecond,
|
||||
maxTimeout,
|
||||
true,
|
||||
func(ctx context.Context) (done bool, err error) {
|
||||
_, err = client.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, name, metav1.GetOptions{})
|
||||
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 {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -265,9 +275,9 @@ func (w waitForStaleGroupVersionsV2) Do(ctx context.Context, client testClient)
|
||||
}
|
||||
|
||||
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 {
|
||||
if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2beta1.DiscoveryFreshnessCurrent {
|
||||
if info := FindGroupVersionV2(result, gv); info == nil || info.Freshness != apidiscoveryv2.DiscoveryFreshnessCurrent {
|
||||
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 {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, gv := range w {
|
||||
if FindGroupVersionV2(result, gv) == nil {
|
||||
return false
|
||||
@@ -298,8 +308,25 @@ func (w waitForGroupVersionsV2) Do(ctx context.Context, client testClient) error
|
||||
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 {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, gv := range w {
|
||||
if FindGroupVersionV2(result, gv) != nil {
|
||||
return false
|
||||
@@ -315,6 +342,23 @@ func (w waitForAbsentGroupVersionsV2) Do(ctx context.Context, client testClient)
|
||||
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 {
|
||||
err := WaitForV1GroupsWithCondition(ctx, client, func(result metav1.APIGroupList) bool {
|
||||
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 {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, gvr := range w {
|
||||
if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
|
||||
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 {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
err := WaitForResultWithCondition(ctx, client, func(result apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, gvr := range w {
|
||||
if info := FindGroupVersionV2(result, metav1.GroupVersion{Group: gvr.Group, Version: gvr.Version}); info == nil {
|
||||
return false
|
||||
@@ -484,7 +528,7 @@ func (i inlineAction) Do(ctx context.Context, client testClient) error {
|
||||
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.
|
||||
Discovery().
|
||||
RESTClient().
|
||||
@@ -494,6 +538,29 @@ func FetchV2Discovery(ctx context.Context, client testClient) (apidiscoveryv2bet
|
||||
Do(ctx).
|
||||
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 {
|
||||
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 {
|
||||
return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, searchGroup := range groups {
|
||||
for _, docGroup := range groupList.Items {
|
||||
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 {
|
||||
return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2beta1.APIGroupDiscoveryList) bool {
|
||||
func WaitForGroups(ctx context.Context, client testClient, groups ...apidiscoveryv2.APIGroupDiscovery) error {
|
||||
return WaitForResultWithCondition(ctx, client, func(groupList apidiscoveryv2.APIGroupDiscoveryList) bool {
|
||||
for _, searchGroup := range groups {
|
||||
found := false
|
||||
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.
|
||||
// Check to see if it contains our service within a reasonable amount of time
|
||||
return wait.PollWithContext(
|
||||
return wait.PollUntilContextTimeout(
|
||||
ctx,
|
||||
250*time.Millisecond,
|
||||
maxTimeout,
|
||||
true,
|
||||
func(ctx context.Context) (done bool, err error) {
|
||||
groupList, err := FetchV2Discovery(ctx, client)
|
||||
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 {
|
||||
// Keep repeatedly fetching document from aggregator.
|
||||
// Check to see if it contains our service within a reasonable amount of time
|
||||
return wait.PollWithContext(
|
||||
return wait.PollUntilContextTimeout(
|
||||
ctx,
|
||||
250*time.Millisecond,
|
||||
maxTimeout,
|
||||
true,
|
||||
func(ctx context.Context) (done bool, err error) {
|
||||
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 {
|
||||
// Keep repeatedly fetching document from aggregator.
|
||||
// Check to see if it contains our service within a reasonable amount of time
|
||||
return wait.PollWithContext(
|
||||
return wait.PollUntilContextTimeout(
|
||||
ctx,
|
||||
250*time.Millisecond,
|
||||
maxTimeout,
|
||||
true,
|
||||
func(ctx context.Context) (done bool, err error) {
|
||||
resourceList, err := FetchV1DiscoveryResource(ctx, client, gv)
|
||||
|
||||
@@ -697,7 +789,23 @@ func FindGroupVersionV1(discovery metav1.APIGroupList, gv metav1.GroupVersion) b
|
||||
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 {
|
||||
if documentGroup.Name != gv.Group {
|
||||
continue
|
||||
|
Reference in New Issue
Block a user