Skip to content

Commit 43a6d93

Browse files
Jefftreek8s-publishing-bot
authored andcommitted
Fallback to legacy discovery on a wider range of conditions in aggregator
Kubernetes-commit: 8656da75f2a6c9b9c761f9d41724bf6f324c5ec2
1 parent 29a840d commit 43a6d93

File tree

2 files changed

+59
-33
lines changed

2 files changed

+59
-33
lines changed

Diff for: discovery/discovery_client.go

+25-21
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ const (
6767
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
6868
)
6969

70+
// Aggregated discovery content-type GVK.
71+
var v2Beta1GVK = schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
72+
7073
// DiscoveryInterface holds the methods that discover server-supported API groups,
7174
// versions and resources.
7275
type DiscoveryInterface interface {
@@ -260,16 +263,15 @@ func (d *DiscoveryClient) downloadLegacy() (
260263
}
261264

262265
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
263-
// Switch on content-type server responded with: aggregated or unaggregated.
264-
switch {
265-
case isV2Beta1ContentType(responseContentType):
266+
// Based on the content-type server responded with: aggregated or unaggregated.
267+
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
266268
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
267269
err = json.Unmarshal(body, &aggregatedDiscovery)
268270
if err != nil {
269271
return nil, nil, nil, err
270272
}
271273
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
272-
default:
274+
} else {
273275
// Default is unaggregated discovery v1.
274276
var v metav1.APIVersions
275277
err = json.Unmarshal(body, &v)
@@ -313,16 +315,15 @@ func (d *DiscoveryClient) downloadAPIs() (
313315
apiGroupList := &metav1.APIGroupList{}
314316
failedGVs := map[schema.GroupVersion]error{}
315317
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
316-
// Switch on content-type server responded with: aggregated or unaggregated.
317-
switch {
318-
case isV2Beta1ContentType(responseContentType):
318+
// Based on the content-type server responded with: aggregated or unaggregated.
319+
if isGVK, _ := ContentTypeIsGVK(responseContentType, v2Beta1GVK); isGVK {
319320
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
320321
err = json.Unmarshal(body, &aggregatedDiscovery)
321322
if err != nil {
322323
return nil, nil, nil, err
323324
}
324325
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
325-
default:
326+
} else {
326327
// Default is unaggregated discovery v1.
327328
err = json.Unmarshal(body, apiGroupList)
328329
if err != nil {
@@ -333,26 +334,29 @@ func (d *DiscoveryClient) downloadAPIs() (
333334
return apiGroupList, resourcesByGV, failedGVs, nil
334335
}
335336

336-
// isV2Beta1ContentType checks of the content-type string is both
337-
// "application/json" and contains the v2beta1 content-type params.
337+
// ContentTypeIsGVK checks of the content-type string is both
338+
// "application/json" and matches the provided GVK. An error
339+
// is returned if the content type string is malformed.
338340
// NOTE: This function is resilient to the ordering of the
339341
// content-type parameters, as well as parameters added by
340342
// intermediaries such as proxies or gateways. Examples:
341343
//
342-
// "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList" = true
343-
// "application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io" = true
344-
// "application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io;charset=utf-8" = true
345-
// "application/json" = false
346-
// "application/json; charset=UTF-8" = false
347-
func isV2Beta1ContentType(contentType string) bool {
344+
// ("application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
345+
// ("application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
346+
// ("application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io;charset=utf-8", {apidiscovery.k8s.io, v2beta1, APIGroupDiscoveryList}) = (true, nil)
347+
// ("application/json", any GVK) = (false, nil)
348+
// ("application/json; charset=UTF-8", any GVK) = (false, nil)
349+
// ("malformed content type string", any GVK) = (false, error)
350+
func ContentTypeIsGVK(contentType string, gvk schema.GroupVersionKind) (bool, error) {
348351
base, params, err := mime.ParseMediaType(contentType)
349352
if err != nil {
350-
return false
353+
return false, err
351354
}
352-
return runtime.ContentTypeJSON == base &&
353-
params["g"] == "apidiscovery.k8s.io" &&
354-
params["v"] == "v2beta1" &&
355-
params["as"] == "APIGroupDiscoveryList"
355+
gvkMatch := runtime.ContentTypeJSON == base &&
356+
params["g"] == gvk.Group &&
357+
params["v"] == gvk.Version &&
358+
params["as"] == gvk.Kind
359+
return gvkMatch, nil
356360
}
357361

358362
// ServerGroups returns the supported groups, with information like supported versions and the

Diff for: discovery/discovery_client_test.go

+34-12
Original file line numberDiff line numberDiff line change
@@ -2762,54 +2762,76 @@ func TestAggregatedServerPreferredResources(t *testing.T) {
27622762
}
27632763

27642764
func TestDiscoveryContentTypeVersion(t *testing.T) {
2765+
v2beta1 := schema.GroupVersionKind{Group: "apidiscovery.k8s.io", Version: "v2beta1", Kind: "APIGroupDiscoveryList"}
27652766
tests := []struct {
27662767
contentType string
2767-
isV2Beta1 bool
2768+
gvk schema.GroupVersionKind
2769+
match bool
2770+
expectErr bool
27682771
}{
27692772
{
27702773
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList",
2771-
isV2Beta1: true,
2774+
gvk: v2beta1,
2775+
match: true,
2776+
expectErr: false,
27722777
},
27732778
{
27742779
// content-type parameters are not in correct order, but comparison ignores order.
27752780
contentType: "application/json; v=v2beta1;as=APIGroupDiscoveryList;g=apidiscovery.k8s.io",
2776-
isV2Beta1: true,
2781+
gvk: v2beta1,
2782+
match: true,
2783+
expectErr: false,
27772784
},
27782785
{
27792786
// content-type parameters are not in correct order, but comparison ignores order.
27802787
contentType: "application/json; as=APIGroupDiscoveryList;g=apidiscovery.k8s.io;v=v2beta1",
2781-
isV2Beta1: true,
2788+
gvk: v2beta1,
2789+
match: true,
2790+
expectErr: false,
27822791
},
27832792
{
27842793
// Ignores extra parameter "charset=utf-8"
27852794
contentType: "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList;charset=utf-8",
2786-
isV2Beta1: true,
2795+
gvk: v2beta1,
2796+
match: true,
2797+
expectErr: false,
27872798
},
27882799
{
27892800
contentType: "application/json",
2790-
isV2Beta1: false,
2801+
gvk: v2beta1,
2802+
match: false,
2803+
expectErr: false,
27912804
},
27922805
{
27932806
contentType: "application/json; charset=UTF-8",
2794-
isV2Beta1: false,
2807+
gvk: v2beta1,
2808+
match: false,
2809+
expectErr: false,
27952810
},
27962811
{
27972812
contentType: "text/json",
2798-
isV2Beta1: false,
2813+
gvk: v2beta1,
2814+
match: false,
2815+
expectErr: false,
27992816
},
28002817
{
28012818
contentType: "text/html",
2802-
isV2Beta1: false,
2819+
gvk: v2beta1,
2820+
match: false,
2821+
expectErr: false,
28032822
},
28042823
{
28052824
contentType: "",
2806-
isV2Beta1: false,
2825+
gvk: v2beta1,
2826+
match: false,
2827+
expectErr: true,
28072828
},
28082829
}
28092830

28102831
for _, test := range tests {
2811-
isV2Beta1 := isV2Beta1ContentType(test.contentType)
2812-
assert.Equal(t, test.isV2Beta1, isV2Beta1)
2832+
match, err := ContentTypeIsGVK(test.contentType, test.gvk)
2833+
assert.Equal(t, test.expectErr, err != nil)
2834+
assert.Equal(t, test.match, match)
28132835
}
28142836
}
28152837

0 commit comments

Comments
 (0)