Add streaming command execution & port forwarding
Add streaming command execution & port forwarding via HTTP connection upgrades (currently using SPDY).
This commit is contained in:
@@ -18,6 +18,7 @@ package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
@@ -40,6 +41,7 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
watchjson "github.com/GoogleCloudPlatform/kubernetes/pkg/watch/json"
|
||||
)
|
||||
@@ -151,16 +153,22 @@ func TestRequestParam(t *testing.T) {
|
||||
if !api.Semantic.DeepDerivative(r.params, url.Values{"foo": []string{"a"}}) {
|
||||
t.Errorf("should have set a param: %#v", r)
|
||||
}
|
||||
|
||||
r.Param("bar", "1")
|
||||
r.Param("bar", "2")
|
||||
if !api.Semantic.DeepDerivative(r.params, url.Values{"foo": []string{"a"}, "bar": []string{"1", "2"}}) {
|
||||
t.Errorf("should have set a param: %#v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestURI(t *testing.T) {
|
||||
r := (&Request{}).Param("foo", "a")
|
||||
r.Prefix("other")
|
||||
r.RequestURI("/test?foo=b&a=b")
|
||||
r.RequestURI("/test?foo=b&a=b&c=1&c=2")
|
||||
if r.path != "/test" {
|
||||
t.Errorf("path is wrong: %#v", r)
|
||||
}
|
||||
if !api.Semantic.DeepDerivative(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}}) {
|
||||
if !api.Semantic.DeepDerivative(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) {
|
||||
t.Errorf("should have set a param: %#v", r)
|
||||
}
|
||||
}
|
||||
@@ -443,6 +451,122 @@ func TestRequestStream(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type fakeUpgradeConnection struct{}
|
||||
|
||||
func (c *fakeUpgradeConnection) CreateStream(headers http.Header) (httpstream.Stream, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (c *fakeUpgradeConnection) Close() error {
|
||||
return nil
|
||||
}
|
||||
func (c *fakeUpgradeConnection) CloseChan() <-chan bool {
|
||||
return make(chan bool)
|
||||
}
|
||||
func (c *fakeUpgradeConnection) SetIdleTimeout(timeout time.Duration) {
|
||||
}
|
||||
|
||||
type fakeUpgradeRoundTripper struct {
|
||||
req *http.Request
|
||||
conn httpstream.Connection
|
||||
}
|
||||
|
||||
func (f *fakeUpgradeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
f.req = req
|
||||
b := []byte{}
|
||||
body := ioutil.NopCloser(bytes.NewReader(b))
|
||||
resp := &http.Response{
|
||||
StatusCode: 101,
|
||||
Body: body,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (f *fakeUpgradeRoundTripper) NewConnection(resp *http.Response) (httpstream.Connection, error) {
|
||||
return f.conn, nil
|
||||
}
|
||||
|
||||
func TestRequestUpgrade(t *testing.T) {
|
||||
uri, _ := url.Parse("http://localhost/")
|
||||
testCases := []struct {
|
||||
Request *Request
|
||||
Config *Config
|
||||
RoundTripper *fakeUpgradeRoundTripper
|
||||
Err bool
|
||||
AuthBasicHeader bool
|
||||
AuthBearerHeader bool
|
||||
}{
|
||||
{
|
||||
Request: &Request{err: errors.New("bail")},
|
||||
Err: true,
|
||||
},
|
||||
{
|
||||
Request: &Request{},
|
||||
Config: &Config{
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
CAFile: "foo",
|
||||
},
|
||||
Insecure: true,
|
||||
},
|
||||
Err: true,
|
||||
},
|
||||
{
|
||||
Request: &Request{},
|
||||
Config: &Config{
|
||||
Username: "u",
|
||||
Password: "p",
|
||||
BearerToken: "b",
|
||||
},
|
||||
Err: true,
|
||||
},
|
||||
{
|
||||
Request: NewRequest(nil, "", uri, testapi.Codec(), true, true),
|
||||
Config: &Config{
|
||||
Username: "u",
|
||||
Password: "p",
|
||||
},
|
||||
AuthBasicHeader: true,
|
||||
Err: false,
|
||||
},
|
||||
{
|
||||
Request: NewRequest(nil, "", uri, testapi.Codec(), true, true),
|
||||
Config: &Config{
|
||||
BearerToken: "b",
|
||||
},
|
||||
AuthBearerHeader: true,
|
||||
Err: false,
|
||||
},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
r := testCase.Request
|
||||
rt := &fakeUpgradeRoundTripper{}
|
||||
expectedConn := &fakeUpgradeConnection{}
|
||||
conn, err := r.Upgrade(testCase.Config, func(config *tls.Config) httpstream.UpgradeRoundTripper {
|
||||
rt.conn = expectedConn
|
||||
return rt
|
||||
})
|
||||
_ = conn
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, r.err)
|
||||
}
|
||||
if testCase.Err {
|
||||
continue
|
||||
}
|
||||
|
||||
if testCase.AuthBasicHeader && !strings.Contains(rt.req.Header.Get("Authorization"), "Basic") {
|
||||
t.Errorf("%d: expected basic auth header, got: %s", rt.req.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
if testCase.AuthBearerHeader && !strings.Contains(rt.req.Header.Get("Authorization"), "Bearer") {
|
||||
t.Errorf("%d: expected bearer auth header, got: %s", rt.req.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
if e, a := expectedConn, conn; e != a {
|
||||
t.Errorf("%d: conn: expected %#v, got %#v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestDo(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Request *Request
|
||||
|
Reference in New Issue
Block a user