diff --git a/cluster/gce/util.sh b/cluster/gce/util.sh index c264a389234..55d6efb7274 100755 --- a/cluster/gce/util.sh +++ b/cluster/gce/util.sh @@ -670,7 +670,7 @@ function kube-up { until curl --insecure -H "Authorization: Bearer ${KUBE_BEARER_TOKEN}" \ --max-time 5 --fail --output /dev/null --silent \ - "https://${KUBE_MASTER_IP}/api/v1beta1/pods"; do + "https://${KUBE_MASTER_IP}/api/v1beta3/pods"; do printf "." sleep 2 done diff --git a/pkg/api/testapi/testapi.go b/pkg/api/testapi/testapi.go index 1d8cc5bfb2e..91706bdb182 100644 --- a/pkg/api/testapi/testapi.go +++ b/pkg/api/testapi/testapi.go @@ -114,8 +114,12 @@ func ResourcePath(resource, namespace, name string) string { // For ex, this is of the form: // /api/v1beta1/pods/pod0?namespace=foo for v1beta1 and // /api/v1beta3/namespaces/foo/pods/pod0 for v1beta3. -func ResourcePathWithQueryParams(resource, namespace, name string) string { - path := ResourcePath(resource, namespace, name) +func ResourcePathWithNamespaceQuery(resource, namespace, name string) string { + return ResourcePathWithPrefixAndNamespaceQuery("", resource, namespace, name) +} + +func ResourcePathWithPrefixAndNamespaceQuery(prefix, resource, namespace, name string) string { + path := ResourcePathWithPrefix(prefix, resource, namespace, name) // Add namespace as query param for pre v1beta3. if api.PreV1Beta3(Version()) && namespace != "" { path = path + "?namespace=" + namespace diff --git a/pkg/api/testapi/testapi_test.go b/pkg/api/testapi/testapi_test.go index af13e95cd78..b407c58719c 100644 --- a/pkg/api/testapi/testapi_test.go +++ b/pkg/api/testapi/testapi_test.go @@ -120,7 +120,7 @@ func TestResourcePathForV1Beta1(t *testing.T) { } } -func TestResourcePathWithQueryParamsForV1Beta3(t *testing.T) { +func TestResourcePathWithNamespaceQueryForV1Beta3(t *testing.T) { if Version() != "v1beta3" { // Skip the test if we are not testing v1beta3. return @@ -138,13 +138,13 @@ func TestResourcePathWithQueryParamsForV1Beta3(t *testing.T) { {"resource", "", "", "/api/v1beta3/resource"}, } for _, item := range testCases { - if actual := ResourcePathWithQueryParams(item.resource, item.namespace, item.name); actual != item.expected { + if actual := ResourcePathWithNamespaceQuery(item.resource, item.namespace, item.name); actual != item.expected { t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name) } } } -func TestResourcePathWithQueryParamsForV1Beta1(t *testing.T) { +func TestResourcePathWithNamespaceQueryForV1Beta1(t *testing.T) { if Version() != "v1beta1" { // Skip the test if we are not testing v1beta1. return @@ -162,7 +162,7 @@ func TestResourcePathWithQueryParamsForV1Beta1(t *testing.T) { {"resource", "", "", "/api/v1beta1/resource"}, } for _, item := range testCases { - if actual := ResourcePathWithQueryParams(item.resource, item.namespace, item.name); actual != item.expected { + if actual := ResourcePathWithNamespaceQuery(item.resource, item.namespace, item.name); actual != item.expected { t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name) } } diff --git a/pkg/apiserver/handlers_test.go b/pkg/apiserver/handlers_test.go index af36e9965a9..56b4d9da663 100644 --- a/pkg/apiserver/handlers_test.go +++ b/pkg/apiserver/handlers_test.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) @@ -48,6 +49,22 @@ func expectHTTP(url string, code int, t *testing.T) { } } +func getPath(resource, namespace, name string) string { + return testapi.ResourcePath(resource, namespace, name) +} + +func pathWithNamespaceQuery(resource, namespace, name string) string { + return testapi.ResourcePathWithNamespaceQuery(resource, namespace, name) +} + +func pathWithPrefix(prefix, resource, namespace, name string) string { + return testapi.ResourcePathWithPrefix(prefix, resource, namespace, name) +} + +func pathWithPrefixAndNamespaceQuery(prefix, resource, namespace, name string) string { + return testapi.ResourcePathWithPrefixAndNamespaceQuery(prefix, resource, namespace, name) +} + func TestMaxInFlight(t *testing.T) { const Iterations = 3 block := sync.WaitGroup{} @@ -168,17 +185,15 @@ func TestGetAPIRequestInfo(t *testing.T) { {"GET", "/watch/namespaces/other/pods", "watch", "", "other", "pods", "", "Pod", "", []string{"pods"}}, // fully-qualified paths - {"GET", "/api/v1beta1/namespaces/other/pods", "list", "v1beta1", "other", "pods", "", "Pod", "", []string{"pods"}}, - {"GET", "/api/v1beta1/namespaces/other/pods/foo", "get", "v1beta1", "other", "pods", "", "Pod", "foo", []string{"pods", "foo"}}, - {"GET", "/api/v1beta1/pods", "list", "v1beta1", api.NamespaceAll, "pods", "", "Pod", "", []string{"pods"}}, - {"POST", "/api/v1beta1/pods", "create", "v1beta1", api.NamespaceDefault, "pods", "", "Pod", "", []string{"pods"}}, - {"GET", "/api/v1beta1/pods/foo", "get", "v1beta1", api.NamespaceDefault, "pods", "", "Pod", "foo", []string{"pods", "foo"}}, - {"GET", "/api/v1beta1/pods/foo?namespace=other", "get", "v1beta1", "other", "pods", "", "Pod", "foo", []string{"pods", "foo"}}, - {"GET", "/api/v1beta1/pods?namespace=other", "list", "v1beta1", "other", "pods", "", "Pod", "", []string{"pods"}}, - {"GET", "/api/v1beta1/proxy/pods/foo", "proxy", "v1beta1", api.NamespaceDefault, "pods", "", "Pod", "foo", []string{"pods", "foo"}}, - {"GET", "/api/v1beta1/redirect/pods/foo", "redirect", "v1beta1", api.NamespaceDefault, "pods", "", "Pod", "foo", []string{"pods", "foo"}}, - {"GET", "/api/v1beta1/watch/pods", "watch", "v1beta1", api.NamespaceAll, "pods", "", "Pod", "", []string{"pods"}}, - {"GET", "/api/v1beta1/watch/namespaces/other/pods", "watch", "v1beta1", "other", "pods", "", "Pod", "", []string{"pods"}}, + {"GET", pathWithNamespaceQuery("pods", "other", ""), "list", testapi.Version(), "other", "pods", "", "Pod", "", []string{"pods"}}, + {"GET", pathWithNamespaceQuery("pods", "other", "foo"), "get", testapi.Version(), "other", "pods", "", "Pod", "foo", []string{"pods", "foo"}}, + {"GET", getPath("pods", "", ""), "list", testapi.Version(), api.NamespaceAll, "pods", "", "Pod", "", []string{"pods"}}, + {"POST", getPath("pods", "", ""), "create", testapi.Version(), api.NamespaceDefault, "pods", "", "Pod", "", []string{"pods"}}, + {"GET", getPath("pods", "", "foo"), "get", testapi.Version(), api.NamespaceDefault, "pods", "", "Pod", "foo", []string{"pods", "foo"}}, + {"GET", pathWithPrefix("proxy", "pods", "", "foo"), "proxy", testapi.Version(), api.NamespaceDefault, "pods", "", "Pod", "foo", []string{"pods", "foo"}}, + {"GET", pathWithPrefix("watch", "pods", "", ""), "watch", testapi.Version(), api.NamespaceAll, "pods", "", "Pod", "", []string{"pods"}}, + {"GET", pathWithPrefixAndNamespaceQuery("redirect", "pods", "", ""), "redirect", testapi.Version(), api.NamespaceAll, "pods", "", "Pod", "", []string{"pods"}}, + {"GET", pathWithPrefixAndNamespaceQuery("watch", "pods", "other", ""), "watch", testapi.Version(), "other", "pods", "", "Pod", "", []string{"pods"}}, // subresource identification {"GET", "/namespaces/other/pods/foo/status", "get", "", "other", "pods", "status", "Pod", "foo", []string{"pods", "foo", "status"}}, @@ -222,8 +237,8 @@ func TestGetAPIRequestInfo(t *testing.T) { errorCases := map[string]string{ "no resource path": "/", - "just apiversion": "/api/v1beta1/", - "apiversion with no resource": "/api/v1beta1/", + "just apiversion": "/api/version/", + "apiversion with no resource": "/api/version/", } for k, v := range errorCases { req, err := http.NewRequest("GET", v, nil) diff --git a/pkg/client/request_test.go b/pkg/client/request_test.go index fe77a8c5901..4c5e7734bd0 100644 --- a/pkg/client/request_test.go +++ b/pkg/client/request_test.go @@ -36,8 +36,6 @@ import ( apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -712,7 +710,7 @@ func TestDoRequestNewWay(t *testing.T) { Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} - expectedBody, _ := v1beta2.Codec.Encode(expectedObj) + expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), @@ -720,7 +718,7 @@ func TestDoRequestNewWay(t *testing.T) { } testServer := httptest.NewServer(&fakeHandler) defer testServer.Close() - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta2", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) obj, err := c.Verb("POST"). Prefix("foo", "bar"). Suffix("baz"). @@ -736,7 +734,9 @@ func TestDoRequestNewWay(t *testing.T) { } else if !api.Semantic.DeepDerivative(expectedObj, obj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } - fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?timeout=1s", "POST", &reqBody) + requestURL := testapi.ResourcePathWithPrefix("foo/bar", "", "", "baz") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &reqBody) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } @@ -758,7 +758,7 @@ func TestCheckRetryClosesBody(t *testing.T) { })) defer testServer.Close() - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta2", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) _, err := c.Verb("POST"). Prefix("foo", "bar"). Suffix("baz"). @@ -787,7 +787,7 @@ func BenchmarkCheckRetryClosesBody(t *testing.B) { })) defer testServer.Close() - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta2", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) r := c.Verb("POST"). Prefix("foo", "bar"). Suffix("baz"). @@ -802,20 +802,20 @@ func BenchmarkCheckRetryClosesBody(t *testing.B) { } func TestDoRequestNewWayReader(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} - reqBodyExpected, _ := v1beta1.Codec.Encode(reqObj) + reqBodyExpected, _ := testapi.Codec().Encode(reqObj) expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{ Protocol: "TCP", Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} - expectedBody, _ := v1beta1.Codec.Encode(expectedObj) + expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta1", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) obj, err := c.Verb("POST"). Resource("bar"). Name("baz"). @@ -834,7 +834,9 @@ func TestDoRequestNewWayReader(t *testing.T) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } tmpStr := string(reqBodyExpected) - fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?labels=name%3Dfoo&timeout=1s", "POST", &tmpStr) + requestURL := testapi.ResourcePathWithPrefix("foo", "bar", "", "baz") + requestURL += "?" + api.LabelSelectorQueryParam(testapi.Version()) + "=name%3Dfoo&timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } @@ -842,20 +844,20 @@ func TestDoRequestNewWayReader(t *testing.T) { func TestDoRequestNewWayObj(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} - reqBodyExpected, _ := v1beta2.Codec.Encode(reqObj) + reqBodyExpected, _ := testapi.Codec().Encode(reqObj) expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{ Protocol: "TCP", Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} - expectedBody, _ := v1beta2.Codec.Encode(expectedObj) + expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta2", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) obj, err := c.Verb("POST"). Suffix("baz"). Name("bar"). @@ -874,7 +876,9 @@ func TestDoRequestNewWayObj(t *testing.T) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } tmpStr := string(reqBodyExpected) - fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?labels=name%3Dfoo&timeout=1s", "POST", &tmpStr) + requestURL := testapi.ResourcePath("foo", "", "bar/baz") + requestURL += "?" + api.LabelSelectorQueryParam(testapi.Version()) + "=name%3Dfoo&timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } @@ -882,7 +886,7 @@ func TestDoRequestNewWayObj(t *testing.T) { func TestDoRequestNewWayFile(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} - reqBodyExpected, err := v1beta1.Codec.Encode(reqObj) + reqBodyExpected, err := testapi.Codec().Encode(reqObj) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -902,14 +906,14 @@ func TestDoRequestNewWayFile(t *testing.T) { Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} - expectedBody, _ := v1beta1.Codec.Encode(expectedObj) + expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta1", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) wasCreated := true obj, err := c.Verb("POST"). Prefix("foo/bar", "baz"). @@ -929,7 +933,9 @@ func TestDoRequestNewWayFile(t *testing.T) { t.Errorf("expected object was not created") } tmpStr := string(reqBodyExpected) - fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?timeout=1s", "POST", &tmpStr) + requestURL := testapi.ResourcePathWithPrefix("foo/bar/baz", "", "", "") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } @@ -937,7 +943,7 @@ func TestDoRequestNewWayFile(t *testing.T) { func TestWasCreated(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} - reqBodyExpected, err := v1beta1.Codec.Encode(reqObj) + reqBodyExpected, err := testapi.Codec().Encode(reqObj) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -947,14 +953,14 @@ func TestWasCreated(t *testing.T) { Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} - expectedBody, _ := v1beta1.Codec.Encode(expectedObj) + expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 201, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) - c := NewOrDie(&Config{Host: testServer.URL, Version: "v1beta1", Username: "user", Password: "pass"}) + c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "user", Password: "pass"}) wasCreated := false obj, err := c.Verb("PUT"). Prefix("foo/bar", "baz"). @@ -975,7 +981,9 @@ func TestWasCreated(t *testing.T) { } tmpStr := string(reqBodyExpected) - fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?timeout=1s", "PUT", &tmpStr) + requestURL := testapi.ResourcePathWithPrefix("foo/bar/baz", "", "", "") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "PUT", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } @@ -1142,7 +1150,7 @@ func TestWatch(t *testing.T) { s, err := New(&Config{ Host: testServer.URL, - Version: "v1beta1", + Version: testapi.Version(), Username: "user", Password: "pass", }) @@ -1192,7 +1200,7 @@ func TestStream(t *testing.T) { s, err := New(&Config{ Host: testServer.URL, - Version: "v1beta1", + Version: testapi.Version(), Username: "user", Password: "pass", }) diff --git a/pkg/client/restclient_test.go b/pkg/client/restclient_test.go index fffbda8a99a..1f30a98114e 100644 --- a/pkg/client/restclient_test.go +++ b/pkg/client/restclient_test.go @@ -25,9 +25,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) @@ -38,11 +35,8 @@ func TestSetsCodec(t *testing.T) { Prefix string Codec runtime.Codec }{ - "v1beta1": {false, "/api/v1beta1/", v1beta1.Codec}, - "": {false, "/api/" + latest.Version + "/", latest.Codec}, - "v1beta2": {false, "/api/v1beta2/", v1beta2.Codec}, - "v1beta3": {false, "/api/v1beta3/", v1beta3.Codec}, - "v1beta4": {true, "", nil}, + testapi.Version(): {false, "/api/" + testapi.Version() + "/", testapi.Codec()}, + "invalidVersion": {true, "", nil}, } for version, expected := range testCases { client, err := New(&Config{Host: "127.0.0.1", Version: version}) @@ -69,7 +63,7 @@ func TestRESTClientRequires(t *testing.T) { if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: "", Codec: testapi.Codec()}); err == nil { t.Errorf("unexpected non-error") } - if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: "v1beta1"}); err == nil { + if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: testapi.Version()}); err == nil { t.Errorf("unexpected non-error") } if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: testapi.Version(), Codec: testapi.Codec()}); err != nil { @@ -85,17 +79,17 @@ func TestValidatesHostParameter(t *testing.T) { URL string Err bool }{ - {"127.0.0.1", "", "http://127.0.0.1/v1beta1/", false}, - {"127.0.0.1:8080", "", "http://127.0.0.1:8080/v1beta1/", false}, - {"foo.bar.com", "", "http://foo.bar.com/v1beta1/", false}, - {"http://host/prefix", "", "http://host/prefix/v1beta1/", false}, - {"http://host", "", "http://host/v1beta1/", false}, - {"http://host", "/", "http://host/v1beta1/", false}, - {"http://host", "/other", "http://host/other/v1beta1/", false}, + {"127.0.0.1", "", "http://127.0.0.1/" + testapi.Version() + "/", false}, + {"127.0.0.1:8080", "", "http://127.0.0.1:8080/" + testapi.Version() + "/", false}, + {"foo.bar.com", "", "http://foo.bar.com/" + testapi.Version() + "/", false}, + {"http://host/prefix", "", "http://host/prefix/" + testapi.Version() + "/", false}, + {"http://host", "", "http://host/" + testapi.Version() + "/", false}, + {"http://host", "/", "http://host/" + testapi.Version() + "/", false}, + {"http://host", "/other", "http://host/other/" + testapi.Version() + "/", false}, {"host/server", "", "", true}, } for i, testCase := range testCases { - c, err := RESTClientFor(&Config{Host: testCase.Host, Prefix: testCase.Prefix, Version: "v1beta1", Codec: testapi.Codec()}) + c, err := RESTClientFor(&Config{Host: testCase.Host, Prefix: testCase.Prefix, Version: testapi.Version(), Codec: testapi.Codec()}) switch { case err == nil && testCase.Err: t.Errorf("expected error but was nil") diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 6eccca2d0a7..bad8e94f835 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -27,6 +27,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" ) @@ -46,9 +47,10 @@ func getFakeClient(t *testing.T, validURLs []string) (ClientPosterFunc, *httptes } server := httptest.NewServer(http.HandlerFunc(handlerFunc)) return func(mapping *meta.RESTMapping) (RESTClientPoster, error) { - fakeCodec := runtime.CodecFor(api.Scheme, "v1beta1") - fakeUri, _ := url.Parse(server.URL + "/api/v1beta1") - return client.NewRESTClient(fakeUri, "v1beta1", fakeCodec, true, 5, 10), nil + fakeCodec := testapi.Codec() + fakeUri, _ := url.Parse(server.URL + "/api/" + testapi.Version()) + legacyBehavior := api.PreV1Beta3(testapi.Version()) + return client.NewRESTClient(fakeUri, testapi.Version(), fakeCodec, legacyBehavior, 5, 10), nil }, server } @@ -64,7 +66,10 @@ func TestCreateObjects(t *testing.T) { }) typer, mapper := getTyperAndMapper() - client, s := getFakeClient(t, []string{"/api/v1beta1/pods?namespace=default", "/api/v1beta1/services?namespace=default"}) + client, s := getFakeClient(t, []string{ + testapi.ResourcePathWithNamespaceQuery("pods", api.NamespaceDefault, ""), + testapi.ResourcePathWithNamespaceQuery("services", api.NamespaceDefault, ""), + }) errs := CreateObjects(typer, mapper, client, items) s.Close() @@ -77,11 +82,13 @@ func TestCreateNoNameItem(t *testing.T) { items := []runtime.Object{} items = append(items, &api.Service{ - TypeMeta: api.TypeMeta{APIVersion: "v1beta1", Kind: "Service"}, + TypeMeta: api.TypeMeta{APIVersion: testapi.Version(), Kind: "Service"}, }) typer, mapper := getTyperAndMapper() - client, s := getFakeClient(t, []string{"/api/v1beta1/services"}) + client, s := getFakeClient(t, []string{ + testapi.ResourcePath("services", api.NamespaceDefault, ""), + }) errs := CreateObjects(typer, mapper, client, items) s.Close() @@ -125,12 +132,15 @@ func TestCreateNoClientItems(t *testing.T) { items := []runtime.Object{} items = append(items, &api.Pod{ - TypeMeta: api.TypeMeta{APIVersion: "v1beta1", Kind: "Pod"}, + TypeMeta: api.TypeMeta{APIVersion: testapi.Version(), Kind: "Pod"}, ObjectMeta: api.ObjectMeta{Name: "test-pod"}, }) typer, mapper := getTyperAndMapper() - _, s := getFakeClient(t, []string{"/api/v1beta1/pods", "/api/v1beta1/services"}) + _, s := getFakeClient(t, []string{ + testapi.ResourcePath("pods", api.NamespaceDefault, ""), + testapi.ResourcePath("services", api.NamespaceDefault, ""), + }) noClientFunc := func(mapping *meta.RESTMapping) (RESTClientPoster, error) { return nil, fmt.Errorf("no client") diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index f6e6cc9cbb5..954dcf684eb 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -251,7 +251,7 @@ func TestCreateReplica(t *testing.T) { }, Spec: controllerSpec.Spec.Template.Spec, } - fakeHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("pods", api.NamespaceDefault, ""), "POST", nil) + fakeHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("pods", api.NamespaceDefault, ""), "POST", nil) actualPod, err := client.Codec.Decode([]byte(fakeHandler.RequestBody)) if err != nil { t.Errorf("Unexpected error: %#v", err) @@ -345,7 +345,7 @@ func TestControllerUpdateReplicas(t *testing.T) { rc.Labels = rc.Spec.Template.Labels decRc := runtime.EncodeOrDie(testapi.Codec(), &rc) - fakeUpdateHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams(replicationControllerResourceName(), rc.Namespace, rc.Name), "PUT", &decRc) + fakeUpdateHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery(replicationControllerResourceName(), rc.Namespace, rc.Name), "PUT", &decRc) validateSyncReplication(t, &fakePodControl, 1, 0) } diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index 7317fda7b8b..6d89046890e 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -215,23 +215,17 @@ func stringBody(body string) io.ReadCloser { func TestClientVersions(t *testing.T) { f := cmdutil.NewFactory(nil) - versions := []string{ - "v1beta1", - "v1beta2", - "v1beta3", + version := testapi.Version() + mapping := &meta.RESTMapping{ + APIVersion: version, } - for _, version := range versions { - mapping := &meta.RESTMapping{ - APIVersion: version, - } - c, err := f.RESTClient(mapping) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - client := c.(*client.RESTClient) - if client.APIVersion() != version { - t.Errorf("unexpected Client APIVersion: %s %v", client.APIVersion, client) - } + c, err := f.RESTClient(mapping) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + client := c.(*client.RESTClient) + if client.APIVersion() != version { + t.Errorf("unexpected Client APIVersion: %s %v", client.APIVersion, client) } } diff --git a/pkg/kubectl/cmd/config/config_test.go b/pkg/kubectl/cmd/config/config_test.go index 4360d9d1f26..2e82742d417 100644 --- a/pkg/kubectl/cmd/config/config_test.go +++ b/pkg/kubectl/cmd/config/config_test.go @@ -26,6 +26,7 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -537,13 +538,13 @@ func TestNewEmptyCluster(t *testing.T) { func TestAdditionalCluster(t *testing.T) { expectedConfig := newRedFederalCowHammerConfig() cluster := *clientcmdapi.NewCluster() - cluster.APIVersion = "v1beta1" + cluster.APIVersion = testapi.Version() cluster.CertificateAuthority = "ca-location" cluster.InsecureSkipTLSVerify = false cluster.Server = "serverlocation" expectedConfig.Clusters["different-cluster"] = cluster test := configCommandTest{ - args: []string{"set-cluster", "different-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation", "--" + clientcmd.FlagInsecure + "=false", "--" + clientcmd.FlagCAFile + "=ca-location", "--" + clientcmd.FlagAPIVersion + "=v1beta1"}, + args: []string{"set-cluster", "different-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation", "--" + clientcmd.FlagInsecure + "=false", "--" + clientcmd.FlagCAFile + "=ca-location", "--" + clientcmd.FlagAPIVersion + "=" + testapi.Version()}, startingConfig: newRedFederalCowHammerConfig(), expectedConfig: expectedConfig, } diff --git a/pkg/kubectl/cmd/get_test.go b/pkg/kubectl/cmd/get_test.go index cba2498ca06..452ffd9ff8d 100644 --- a/pkg/kubectl/cmd/get_test.go +++ b/pkg/kubectl/cmd/get_test.go @@ -376,7 +376,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { }), } tf.Namespace = "test" - tf.ClientConfig = &client.Config{Version: "v1beta1"} + tf.ClientConfig = &client.Config{Version: testapi.Version()} buf := bytes.NewBuffer([]byte{}) cmd := NewCmdGet(f, buf) diff --git a/pkg/kubectl/cmd/label_test.go b/pkg/kubectl/cmd/label_test.go index 53f435efcd9..b6a654fa413 100644 --- a/pkg/kubectl/cmd/label_test.go +++ b/pkg/kubectl/cmd/label_test.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" ) @@ -291,7 +292,7 @@ func TestLabelErrors(t *testing.T) { f, tf, _ := NewAPIFactory() tf.Printer = &testPrinter{} tf.Namespace = "test" - tf.ClientConfig = &client.Config{Version: "v1beta1"} + tf.ClientConfig = &client.Config{Version: testapi.Version()} buf := bytes.NewBuffer([]byte{}) cmd := NewCmdLabel(f, buf) @@ -348,7 +349,7 @@ func TestLabelMultipleObjects(t *testing.T) { }), } tf.Namespace = "test" - tf.ClientConfig = &client.Config{Version: "v1beta1"} + tf.ClientConfig = &client.Config{Version: testapi.Version()} buf := bytes.NewBuffer([]byte{}) cmd := NewCmdLabel(f, buf) diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index db7455f65e2..7211d65f1ff 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -28,7 +28,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -150,11 +149,13 @@ func TestPrintYAML(t *testing.T) { func TestPrintTemplate(t *testing.T) { buf := bytes.NewBuffer([]byte{}) - printer, found, err := GetPrinter("template", "{{.id}}") + printer, found, err := GetPrinter("template", "{{if .id}}{{.id}}{{end}}{{if .metadata.name}}{{.metadata.name}}{{end}}") if err != nil || !found { t.Fatalf("unexpected error: %#v", err) } - err = printer.PrintObj(&v1beta1.Pod{TypeMeta: v1beta1.TypeMeta{ID: "foo"}}, buf) + unversionedPod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} + obj, err := api.Scheme.ConvertToVersion(unversionedPod, testapi.Version()) + err = printer.PrintObj(obj, buf) if err != nil { t.Fatalf("unexpected error: %#v", err) } @@ -289,7 +290,7 @@ func TestTemplateEmitsVersionedObjects(t *testing.T) { if err != nil { t.Fatalf("tmpl fail: %v", err) } - obj, err := api.Scheme.ConvertToVersion(&api.Pod{}, "v1beta1") + obj, err := api.Scheme.ConvertToVersion(&api.Pod{}, testapi.Version()) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/pkg/kubelet/config/common.go b/pkg/kubelet/config/common.go index f74084e3fe8..401af5d65e0 100644 --- a/pkg/kubelet/config/common.go +++ b/pkg/kubelet/config/common.go @@ -24,6 +24,7 @@ import ( "strings" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" @@ -77,12 +78,23 @@ func applyDefaults(pod *api.Pod, source string, isFile bool, hostname string) er // Set the Host field to indicate this pod is scheduled on the current node. pod.Spec.Host = hostname - // Currently just simply follow the same format in resthandler.go - pod.ObjectMeta.SelfLink = - fmt.Sprintf("/api/v1beta2/pods/%s?namespace=%s", pod.Name, pod.Namespace) + pod.ObjectMeta.SelfLink = getSelfLink(pod.Name, pod.Namespace) return nil } +func getSelfLink(name, namespace string) string { + var selfLink string + if api.PreV1Beta3(latest.Version) { + selfLink = fmt.Sprintf("/api/"+latest.Version+"/pods/%s?namespace=%s", name, namespace) + } else { + if len(namespace) == 0 { + namespace = api.NamespaceDefault + } + selfLink = fmt.Sprintf("/api/"+latest.Version+"/pods/namespaces/%s/%s", name, namespace) + } + return selfLink +} + type defaultFunc func(pod *api.Pod) error func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *api.Pod, err error) { diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index 9871e47fb34..851d34ab05d 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -18,6 +18,7 @@ package config import ( "encoding/json" + "fmt" "io/ioutil" "os" "sort" @@ -25,9 +26,11 @@ import ( "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" ) @@ -68,7 +71,11 @@ func writeTestFile(t *testing.T, dir, name string, contents string) *os.File { return file } -func TestReadFromFile(t *testing.T) { +func TestReadContainerManifestFromFile(t *testing.T) { + // ContainerManifest is supported only for pre v1beta3 versions. + if !api.PreV1Beta3(testapi.Version()) { + return + } hostname := "random-test-hostname" var testCases = []struct { desc string @@ -77,18 +84,18 @@ func TestReadFromFile(t *testing.T) { }{ { desc: "Manifest", - fileContents: `{ - "version": "v1beta1", + fileContents: fmt.Sprintf(`{ + "version": "%s", "uuid": "12345", "id": "test", "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] - }`, + }`, testapi.Version()), expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-" + hostname, UID: "12345", Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", + SelfLink: getSelfLink("test-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -104,17 +111,17 @@ func TestReadFromFile(t *testing.T) { }, { desc: "Manifest without ID", - fileContents: `{ - "version": "v1beta1", - "uuid": "12345", - "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] - }`, + fileContents: fmt.Sprintf(`{ + "version": "%s", + "uuid": "12345", + "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] + }`, testapi.Version()), expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "12345-" + hostname, UID: "12345", Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", + SelfLink: getSelfLink("12345-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -128,129 +135,6 @@ func TestReadFromFile(t *testing.T) { }, }), }, - { - desc: "Manifest v1beta2", - fileContents: `{ - "version": "v1beta2", - "uuid": "12345", - "id": "test", - "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] - }`, - expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{ - Host: hostname, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "image", - Image: "test/image", - TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always"}}, - }, - }), - }, - { - desc: "Simple pod", - fileContents: `{ - "kind": "Pod", - "apiVersion": "v1beta1", - "uid": "12345", - "id": "test", - "namespace": "mynamespace", - "desiredState": { - "manifest": { - "containers": [{ "name": "image", "image": "test/image" }] - } - } - }`, - expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: "mynamespace", - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=mynamespace", - }, - Spec: api.PodSpec{ - Host: hostname, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "image", - Image: "test/image", - TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent"}}, - }, - }), - }, - { - desc: "Pod without ID", - fileContents: `{ - "kind": "Pod", - "apiversion": "v1beta1", - "uid": "12345", - "desiredState": { - "manifest": { - "containers": [{ "name": "image", "image": "test/image" }] - } - } - }`, - expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "12345-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{ - Host: hostname, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "image", - Image: "test/image", - TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent"}}, - }, - }), - }, - { - desc: "Pod v1beta3", - fileContents: `{ - "kind": "Pod", - "apiversion": "v1beta3", - "metadata": { - "uid": "12345", - "name": "test" - }, - "spec": { - "containers": [{ "name": "image", "image": "test/image" }] - } - }`, - expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{ - Host: hostname, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "image", - Image: "test/image", - TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent"}}, - }, - }), - }, } for _, testCase := range testCases { @@ -278,13 +162,129 @@ func TestReadFromFile(t *testing.T) { } } +func TestReadPodsFromFile(t *testing.T) { + hostname := "random-test-hostname" + var testCases = []struct { + desc string + pod runtime.Object + expected kubelet.PodUpdate + }{ + { + desc: "Simple pod", + pod: &api.Pod{ + TypeMeta: api.TypeMeta{ + Kind: "Pod", + APIVersion: "", + }, + ObjectMeta: api.ObjectMeta{ + Name: "test", + UID: "12345", + Namespace: "mynamespace", + }, + Spec: api.PodSpec{ + Containers: []api.Container{{Name: "image", Image: "test/image"}}, + }, + }, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "test-" + hostname, + UID: "12345", + Namespace: "mynamespace", + SelfLink: getSelfLink("test-"+hostname, "mynamespace"), + }, + Spec: api.PodSpec{ + Host: hostname, + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "IfNotPresent"}}, + }, + }), + }, + { + desc: "Pod without ID", + pod: &api.Pod{ + TypeMeta: api.TypeMeta{ + Kind: "Pod", + APIVersion: "", + }, + ObjectMeta: api.ObjectMeta{ + // No name + UID: "12345", + }, + Spec: api.PodSpec{ + Containers: []api.Container{{Name: "image", Image: "test/image"}}, + }, + }, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "12345-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: getSelfLink("12345-"+hostname, kubelet.NamespaceDefault), + }, + Spec: api.PodSpec{ + Host: hostname, + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "IfNotPresent"}}, + }, + }), + }, + } + + for _, testCase := range testCases { + func() { + var versionedPod runtime.Object + err := testapi.Converter().Convert(&testCase.pod, &versionedPod) + if err != nil { + t.Fatalf("error in versioning the pod: %s", testCase.desc, err) + } + fileContents, err := testapi.Codec().Encode(versionedPod) + if err != nil { + t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err) + } + + file := writeTestFile(t, os.TempDir(), "test_pod_config", string(fileContents)) + defer os.Remove(file.Name()) + + ch := make(chan interface{}) + NewSourceFile(file.Name(), hostname, time.Millisecond, ch) + select { + case got := <-ch: + update := got.(kubelet.PodUpdate) + for _, pod := range update.Pods { + if errs := validation.ValidatePod(pod); len(errs) > 0 { + t.Errorf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs) + } + } + if !api.Semantic.DeepEqual(testCase.expected, update) { + t.Errorf("%s: Expected %#v, Got %#v", testCase.desc, testCase.expected, update) + } + case <-time.After(time.Second): + t.Errorf("%s: Expected update, timeout instead", testCase.desc) + } + }() + } +} + func TestReadManifestFromFileWithDefaults(t *testing.T) { + if !api.PreV1Beta3(testapi.Version()) { + return + } file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "version": "v1beta1", + fmt.Sprintf(`{ + "version": "%s", "id": "test", "containers": [{ "name": "image", "image": "test/image" }] - }`) + }`, testapi.Version())) defer os.Remove(file.Name()) ch := make(chan interface{}) @@ -335,7 +335,7 @@ func TestExtractFromEmptyDir(t *testing.T) { } } -func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) { +func exampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) { hostname := "an-example-host" manifest := v1beta1.ContainerManifest{ @@ -363,7 +363,7 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) { Name: id + "-" + hostname, UID: types.UID(id), Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/" + id + "-" + hostname + "?namespace=default", + SelfLink: getSelfLink(id+"-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -387,8 +387,11 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) { } func TestExtractFromDir(t *testing.T) { - manifest, expectedPod := ExampleManifestAndPod("1") - manifest2, expectedPod2 := ExampleManifestAndPod("2") + if !api.PreV1Beta3(testapi.Version()) { + return + } + manifest, expectedPod := exampleManifestAndPod("1") + manifest2, expectedPod2 := exampleManifestAndPod("2") manifests := []v1beta1.ContainerManifest{manifest, manifest2} pods := []*api.Pod{expectedPod, expectedPod2} diff --git a/pkg/kubelet/config/http_test.go b/pkg/kubelet/config/http_test.go index 0db1c826c7b..b1500dc771c 100644 --- a/pkg/kubelet/config/http_test.go +++ b/pkg/kubelet/config/http_test.go @@ -23,10 +23,11 @@ import ( "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" ) @@ -66,14 +67,14 @@ func TestExtractInvalidManifest(t *testing.T) { { desc: "Invalid volume name", manifests: []api.ContainerManifest{ - {Version: "v1beta1", Volumes: []api.Volume{{Name: "_INVALID_"}}}, + {Version: testapi.Version(), Volumes: []api.Volume{{Name: "_INVALID_"}}}, }, }, { desc: "Duplicate volume names", manifests: []api.ContainerManifest{ { - Version: "v1beta1", + Version: testapi.Version(), Volumes: []api.Volume{{Name: "repeated"}, {Name: "repeated"}}, }, }, @@ -82,7 +83,7 @@ func TestExtractInvalidManifest(t *testing.T) { desc: "Unspecified container name", manifests: []api.ContainerManifest{ { - Version: "v1beta1", + Version: testapi.Version(), Containers: []api.Container{{Name: ""}}, }, }, @@ -91,7 +92,7 @@ func TestExtractInvalidManifest(t *testing.T) { desc: "Invalid container name", manifests: []api.ContainerManifest{ { - Version: "v1beta1", + Version: testapi.Version(), Containers: []api.Container{{Name: "_INVALID_"}}, }, }, @@ -118,6 +119,10 @@ func TestExtractInvalidManifest(t *testing.T) { func TestExtractManifestFromHTTP(t *testing.T) { hostname := "random-hostname" + // ContainerManifests are not supported v1beta3 onwards. + if api.PreV1Beta3(testapi.Version()) { + return + } var testCases = []struct { desc string @@ -135,7 +140,8 @@ func TestExtractManifestFromHTTP(t *testing.T) { UID: "111", Name: "foo" + "-" + hostname, Namespace: "foobar", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -160,7 +166,8 @@ func TestExtractManifestFromHTTP(t *testing.T) { UID: "111", Name: "111" + "-" + hostname, Namespace: "foobar", - SelfLink: "/api/v1beta2/pods/111-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("111-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -185,7 +192,8 @@ func TestExtractManifestFromHTTP(t *testing.T) { UID: "111", Name: "foo" + "-" + hostname, Namespace: "foobar", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -214,7 +222,8 @@ func TestExtractManifestFromHTTP(t *testing.T) { UID: "111", Name: "foo" + "-" + hostname, Namespace: "foobar", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -232,7 +241,8 @@ func TestExtractManifestFromHTTP(t *testing.T) { UID: "222", Name: "bar" + "-" + hostname, Namespace: "foobar", - SelfLink: "/api/v1beta2/pods/bar-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -296,61 +306,24 @@ func TestExtractPodsFromHTTP(t *testing.T) { var testCases = []struct { desc string - pods interface{} + pods runtime.Object expected kubelet.PodUpdate }{ { - desc: "Single pod v1beta1", - pods: v1beta1.Pod{ - TypeMeta: v1beta1.TypeMeta{ + desc: "Single pod", + pods: &api.Pod{ + TypeMeta: api.TypeMeta{ Kind: "Pod", - APIVersion: "v1beta1", - ID: "foo", - UID: "111", - Namespace: "mynamespace", + APIVersion: "", }, - DesiredState: v1beta1.PodState{ - Manifest: v1beta1.ContainerManifest{ - Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}, - }, - }, - }, - expected: CreatePodUpdate(kubelet.SET, - kubelet.HTTPSource, - &api.Pod{ - ObjectMeta: api.ObjectMeta{ - UID: "111", - Name: "foo" + "-" + hostname, - Namespace: "mynamespace", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=mynamespace", - }, - Spec: api.PodSpec{ - Host: hostname, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "1", - Image: "foo", - TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always"}}, - }, - }), - }, - { - desc: "Single pod v1beta3", - pods: v1beta3.Pod{ - TypeMeta: v1beta3.TypeMeta{ - Kind: "Pod", - APIVersion: "v1beta3", - }, - ObjectMeta: v1beta3.ObjectMeta{ + ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "111", Namespace: "mynamespace", }, - Spec: v1beta3.PodSpec{ + Spec: api.PodSpec{ Host: hostname, - Containers: []v1beta3.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta3.PullAlways}}, + Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}}, }, }, expected: CreatePodUpdate(kubelet.SET, @@ -360,7 +333,8 @@ func TestExtractPodsFromHTTP(t *testing.T) { UID: "111", Name: "foo" + "-" + hostname, Namespace: "mynamespace", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=mynamespace", + + SelfLink: getSelfLink("foo-"+hostname, "mynamespace"), }, Spec: api.PodSpec{ Host: hostname, @@ -376,30 +350,30 @@ func TestExtractPodsFromHTTP(t *testing.T) { }, { desc: "Multiple pods", - pods: v1beta3.PodList{ - TypeMeta: v1beta3.TypeMeta{ + pods: &api.PodList{ + TypeMeta: api.TypeMeta{ Kind: "PodList", - APIVersion: "v1beta3", + APIVersion: "", }, - Items: []v1beta3.Pod{ + Items: []api.Pod{ { - ObjectMeta: v1beta3.ObjectMeta{ + ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "111", }, - Spec: v1beta3.PodSpec{ + Spec: api.PodSpec{ Host: hostname, - Containers: []v1beta3.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta3.PullAlways}}, + Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}}, }, }, { - ObjectMeta: v1beta3.ObjectMeta{ + ObjectMeta: api.ObjectMeta{ Name: "bar", UID: "222", }, - Spec: v1beta3.PodSpec{ + Spec: api.PodSpec{ Host: hostname, - Containers: []v1beta3.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}}, + Containers: []api.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}}, }, }, }, @@ -411,7 +385,8 @@ func TestExtractPodsFromHTTP(t *testing.T) { UID: "111", Name: "foo" + "-" + hostname, Namespace: "default", - SelfLink: "/api/v1beta2/pods/foo-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -429,7 +404,8 @@ func TestExtractPodsFromHTTP(t *testing.T) { UID: "222", Name: "bar" + "-" + hostname, Namespace: "default", - SelfLink: "/api/v1beta2/pods/bar-" + hostname + "?namespace=default", + + SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault), }, Spec: api.PodSpec{ Host: hostname, @@ -443,17 +419,17 @@ func TestExtractPodsFromHTTP(t *testing.T) { }, }), }, - { - desc: "Empty Array", - pods: []v1beta3.Pod{}, - expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource), - }, } for _, testCase := range testCases { - data, err := json.Marshal(testCase.pods) + var versionedPods runtime.Object + err := testapi.Converter().Convert(&testCase.pods, &versionedPods) if err != nil { - t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err) + t.Fatalf("error in versioning the pods: %s", testCase.desc, err) + } + data, err := testapi.Codec().Encode(versionedPods) + if err != nil { + t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err) } fakeHandler := util.FakeHandler{ StatusCode: 200, diff --git a/pkg/kubelet/container/ref_test.go b/pkg/kubelet/container/ref_test.go index d1f09742053..45c621f3225 100644 --- a/pkg/kubelet/container/ref_test.go +++ b/pkg/kubelet/container/ref_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" ) func TestFieldPath(t *testing.T) { @@ -65,14 +66,14 @@ func TestGenerateContainerRef(t *testing.T) { okPod = api.Pod{ TypeMeta: api.TypeMeta{ Kind: "Pod", - APIVersion: "v1beta1", + APIVersion: testapi.Version(), }, ObjectMeta: api.ObjectMeta{ Name: "ok", Namespace: "test-ns", UID: "bar", ResourceVersion: "42", - SelfLink: "/api/v1beta1/pods/foo", + SelfLink: "/api/" + testapi.Version() + "/pods/foo", }, Spec: api.PodSpec{ Containers: []api.Container{ @@ -89,7 +90,7 @@ func TestGenerateContainerRef(t *testing.T) { noSelfLinkPod.Kind = "" noSelfLinkPod.APIVersion = "" noSelfLinkPod.ObjectMeta.SelfLink = "" - defaultedSelfLinkPod.ObjectMeta.SelfLink = "/api/v1beta1/pods/ok" + defaultedSelfLinkPod.ObjectMeta.SelfLink = "/api/" + testapi.Version() + "/pods/ok" cases := []struct { name string @@ -106,7 +107,7 @@ func TestGenerateContainerRef(t *testing.T) { }, expected: &api.ObjectReference{ Kind: "Pod", - APIVersion: "v1beta1", + APIVersion: testapi.Version(), Name: "ok", Namespace: "test-ns", UID: "bar", @@ -121,7 +122,7 @@ func TestGenerateContainerRef(t *testing.T) { container: &api.Container{}, expected: &api.ObjectReference{ Kind: "Pod", - APIVersion: "v1beta1", + APIVersion: testapi.Version(), Name: "ok", Namespace: "test-ns", UID: "bar", @@ -145,7 +146,7 @@ func TestGenerateContainerRef(t *testing.T) { }, expected: &api.ObjectReference{ Kind: "Pod", - APIVersion: "v1beta1", + APIVersion: testapi.Version(), Name: "ok", Namespace: "test-ns", UID: "bar", @@ -162,7 +163,7 @@ func TestGenerateContainerRef(t *testing.T) { }, expected: &api.ObjectReference{ Kind: "Pod", - APIVersion: "v1beta1", + APIVersion: testapi.Version(), Name: "ok", Namespace: "test-ns", UID: "bar", diff --git a/pkg/service/endpoints_controller_test.go b/pkg/service/endpoints_controller_test.go index ade1ce34c79..c1769cd9f30 100644 --- a/pkg/service/endpoints_controller_test.go +++ b/pkg/service/endpoints_controller_test.go @@ -352,7 +352,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAll(t *testing.T) { Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, }) - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", ns, "foo"), "PUT", &data) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", ns, "foo"), "PUT", &data) } func TestSyncEndpointsItemsPreexisting(t *testing.T) { @@ -392,7 +392,7 @@ func TestSyncEndpointsItemsPreexisting(t *testing.T) { Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, }) - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", ns, "foo"), "PUT", &data) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", ns, "foo"), "PUT", &data) } func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) { @@ -421,7 +421,7 @@ func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) { }, }) endpoints.syncService(ns + "/foo") - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", api.NamespaceDefault, "foo"), "GET", nil) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", api.NamespaceDefault, "foo"), "GET", nil) } func TestSyncEndpointsItems(t *testing.T) { @@ -463,7 +463,7 @@ func TestSyncEndpointsItems(t *testing.T) { }) // endpointsHandler should get 2 requests - one for "GET" and the next for "POST". endpointsHandler.ValidateRequestCount(t, 2) - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", ns, ""), "POST", &data) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", ns, ""), "POST", &data) } func TestSyncEndpointsItemsWithLabels(t *testing.T) { @@ -510,7 +510,7 @@ func TestSyncEndpointsItemsWithLabels(t *testing.T) { }) // endpointsHandler should get 2 requests - one for "GET" and the next for "POST". endpointsHandler.ValidateRequestCount(t, 2) - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", ns, ""), "POST", &data) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", ns, ""), "POST", &data) } func TestSyncEndpointsItemsPreexistingLabelsChange(t *testing.T) { @@ -559,5 +559,5 @@ func TestSyncEndpointsItemsPreexistingLabelsChange(t *testing.T) { Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, }) - endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("endpoints", ns, "foo"), "PUT", &data) + endpointsHandler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("endpoints", ns, "foo"), "PUT", &data) } diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index a39bea0b1c6..6e5d7e12150 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -170,7 +170,7 @@ func TestDefaultErrorFunc(t *testing.T) { if !exists { continue } - handler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("pods", "bar", "foo"), "GET", nil) + handler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("pods", "bar", "foo"), "GET", nil) if e, a := testPod, got; !reflect.DeepEqual(e, a) { t.Errorf("Expected %v, got %v", e, a) } @@ -241,7 +241,7 @@ func TestBind(t *testing.T) { continue } expectedBody := runtime.EncodeOrDie(testapi.Codec(), item.binding) - handler.ValidateRequest(t, testapi.ResourcePathWithQueryParams("bindings", api.NamespaceDefault, ""), "POST", &expectedBody) + handler.ValidateRequest(t, testapi.ResourcePathWithNamespaceQuery("bindings", api.NamespaceDefault, ""), "POST", &expectedBody) } } diff --git a/test/integration/auth_test.go b/test/integration/auth_test.go index 34efdd05e0f..dd5da1e3e2d 100644 --- a/test/integration/auth_test.go +++ b/test/integration/auth_test.go @@ -78,8 +78,8 @@ func path(resource, namespace, name string) string { return testapi.ResourcePath(resource, namespace, name) } -func pathWithQuery(resource, namespace, name string) string { - return testapi.ResourcePathWithQueryParams(resource, namespace, name) +func pathWithNamespaceQuery(resource, namespace, name string) string { + return testapi.ResourcePathWithNamespaceQuery(resource, namespace, name) } func pathWithPrefix(prefix, resource, namespace, name string) string { @@ -90,8 +90,8 @@ func timeoutPath(resource, namespace, name string) string { return addTimeoutFlag(testapi.ResourcePath(resource, namespace, name)) } -func timeoutPathWithQuery(resource, namespace, name string) string { - return addTimeoutFlag(testapi.ResourcePathWithQueryParams(resource, namespace, name)) +func timeoutPathWithNamespaceQuery(resource, namespace, name string) string { + return addTimeoutFlag(testapi.ResourcePathWithNamespaceQuery(resource, namespace, name)) } // Bodies for requests used in subsequent tests. @@ -848,15 +848,15 @@ func TestNamespaceAuthorization(t *testing.T) { statusCodes map[int]bool // allowed status codes. }{ - {"POST", timeoutPathWithQuery("pods", "foo", ""), "foo", aPod, code201}, - {"GET", pathWithQuery("pods", "foo", ""), "foo", "", code200}, - {"GET", pathWithQuery("pods", "foo", "a"), "foo", "", code200}, - {"DELETE", timeoutPathWithQuery("pods", "foo", "a"), "foo", "", code200}, + {"POST", timeoutPathWithNamespaceQuery("pods", "foo", ""), "foo", aPod, code201}, + {"GET", pathWithNamespaceQuery("pods", "foo", ""), "foo", "", code200}, + {"GET", pathWithNamespaceQuery("pods", "foo", "a"), "foo", "", code200}, + {"DELETE", timeoutPathWithNamespaceQuery("pods", "foo", "a"), "foo", "", code200}, {"POST", timeoutPath("pods", "bar", ""), "bar", aPod, code403}, - {"GET", pathWithQuery("pods", "bar", ""), "bar", "", code403}, - {"GET", pathWithQuery("pods", "bar", "a"), "bar", "", code403}, - {"DELETE", timeoutPathWithQuery("pods", "bar", "a"), "bar", "", code403}, + {"GET", pathWithNamespaceQuery("pods", "bar", ""), "bar", "", code403}, + {"GET", pathWithNamespaceQuery("pods", "bar", "a"), "bar", "", code403}, + {"DELETE", timeoutPathWithNamespaceQuery("pods", "bar", "a"), "bar", "", code403}, {"POST", timeoutPath("pods", api.NamespaceDefault, ""), "", aPod, code403}, {"GET", path("pods", "", ""), "", "", code403},