From 6a4c477af7649458cc9a9bb931e14b36eb94e934 Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Thu, 1 Oct 2015 14:56:22 -0700 Subject: [PATCH] add a ServerAPIVersions function that visits both /api and /apis, and doesn't require a high-level client --- pkg/client/unversioned/helper.go | 46 +++++++++++++++++++++ pkg/client/unversioned/helper_test.go | 59 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/pkg/client/unversioned/helper.go b/pkg/client/unversioned/helper.go index f93c2417eaf..98877735d22 100644 --- a/pkg/client/unversioned/helper.go +++ b/pkg/client/unversioned/helper.go @@ -17,6 +17,7 @@ limitations under the License. package unversioned import ( + "encoding/json" "fmt" "io/ioutil" "net" @@ -175,6 +176,51 @@ func MatchesServerVersion(client *Client, c *Config) error { return nil } +func extractGroupVersions(l *api.APIGroupList) []string { + var groupVersions []string + for _, g := range l.Groups { + for _, gv := range g.Versions { + groupVersions = append(groupVersions, gv.GroupVersion) + } + } + return groupVersions +} + +// ServerAPIVersions returns the GroupVersions supported by the API server. +// It creates a RESTClient based on the passed in config, but it doesn't rely +// on the Version, Codec, and Prefix of the config, because it uses AbsPath and +// takes the raw response. +func ServerAPIVersions(c *Config) (groupVersions []string, err error) { + client, err := RESTClientFor(c) + if err != nil { + return nil, err + } + // Get the groupVersions exposed at /api + body, err := client.Get().AbsPath("api").Do().Raw() + if err != nil { + return nil, err + } + var v api.APIVersions + err = json.Unmarshal(body, &v) + if err != nil { + return nil, fmt.Errorf("got '%s': %v", string(body), err) + } + groupVersions = append(groupVersions, v.Versions...) + // Get the groupVersions exposed at /apis + body, err = client.Get().AbsPath("apis").Do().Raw() + if err != nil { + return nil, err + } + var apiGroupList api.APIGroupList + err = json.Unmarshal(body, &apiGroupList) + if err != nil { + return nil, fmt.Errorf("got '%s': %v", string(body), err) + } + groupVersions = append(groupVersions, extractGroupVersions(&apiGroupList)...) + + return groupVersions, nil +} + // NegotiateVersion queries the server's supported api versions to find // a version that both client and server support. // - If no version is provided, try registered client versions in order of diff --git a/pkg/client/unversioned/helper_test.go b/pkg/client/unversioned/helper_test.go index 21c70a890cb..0b2642b91ef 100644 --- a/pkg/client/unversioned/helper_test.go +++ b/pkg/client/unversioned/helper_test.go @@ -17,11 +17,14 @@ limitations under the License. package unversioned import ( + "encoding/json" "net/http" + "net/http/httptest" "reflect" "strings" "testing" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" ) @@ -374,3 +377,59 @@ func TestSetKubernetesDefaultsUserAgent(t *testing.T) { t.Errorf("no user agent set: %#v", config) } } + +func TestHelperGetServerAPIVersions(t *testing.T) { + expect := []string{"v1", "v2", "v3"} + APIVersions := api.APIVersions{Versions: expect} + expect = append(expect, "group1/v1", "group1/v2", "group2/v1", "group2/v2") + APIGroupList := api.APIGroupList{ + Groups: []api.APIGroup{ + { + Versions: []api.GroupVersion{ + { + GroupVersion: "group1/v1", + }, + { + GroupVersion: "group1/v2", + }, + }, + }, + { + Versions: []api.GroupVersion{ + { + GroupVersion: "group2/v1", + }, + { + GroupVersion: "group2/v2", + }, + }, + }, + }, + } + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + var output []byte + var err error + switch req.URL.Path { + case "/api": + output, err = json.Marshal(APIVersions) + + case "/apis": + output, err = json.Marshal(APIGroupList) + } + 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) + })) + got, err := ServerAPIVersions(&Config{Host: server.URL, Version: "invalid version", Codec: testapi.Default.Codec()}) + if err != nil { + t.Fatalf("unexpected encoding error: %v", err) + } + if e, a := expect, got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +}