mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Let discoveryClient use RESTClient;
Ignore 403 and 404 error when discovering server-supported group/version
This commit is contained in:
		@@ -271,6 +271,76 @@ func TestGetServerVersion(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetServerGroupsWithV1Server(t *testing.T) {
 | 
				
			||||||
 | 
						server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
 | 
							var obj interface{}
 | 
				
			||||||
 | 
							switch req.URL.Path {
 | 
				
			||||||
 | 
							case "/api":
 | 
				
			||||||
 | 
								obj = &unversioned.APIVersions{
 | 
				
			||||||
 | 
									Versions: []string{
 | 
				
			||||||
 | 
										"v1",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							output, err := json.Marshal(obj)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Errorf("unexpected encoding error: %v", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
							w.Write(output)
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						client := NewOrDie(&Config{Host: server.URL})
 | 
				
			||||||
 | 
						// ServerGroups should not return an error even if server returns error at /api and /apis
 | 
				
			||||||
 | 
						apiGroupList, err := client.Discovery().ServerGroups()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						groupVersions := ExtractGroupVersions(apiGroupList)
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(groupVersions, []string{"v1"}) {
 | 
				
			||||||
 | 
							t.Errorf("expected: %q, got: %q", []string{"v1"}, groupVersions)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetServerResourcesWithV1Server(t *testing.T) {
 | 
				
			||||||
 | 
						server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
 | 
							var obj interface{}
 | 
				
			||||||
 | 
							switch req.URL.Path {
 | 
				
			||||||
 | 
							case "/api":
 | 
				
			||||||
 | 
								obj = &unversioned.APIVersions{
 | 
				
			||||||
 | 
									Versions: []string{
 | 
				
			||||||
 | 
										"v1",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							output, err := json.Marshal(obj)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Errorf("unexpected encoding error: %v", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
							w.Write(output)
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						client := NewOrDie(&Config{Host: server.URL})
 | 
				
			||||||
 | 
						// ServerResources should not return an error even if server returns error at /api/v1.
 | 
				
			||||||
 | 
						resourceMap, err := client.Discovery().ServerResources()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, found := resourceMap["v1"]; !found {
 | 
				
			||||||
 | 
							t.Errorf("missing v1 in resource map")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetServerResources(t *testing.T) {
 | 
					func TestGetServerResources(t *testing.T) {
 | 
				
			||||||
	stable := unversioned.APIResourceList{
 | 
						stable := unversioned.APIResourceList{
 | 
				
			||||||
		GroupVersion: "v1",
 | 
							GroupVersion: "v1",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,10 @@ limitations under the License.
 | 
				
			|||||||
package unversioned
 | 
					package unversioned
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
						"k8s.io/kubernetes/pkg/api/unversioned"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,8 +49,7 @@ type ServerResourcesInterface interface {
 | 
				
			|||||||
// DiscoveryClient implements the functions that dicovery server-supported API groups,
 | 
					// DiscoveryClient implements the functions that dicovery server-supported API groups,
 | 
				
			||||||
// versions and resources.
 | 
					// versions and resources.
 | 
				
			||||||
type DiscoveryClient struct {
 | 
					type DiscoveryClient struct {
 | 
				
			||||||
	httpClient HTTPClient
 | 
						*RESTClient
 | 
				
			||||||
	baseURL    url.URL
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so
 | 
					// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so
 | 
				
			||||||
@@ -71,42 +69,29 @@ func apiVersionsToAPIGroup(apiVersions *unversioned.APIVersions) (apiGroup unver
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DiscoveryClient) get(url string) (resp *http.Response, err error) {
 | 
					 | 
				
			||||||
	req, err := http.NewRequest("GET", url, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return d.httpClient.Do(req)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ServerGroups returns the supported groups, with information like supported versions and the
 | 
					// ServerGroups returns the supported groups, with information like supported versions and the
 | 
				
			||||||
// preferred version.
 | 
					// preferred version.
 | 
				
			||||||
func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList, err error) {
 | 
					func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList, err error) {
 | 
				
			||||||
	// Get the groupVersions exposed at /api
 | 
						// Get the groupVersions exposed at /api
 | 
				
			||||||
	url := d.baseURL
 | 
						v := &unversioned.APIVersions{}
 | 
				
			||||||
	url.Path = "/api"
 | 
						err = d.Get().AbsPath("/api").Do().Into(v)
 | 
				
			||||||
	resp, err := d.get(url.String())
 | 
						apiGroup := unversioned.APIGroup{}
 | 
				
			||||||
	if err != nil {
 | 
						if err == nil {
 | 
				
			||||||
 | 
							apiGroup = apiVersionsToAPIGroup(v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var v unversioned.APIVersions
 | 
					 | 
				
			||||||
	defer resp.Body.Close()
 | 
					 | 
				
			||||||
	err = json.NewDecoder(resp.Body).Decode(&v)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("unexpected error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	apiGroup := apiVersionsToAPIGroup(&v)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get the groupVersions exposed at /apis
 | 
						// Get the groupVersions exposed at /apis
 | 
				
			||||||
	url.Path = "/apis"
 | 
						apiGroupList = &unversioned.APIGroupList{}
 | 
				
			||||||
	resp2, err := d.get(url.String())
 | 
						err = d.Get().AbsPath("/apis").Do().Into(apiGroupList)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer resp2.Body.Close()
 | 
						// to be compatible with a v1.0 server, if it's a 403 or 404, ignore and return whatever we got from /api
 | 
				
			||||||
	apiGroupList = &unversioned.APIGroupList{}
 | 
						if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
 | 
				
			||||||
	if err = json.NewDecoder(resp2.Body).Decode(&apiGroupList); err != nil {
 | 
							apiGroupList = &unversioned.APIGroupList{}
 | 
				
			||||||
		return nil, fmt.Errorf("unexpected error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// append the group retrieved from /api to the list
 | 
						// append the group retrieved from /api to the list
 | 
				
			||||||
@@ -116,20 +101,21 @@ func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
 | 
					// ServerResourcesForGroupVersion returns the supported resources for a group and version.
 | 
				
			||||||
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) {
 | 
					func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) {
 | 
				
			||||||
	url := d.baseURL
 | 
						url := url.URL{}
 | 
				
			||||||
	if groupVersion == "v1" {
 | 
						if groupVersion == "v1" {
 | 
				
			||||||
		url.Path = "/api/" + groupVersion
 | 
							url.Path = "/api/" + groupVersion
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		url.Path = "/apis/" + groupVersion
 | 
							url.Path = "/apis/" + groupVersion
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp, err := d.get(url.String())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer resp.Body.Close()
 | 
					 | 
				
			||||||
	resources = &unversioned.APIResourceList{}
 | 
						resources = &unversioned.APIResourceList{}
 | 
				
			||||||
	if err = json.NewDecoder(resp.Body).Decode(resources); err != nil {
 | 
						err = d.Get().AbsPath(url.String()).Do().Into(resources)
 | 
				
			||||||
		return nil, fmt.Errorf("unexpected error: %v", err)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// ignore 403 or 404 error to be compatible with an v1.0 server.
 | 
				
			||||||
 | 
							if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
 | 
				
			||||||
 | 
								return resources, nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return resources, nil
 | 
						return resources, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -155,6 +141,8 @@ func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResource
 | 
				
			|||||||
func setDiscoveryDefaults(config *Config) error {
 | 
					func setDiscoveryDefaults(config *Config) error {
 | 
				
			||||||
	config.Prefix = ""
 | 
						config.Prefix = ""
 | 
				
			||||||
	config.Version = ""
 | 
						config.Version = ""
 | 
				
			||||||
 | 
						// Discovery client deals with unversioned objects, so we use api.Codec.
 | 
				
			||||||
 | 
						config.Codec = api.Codec
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -165,11 +153,6 @@ func NewDiscoveryClient(c *Config) (*DiscoveryClient, error) {
 | 
				
			|||||||
	if err := setDiscoveryDefaults(&config); err != nil {
 | 
						if err := setDiscoveryDefaults(&config); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	transport, err := TransportFor(c)
 | 
						client, err := UnversionedRESTClientFor(&config)
 | 
				
			||||||
	if err != nil {
 | 
						return &DiscoveryClient{client}, err
 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	client := &http.Client{Transport: transport}
 | 
					 | 
				
			||||||
	baseURL, err := defaultServerUrlFor(c)
 | 
					 | 
				
			||||||
	return &DiscoveryClient{client, *baseURL}, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -416,6 +416,31 @@ func RESTClientFor(config *Config) (*RESTClient, error) {
 | 
				
			|||||||
	return client, nil
 | 
						return client, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows
 | 
				
			||||||
 | 
					// the config.Version to be empty.
 | 
				
			||||||
 | 
					func UnversionedRESTClientFor(config *Config) (*RESTClient, error) {
 | 
				
			||||||
 | 
						if config.Codec == nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						baseURL, err := defaultServerUrlFor(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						client := NewRESTClient(baseURL, config.Version, config.Codec, config.QPS, config.Burst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						transport, err := TransportFor(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if transport != http.DefaultTransport {
 | 
				
			||||||
 | 
							client.Client = &http.Client{Transport: transport}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	// tlsTransports stores reusable round trippers with custom TLSClientConfig options
 | 
						// tlsTransports stores reusable round trippers with custom TLSClientConfig options
 | 
				
			||||||
	tlsTransports = map[string]*http.Transport{}
 | 
						tlsTransports = map[string]*http.Transport{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package conversion
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ugorji/go/codec"
 | 
						"github.com/ugorji/go/codec"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user