Merge pull request #73676 from martin-helmich/bugfix/expose-forwarded-local-port

client-go: Dynamically assigned local port number not retrievable when port-forwarding

Kubernetes-commit: 38a325250fbefa8785740d00358978eefa160dde
This commit is contained in:
Kubernetes Publisher 2019-02-26 20:55:12 -08:00
commit 269fa37ba0
3 changed files with 131 additions and 54 deletions

104
Godeps/Godeps.json generated
View File

@ -1,7 +1,7 @@
{
"ImportPath": "k8s.io/client-go",
"GoVersion": "go1.11",
"GodepVersion": "v80-k8s-r1",
"GodepVersion": "v80",
"Packages": [
"./..."
],
@ -412,207 +412,207 @@
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/fuzzer",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/roundtrip",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/naming",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "f951fa7b8c72cf726656de66d834a518359ce6e7"
"Rev": "dcb391cde5ca0298013d43336817d20b74650702"
},
{
"ImportPath": "k8s.io/klog",

View File

@ -205,8 +205,9 @@ func (pf *PortForwarder) forward() error {
var err error
listenSuccess := false
for _, port := range pf.ports {
err = pf.listenOnPort(&port)
for i := range pf.ports {
port := &pf.ports[i]
err = pf.listenOnPort(port)
switch {
case err == nil:
listenSuccess = true

View File

@ -18,11 +18,13 @@ package portforward
import (
"net"
"net/http"
"os"
"reflect"
"sort"
"strings"
"testing"
"time"
"k8s.io/apimachinery/pkg/util/httpstream"
)
@ -39,6 +41,37 @@ func (d *fakeDialer) Dial(protocols ...string) (httpstream.Connection, string, e
return d.conn, d.negotiatedProtocol, d.err
}
type fakeConnection struct {
closed bool
closeChan chan bool
}
func newFakeConnection() httpstream.Connection {
return &fakeConnection{
closeChan: make(chan bool),
}
}
func (c *fakeConnection) CreateStream(headers http.Header) (httpstream.Stream, error) {
return nil, nil
}
func (c *fakeConnection) Close() error {
if !c.closed {
c.closed = true
close(c.closeChan)
}
return nil
}
func (c *fakeConnection) CloseChan() <-chan bool {
return c.closeChan
}
func (c *fakeConnection) SetIdleTimeout(timeout time.Duration) {
// no-op
}
func TestParsePortsAndNew(t *testing.T) {
tests := []struct {
input []string
@ -310,3 +343,46 @@ func TestGetListener(t *testing.T) {
}
}
func TestGetPortsReturnsDynamicallyAssignedLocalPort(t *testing.T) {
dialer := &fakeDialer{
conn: newFakeConnection(),
}
stopChan := make(chan struct{})
readyChan := make(chan struct{})
errChan := make(chan error)
defer func() {
close(stopChan)
forwardErr := <-errChan
if forwardErr != nil {
t.Fatalf("ForwardPorts returned error: %s", forwardErr)
}
}()
pf, err := New(dialer, []string{":5000"}, stopChan, readyChan, os.Stdout, os.Stderr)
if err != nil {
t.Fatalf("error while calling New: %s", err)
}
go func() {
errChan <- pf.ForwardPorts()
close(errChan)
}()
<-pf.Ready
ports, err := pf.GetPorts()
if len(ports) != 1 {
t.Fatalf("expected 1 port, got %d", len(ports))
}
port := ports[0]
if port.Local == 0 {
t.Fatalf("local port is 0, expected != 0")
}
}