Remove aggregated discovery v2beta1 client-side references

Kubernetes-commit: 6d48f50dcf41c11c72f511ca51b5aa8b580782af
This commit is contained in:
Jefftree
2026-04-08 10:44:27 -04:00
committed by Kubernetes Publisher
parent 0a31f6e5eb
commit d59f4e8465
4 changed files with 66 additions and 1641 deletions

View File

@@ -20,7 +20,6 @@ import (
"fmt"
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"
)
@@ -155,124 +154,3 @@ 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.35. 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
}

View File

@@ -21,7 +21,6 @@ import (
"github.com/stretchr/testify/assert"
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"
)
@@ -962,941 +961,3 @@ 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)
}
}

View File

@@ -33,7 +33,6 @@ import (
"google.golang.org/protobuf/proto"
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"
@@ -60,18 +59,16 @@ const (
defaultBurst = 300
AcceptV1 = runtime.ContentTypeJSON
// Aggregated discovery content-type (v2beta1). NOTE: content-type parameters
// Aggregated discovery content-type. NOTE: content-type parameters
// 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"
AcceptV2NoPeer = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList;profile=nopeer"
// Prioritize aggregated discovery by placing first in the order of discovery accept types.
acceptDiscoveryFormats = AcceptV2 + "," + AcceptV2Beta1 + "," + AcceptV1
acceptDiscoveryFormats = AcceptV2 + "," + 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,
@@ -277,13 +274,6 @@ func (d *DiscoveryClient) downloadLegacy() (
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
@@ -333,13 +323,6 @@ func (d *DiscoveryClient) downloadAPIs() (
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)
@@ -368,9 +351,9 @@ func selectDiscoveryAcceptHeader(useLegacy, nopeer bool) string {
// content-type parameters, as well as parameters added by
// intermediaries such as proxies or gateways. Examples:
//
// ("application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
// ("application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
// ("application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io;charset=utf-8", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
// ("application/json; g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList", {apidiscovery.k8s.io, v2, APIGroupDiscoveryList}) = (true, nil)
// ("application/json; as=APIGroupDiscoveryList;v=v2;g=apidiscovery.k8s.io", {apidiscovery.k8s.io, v2, APIGroupDiscoveryList}) = (true, nil)
// ("application/json; as=APIGroupDiscoveryList;v=v2;g=apidiscovery.k8s.io;charset=utf-8", {apidiscovery.k8s.io, v2, APIGroupDiscoveryList}) = (true, nil)
// ("application/json", any GVK) = (false, nil)
// ("application/json; charset=UTF-8", any GVK) = (false, nil)
// ("malformed content type string", any GVK) = (false, error)

View File

@@ -33,7 +33,6 @@ import (
golangproto "google.golang.org/protobuf/proto"
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"
@@ -1363,9 +1362,7 @@ 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
@@ -1395,28 +1392,6 @@ 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{
{
@@ -1442,31 +1417,6 @@ 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{
@@ -1498,28 +1448,6 @@ 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{
{
@@ -1559,45 +1487,6 @@ 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{
@@ -1630,28 +1519,6 @@ 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{
{
@@ -1692,46 +1559,6 @@ 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{
@@ -1773,37 +1600,6 @@ 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{
{
@@ -1863,65 +1659,6 @@ 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{
@@ -1965,37 +1702,6 @@ 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{
{
@@ -2085,95 +1791,6 @@ 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{
@@ -2187,9 +1804,8 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
expectedFailedGVs: []string{"batch/v1"},
},
{
name: "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
corev1: &apidiscovery.APIGroupDiscoveryList{},
corev1DiscoveryBeta: &apidiscoveryv2beta1.APIGroupDiscoveryList{},
name: "Aggregated discovery: /api returns nothing, 2 groups/2 resources at /apis",
corev1: &apidiscovery.APIGroupDiscoveryList{},
apis: &apidiscovery.APIGroupDiscoveryList{
Items: []apidiscovery.APIGroupDiscovery{
{
@@ -2279,95 +1895,6 @@ 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{
@@ -2380,92 +1907,68 @@ func TestAggregatedServerGroupsAndResources(t *testing.T) {
},
}
// Ensure that client can parse both V2Beta1 and V2 types from server
serverAccepts := []string{AcceptV2Beta1, AcceptV2}
for _, test := range tests {
for _, 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)
if err != nil {
t.Errorf("unexpected error %v", err)
return
}
} 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)
if err != nil {
t.Errorf("unexpected error %v", err)
return
}
}
// 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)
if err != nil {
t.Errorf("unexpected error %v", err)
}
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
}
output, err := json.Marshal(agg)
if err != nil {
t.Errorf("unexpected error %v", err)
return
}
// Content-Type is "aggregated" discovery format. Add extra parameter
// to ensure we are resilient to these extra parameters.
w.Header().Set("Content-Type", AcceptV2+"; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, err = w.Write(output)
if err != nil {
t.Errorf("unexpected error %v", 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)
}
// 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.NotEmpty(t, apiGroups)
actualFirstGroup := apiGroups[0]
assert.NotEmpty(t, actualFirstGroup.Versions)
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())
}))
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.NotEmpty(t, apiGroups)
actualFirstGroup := apiGroups[0]
assert.NotEmpty(t, actualFirstGroup.Versions)
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())
}
}