diff --git a/test/e2e/proxy.go b/test/e2e/proxy.go
index 8ec1d962dd5..4a04ffec056 100644
--- a/test/e2e/proxy.go
+++ b/test/e2e/proxy.go
@@ -18,7 +18,9 @@ package e2e
import (
"fmt"
+ "net/http"
"strings"
+ "sync"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
@@ -37,52 +39,23 @@ var _ = Describe("Proxy", func() {
}
})
+const (
+ // Try all the proxy tests this many times (to catch even rare flakes).
+ proxyAttempts = 20
+ // Only print this many characters of the response (to keep the logs
+ // legible).
+ maxDisplayBodyLen = 100
+)
+
func proxyContext(version string) {
f := NewFramework("proxy")
prefix := "/api/" + version
- It("should proxy logs on node with explicit kubelet port", func() {
- node, err := pickNode(f.Client)
- Expect(err).NotTo(HaveOccurred())
- // AbsPath preserves the trailing '/'.
- body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + ":10250/logs/").Do().Raw()
- if len(body) > 0 {
- if len(body) > 100 {
- body = body[:100]
- body = append(body, '.', '.', '.')
- }
- Logf("Got: %s", body)
- }
- Expect(err).NotTo(HaveOccurred())
- })
+ It("should proxy logs on node with explicit kubelet port", func() { nodeProxyTest(f, version, ":10250/logs/") })
- It("should proxy logs on node", func() {
- node, err := pickNode(f.Client)
- Expect(err).NotTo(HaveOccurred())
- body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + "/logs/").Do().Raw()
- if len(body) > 0 {
- if len(body) > 100 {
- body = body[:100]
- body = append(body, '.', '.', '.')
- }
- Logf("Got: %s", body)
- }
- Expect(err).NotTo(HaveOccurred())
- })
+ It("should proxy logs on node", func() { nodeProxyTest(f, version, "/logs/") })
- It("should proxy to cadvisor", func() {
- node, err := pickNode(f.Client)
- Expect(err).NotTo(HaveOccurred())
- body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + ":4194/containers/").Do().Raw()
- if len(body) > 0 {
- if len(body) > 100 {
- body = body[:100]
- body = append(body, '.', '.', '.')
- }
- Logf("Got: %s", body)
- }
- Expect(err).NotTo(HaveOccurred())
- })
+ It("should proxy to cadvisor", func() { nodeProxyTest(f, version, ":4194/containers/") })
It("should proxy through a service and a pod", func() {
labels := map[string]string{"proxy-service-target": "true"}
@@ -118,13 +91,13 @@ func proxyContext(version string) {
pods := []*api.Pod{}
cfg := RCConfig{
Client: f.Client,
- Image: "gcr.io/google_containers/porter:91d46193649807d1340b46797774d8b2",
+ Image: "gcr.io/google_containers/porter:59ad46ed2c56ba50fa7f1dc176c07c37",
Name: service.Name,
Namespace: f.Namespace.Name,
Replicas: 1,
PollInterval: time.Second,
Env: map[string]string{
- "SERVE_PORT_80": "not accessible via service",
+ "SERVE_PORT_80": `test`,
"SERVE_PORT_160": "foo",
"SERVE_PORT_162": "bar",
},
@@ -144,11 +117,11 @@ func proxyContext(version string) {
svcPrefix := prefix + "/proxy/namespaces/" + f.Namespace.Name + "/services/" + service.Name
podPrefix := prefix + "/proxy/namespaces/" + f.Namespace.Name + "/pods/" + pods[0].Name
expectations := map[string]string{
- svcPrefix + ":portname1": "foo",
- svcPrefix + ":portname2": "bar",
- podPrefix + ":80": "not accessible via service",
- podPrefix + ":160": "foo",
- podPrefix + ":162": "bar",
+ svcPrefix + ":portname1/": "foo",
+ svcPrefix + ":portname2/": "bar",
+ podPrefix + ":80/": `test`,
+ podPrefix + ":160/": "foo",
+ podPrefix + ":162/": "bar",
// TODO: below entries don't work, but I believe we should make them work.
// svcPrefix + ":80": "foo",
// svcPrefix + ":81": "bar",
@@ -156,17 +129,38 @@ func proxyContext(version string) {
// podPrefix + ":dest2": "bar",
}
+ wg := sync.WaitGroup{}
errors := []string{}
- for path, val := range expectations {
- body, err := f.Client.Get().AbsPath(path).Do().Raw()
- if err != nil {
- errors = append(errors, fmt.Sprintf("path %v gave error %v", path, err))
- continue
- }
- if e, a := val, string(body); e != a {
- errors = append(errors, fmt.Sprintf("path %v: wanted %v, got %v", path, e, a))
+ errLock := sync.Mutex{}
+ recordError := func(s string) {
+ errLock.Lock()
+ defer errLock.Unlock()
+ errors = append(errors, s)
+ }
+ for i := 0; i < proxyAttempts; i++ {
+ for path, val := range expectations {
+ wg.Add(1)
+ go func(i int, path, val string) {
+ defer wg.Done()
+ body, status, d, err := doProxy(f, path)
+ if err != nil {
+ recordError(fmt.Sprintf("%v: path %v gave error: %v", i, path, err))
+ return
+ }
+ if status != http.StatusOK {
+ recordError(fmt.Sprintf("%v: path %v gave status: %v", i, path, status))
+ }
+ if e, a := val, string(body); e != a {
+ recordError(fmt.Sprintf("%v: path %v: wanted %v, got %v", i, path, e, a))
+ }
+ if d > 15*time.Second {
+ recordError(fmt.Sprintf("%v: path %v took %v > 15s", i, path, d))
+ }
+ }(i, path, val)
+ time.Sleep(150 * time.Millisecond)
}
}
+ wg.Wait()
if len(errors) != 0 {
Fail(strings.Join(errors, "\n"))
@@ -174,6 +168,31 @@ func proxyContext(version string) {
})
}
+func doProxy(f *Framework, path string) (body []byte, statusCode int, d time.Duration, err error) {
+ // About all of the proxy accesses in this file:
+ // * AbsPath is used because it preserves the trailing '/'.
+ // * Do().Raw() is used (instead of DoRaw()) because it will turn an
+ // error from apiserver proxy into an actual error, and there is no
+ // chance of the things we are talking to being confused for an error
+ // that apiserver would have emitted.
+ start := time.Now()
+ body, err = f.Client.Get().AbsPath(path).Do().StatusCode(&statusCode).Raw()
+ d = time.Since(start)
+ if len(body) > 0 {
+ Logf("%v: %s (%v; %v)", path, truncate(body, maxDisplayBodyLen), statusCode, d)
+ }
+ return
+}
+
+func truncate(b []byte, maxLen int) []byte {
+ if len(b) <= maxLen-3 {
+ return b
+ }
+ b2 := append([]byte(nil), b[:maxLen-3]...)
+ b2 = append(b2, '.', '.', '.')
+ return b2
+}
+
func pickNode(c *client.Client) (string, error) {
nodes, err := c.Nodes().List(labels.Everything(), fields.Everything())
if err != nil {
@@ -184,3 +203,15 @@ func pickNode(c *client.Client) (string, error) {
}
return nodes.Items[0].Name, nil
}
+
+func nodeProxyTest(f *Framework, version, nodeDest string) {
+ prefix := "/api/" + version
+ node, err := pickNode(f.Client)
+ Expect(err).NotTo(HaveOccurred())
+ for i := 0; i < proxyAttempts; i++ {
+ _, status, d, err := doProxy(f, prefix+"/proxy/nodes/"+node+nodeDest)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(status).To(Equal(http.StatusOK))
+ Expect(d).To(BeNumerically("<", 15*time.Second))
+ }
+}