mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-24 14:12:18 +00:00
Fallback to legacy discovery on a wider range of conditions in aggregator
Kubernetes-commit: 57b27fd3cd11cb5f2515c7ac5f67f612998fb368
This commit is contained in:
parent
f28f485cb4
commit
c4ed5da76e
@ -68,6 +68,9 @@ const (
|
|||||||
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
|
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Aggregated discovery content-type GVK.
|
||||||
|
var v2Beta1GVK = schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
|
||||||
|
|
||||||
// DiscoveryInterface holds the methods that discover server-supported API groups,
|
// DiscoveryInterface holds the methods that discover server-supported API groups,
|
||||||
// versions and resources.
|
// versions and resources.
|
||||||
type DiscoveryInterface interface {
|
type DiscoveryInterface interface {
|
||||||
@ -261,16 +264,15 @@ func (d *DiscoveryClient) downloadLegacy() (
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||||
// Switch on content-type server responded with: aggregated or unaggregated.
|
// Based on the content-type server responded with: aggregated or unaggregated.
|
||||||
switch {
|
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
|
||||||
case isV2Beta1ContentType(responseContentType):
|
|
||||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
||||||
default:
|
} else {
|
||||||
// Default is unaggregated discovery v1.
|
// Default is unaggregated discovery v1.
|
||||||
var v metav1.APIVersions
|
var v metav1.APIVersions
|
||||||
err = json.Unmarshal(body, &v)
|
err = json.Unmarshal(body, &v)
|
||||||
@ -314,16 +316,15 @@ func (d *DiscoveryClient) downloadAPIs() (
|
|||||||
apiGroupList := &metav1.APIGroupList{}
|
apiGroupList := &metav1.APIGroupList{}
|
||||||
failedGVs := map[schema.GroupVersion]error{}
|
failedGVs := map[schema.GroupVersion]error{}
|
||||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||||
// Switch on content-type server responded with: aggregated or unaggregated.
|
// Based on the content-type server responded with: aggregated or unaggregated.
|
||||||
switch {
|
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
|
||||||
case isV2Beta1ContentType(responseContentType):
|
|
||||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
||||||
default:
|
} else {
|
||||||
// Default is unaggregated discovery v1.
|
// Default is unaggregated discovery v1.
|
||||||
err = json.Unmarshal(body, apiGroupList)
|
err = json.Unmarshal(body, apiGroupList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -334,26 +335,29 @@ func (d *DiscoveryClient) downloadAPIs() (
|
|||||||
return apiGroupList, resourcesByGV, failedGVs, nil
|
return apiGroupList, resourcesByGV, failedGVs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isV2Beta1ContentType checks of the content-type string is both
|
// ContentTypeIsGVK checks of the content-type string is both
|
||||||
// "application/json" and contains the v2beta1 content-type params.
|
// "application/json" and matches the provided GVK. An error
|
||||||
|
// is returned if the content type string is malformed.
|
||||||
// NOTE: This function is resilient to the ordering of the
|
// NOTE: This function is resilient to the ordering of the
|
||||||
// content-type parameters, as well as parameters added by
|
// content-type parameters, as well as parameters added by
|
||||||
// intermediaries such as proxies or gateways. Examples:
|
// intermediaries such as proxies or gateways. Examples:
|
||||||
//
|
//
|
||||||
// "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList" = true
|
// ("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" = true
|
// ("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" = true
|
// ("application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io;charset=utf-8", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
|
||||||
// "application/json" = false
|
// ("application/json", any GVK) = (false, nil)
|
||||||
// "application/json; charset=UTF-8" = false
|
// ("application/json; charset=UTF-8", any GVK) = (false, nil)
|
||||||
func isV2Beta1ContentType(contentType string) bool {
|
// ("malformed content type string", any GVK) = (false, error)
|
||||||
|
func ContentTypeIsGVK(contentType string, gvk schema.GroupVersionKind) (bool, error) {
|
||||||
base, params, err := mime.ParseMediaType(contentType)
|
base, params, err := mime.ParseMediaType(contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false, err
|
||||||
}
|
}
|
||||||
return runtime.ContentTypeJSON == base &&
|
gvkMatch := runtime.ContentTypeJSON == base &&
|
||||||
params["g"] == "apidiscovery.k8s.io" &&
|
params["g"] == gvk.Group &&
|
||||||
params["v"] == "v2beta1" &&
|
params["v"] == gvk.Version &&
|
||||||
params["as"] == "APIGroupDiscoveryList"
|
params["as"] == gvk.Kind
|
||||||
|
return gvkMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||||
|
@ -2762,54 +2762,76 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDiscoveryContentTypeVersion(t *testing.T) {
|
func TestDiscoveryContentTypeVersion(t *testing.T) {
|
||||||
|
v2beta1 := schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
contentType string
|
contentType string
|
||||||
isV2Beta1 bool
|
gvk schema.GroupVersionKind
|
||||||
|
match bool
|
||||||
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList",
|
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList",
|
||||||
isV2Beta1: true,
|
gvk: v2beta1,
|
||||||
|
match: true,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// content-type parameters are not in correct order, but comparison ignores order.
|
// content-type parameters are not in correct order, but comparison ignores order.
|
||||||
contentType: "application/json; v=v2beta1;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
|
contentType: "application/json; v=v2beta1;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
|
||||||
isV2Beta1: true,
|
gvk: v2beta1,
|
||||||
|
match: true,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// content-type parameters are not in correct order, but comparison ignores order.
|
// content-type parameters are not in correct order, but comparison ignores order.
|
||||||
contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2beta1",
|
contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2beta1",
|
||||||
isV2Beta1: true,
|
gvk: v2beta1,
|
||||||
|
match: true,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Ignores extra parameter "charset=utf-8"
|
// Ignores extra parameter "charset=utf-8"
|
||||||
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList;charset=utf-8",
|
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList;charset=utf-8",
|
||||||
isV2Beta1: true,
|
gvk: v2beta1,
|
||||||
|
match: true,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
isV2Beta1: false,
|
gvk: v2beta1,
|
||||||
|
match: false,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentType: "application/json; charset=UTF-8",
|
contentType: "application/json; charset=UTF-8",
|
||||||
isV2Beta1: false,
|
gvk: v2beta1,
|
||||||
|
match: false,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentType: "text/json",
|
contentType: "text/json",
|
||||||
isV2Beta1: false,
|
gvk: v2beta1,
|
||||||
|
match: false,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentType: "text/html",
|
contentType: "text/html",
|
||||||
isV2Beta1: false,
|
gvk: v2beta1,
|
||||||
|
match: false,
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentType: "",
|
contentType: "",
|
||||||
isV2Beta1: false,
|
gvk: v2beta1,
|
||||||
|
match: false,
|
||||||
|
expectErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
isV2Beta1 := isV2Beta1ContentType(test.contentType)
|
match, err := ContentTypeIsGVK(test.contentType, test.gvk)
|
||||||
assert.Equal(t, test.isV2Beta1, isV2Beta1)
|
assert.Equal(t, test.expectErr, err != nil)
|
||||||
|
assert.Equal(t, test.match, match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user