Merge pull request #21009 from caesarxuchao/unversioned-discovery
Auto commit by PR queue bot
This commit is contained in:
		@@ -221,7 +221,11 @@ func serviceErrorHandler(s runtime.NegotiatedSerializer, requestResolver *Reques
 | 
			
		||||
func AddApiWebService(s runtime.NegotiatedSerializer, container *restful.Container, apiPrefix string, getAPIVersionsFunc func(req *restful.Request) *unversioned.APIVersions) {
 | 
			
		||||
	// TODO: InstallREST should register each version automatically
 | 
			
		||||
 | 
			
		||||
	versionHandler := APIVersionHandler(s, getAPIVersionsFunc)
 | 
			
		||||
	// Because in release 1.1, /api returns response with empty APIVersion, we
 | 
			
		||||
	// use StripVersionNegotiatedSerializer to keep the response backwards
 | 
			
		||||
	// compatible.
 | 
			
		||||
	ss := StripVersionNegotiatedSerializer{s}
 | 
			
		||||
	versionHandler := APIVersionHandler(ss, getAPIVersionsFunc)
 | 
			
		||||
	ws := new(restful.WebService)
 | 
			
		||||
	ws.Path(apiPrefix)
 | 
			
		||||
	ws.Doc("get available API versions")
 | 
			
		||||
@@ -233,9 +237,52 @@ func AddApiWebService(s runtime.NegotiatedSerializer, container *restful.Contain
 | 
			
		||||
	container.Add(ws)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stripVersionEncoder strips APIVersion field from the encoding output. It's
 | 
			
		||||
// used to keep the responses at the discovery endpoints backward compatible
 | 
			
		||||
// with release-1.1, when the responses have empty APIVersion.
 | 
			
		||||
type stripVersionEncoder struct {
 | 
			
		||||
	encoder    runtime.Encoder
 | 
			
		||||
	serializer runtime.Serializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c stripVersionEncoder) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error {
 | 
			
		||||
	buf := bytes.NewBuffer([]byte{})
 | 
			
		||||
	err := c.encoder.EncodeToStream(obj, buf, overrides...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	roundTrippedObj, gvk, err := c.serializer.Decode(buf.Bytes(), nil, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	gvk.Group = ""
 | 
			
		||||
	gvk.Version = ""
 | 
			
		||||
	roundTrippedObj.GetObjectKind().SetGroupVersionKind(gvk)
 | 
			
		||||
	return c.serializer.EncodeToStream(roundTrippedObj, w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StripVersionNegotiatedSerializer will return stripVersionEncoder when
 | 
			
		||||
// EncoderForVersion is called. See comments for stripVersionEncoder.
 | 
			
		||||
type StripVersionNegotiatedSerializer struct {
 | 
			
		||||
	runtime.NegotiatedSerializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n StripVersionNegotiatedSerializer) EncoderForVersion(serializer runtime.Serializer, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
	encoder := n.NegotiatedSerializer.EncoderForVersion(serializer, gv)
 | 
			
		||||
	return stripVersionEncoder{encoder, serializer}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func keepUnversioned(group string) bool {
 | 
			
		||||
	return group == "" || group == "extensions"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds a service to return the supported api versions at /apis.
 | 
			
		||||
func AddApisWebService(s runtime.NegotiatedSerializer, container *restful.Container, apiPrefix string, f func(req *restful.Request) []unversioned.APIGroup) {
 | 
			
		||||
	rootAPIHandler := RootAPIHandler(s, f)
 | 
			
		||||
	// Because in release 1.1, /apis returns response with empty APIVersion, we
 | 
			
		||||
	// use StripVersionNegotiatedSerializer to keep the response backwards
 | 
			
		||||
	// compatible.
 | 
			
		||||
	ss := StripVersionNegotiatedSerializer{s}
 | 
			
		||||
	rootAPIHandler := RootAPIHandler(ss, f)
 | 
			
		||||
	ws := new(restful.WebService)
 | 
			
		||||
	ws.Path(apiPrefix)
 | 
			
		||||
	ws.Doc("get available API versions")
 | 
			
		||||
@@ -250,7 +297,14 @@ func AddApisWebService(s runtime.NegotiatedSerializer, container *restful.Contai
 | 
			
		||||
// Adds a service to return the supported versions, preferred version, and name
 | 
			
		||||
// of a group. E.g., a such web service will be registered at /apis/extensions.
 | 
			
		||||
func AddGroupWebService(s runtime.NegotiatedSerializer, container *restful.Container, path string, group unversioned.APIGroup) {
 | 
			
		||||
	groupHandler := GroupHandler(s, group)
 | 
			
		||||
	ss := s
 | 
			
		||||
	if keepUnversioned(group.Name) {
 | 
			
		||||
		// Because in release 1.1, /apis/extensions returns response with empty
 | 
			
		||||
		// APIVersion, we use StripVersionNegotiatedSerializer to keep the
 | 
			
		||||
		// response backwards compatible.
 | 
			
		||||
		ss = StripVersionNegotiatedSerializer{s}
 | 
			
		||||
	}
 | 
			
		||||
	groupHandler := GroupHandler(ss, group)
 | 
			
		||||
	ws := new(restful.WebService)
 | 
			
		||||
	ws.Path(path)
 | 
			
		||||
	ws.Doc("get information of a group")
 | 
			
		||||
@@ -265,7 +319,14 @@ func AddGroupWebService(s runtime.NegotiatedSerializer, container *restful.Conta
 | 
			
		||||
// Adds a service to return the supported resources, E.g., a such web service
 | 
			
		||||
// will be registered at /apis/extensions/v1.
 | 
			
		||||
func AddSupportedResourcesWebService(s runtime.NegotiatedSerializer, ws *restful.WebService, groupVersion unversioned.GroupVersion, apiResources []unversioned.APIResource) {
 | 
			
		||||
	resourceHandler := SupportedResourcesHandler(s, groupVersion, apiResources)
 | 
			
		||||
	ss := s
 | 
			
		||||
	if keepUnversioned(groupVersion.Group) {
 | 
			
		||||
		// Because in release 1.1, /apis/extensions/v1beta1 returns response
 | 
			
		||||
		// with empty APIVersion, we use StripVersionNegotiatedSerializer to
 | 
			
		||||
		// keep the response backwards compatible.
 | 
			
		||||
		ss = StripVersionNegotiatedSerializer{s}
 | 
			
		||||
	}
 | 
			
		||||
	resourceHandler := SupportedResourcesHandler(ss, groupVersion, apiResources)
 | 
			
		||||
	ws.Route(ws.GET("/").To(resourceHandler).
 | 
			
		||||
		Doc("get available resources").
 | 
			
		||||
		Operation("getAPIResources").
 | 
			
		||||
 
 | 
			
		||||
@@ -260,6 +260,82 @@ func TestGetNodeAddresses(t *testing.T) {
 | 
			
		||||
	assert.Equal([]string{"127.0.0.2", "127.0.0.2"}, addrs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Because we need to be backwards compatible with release 1.1, at endpoints
 | 
			
		||||
// that exist in release 1.1, the responses should have empty APIVersion.
 | 
			
		||||
func TestAPIVersionOfDiscoveryEndpoints(t *testing.T) {
 | 
			
		||||
	master, etcdserver, _, assert := newMaster(t)
 | 
			
		||||
	defer etcdserver.Terminate(t)
 | 
			
		||||
 | 
			
		||||
	server := httptest.NewServer(master.HandlerContainer.ServeMux)
 | 
			
		||||
 | 
			
		||||
	// /api exists in release-1.1
 | 
			
		||||
	resp, err := http.Get(server.URL + "/api")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	apiVersions := unversioned.APIVersions{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &apiVersions))
 | 
			
		||||
	assert.Equal(apiVersions.APIVersion, "")
 | 
			
		||||
 | 
			
		||||
	// /api/v1 exists in release-1.1
 | 
			
		||||
	resp, err = http.Get(server.URL + "/api/v1")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	resourceList := unversioned.APIResourceList{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &resourceList))
 | 
			
		||||
	assert.Equal(resourceList.APIVersion, "")
 | 
			
		||||
 | 
			
		||||
	// /apis exists in release-1.1
 | 
			
		||||
	resp, err = http.Get(server.URL + "/apis")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	groupList := unversioned.APIGroupList{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &groupList))
 | 
			
		||||
	assert.Equal(groupList.APIVersion, "")
 | 
			
		||||
 | 
			
		||||
	// /apis/extensions exists in release-1.1
 | 
			
		||||
	resp, err = http.Get(server.URL + "/apis/extensions")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	group := unversioned.APIGroup{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &group))
 | 
			
		||||
	assert.Equal(group.APIVersion, "")
 | 
			
		||||
 | 
			
		||||
	// /apis/extensions/v1beta1 exists in release-1.1
 | 
			
		||||
	resp, err = http.Get(server.URL + "/apis/extensions/v1beta1")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	resourceList = unversioned.APIResourceList{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &resourceList))
 | 
			
		||||
	assert.Equal(resourceList.APIVersion, "")
 | 
			
		||||
 | 
			
		||||
	// /apis/autoscaling doesn't exist in release-1.1, so the APIVersion field
 | 
			
		||||
	// should be non-empty in the results returned by the server.
 | 
			
		||||
	resp, err = http.Get(server.URL + "/apis/autoscaling")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	group = unversioned.APIGroup{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &group))
 | 
			
		||||
	assert.Equal(group.APIVersion, "v1")
 | 
			
		||||
 | 
			
		||||
	// apis/autoscaling/v1 doesn't exist in release-1.1, so the APIVersion field
 | 
			
		||||
	// should be non-empty in the results returned by the server.
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Get(server.URL + "/apis/autoscaling/v1")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	resourceList = unversioned.APIResourceList{}
 | 
			
		||||
	assert.NoError(decodeResponse(resp, &resourceList))
 | 
			
		||||
	assert.Equal(resourceList.APIVersion, "v1")
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDiscoveryAtAPIS(t *testing.T) {
 | 
			
		||||
	master, etcdserver, config, assert := newMaster(t)
 | 
			
		||||
	defer etcdserver.Terminate(t)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user