Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add port-forwarding example #51

Closed
gtaylor opened this issue Dec 12, 2016 · 9 comments
Closed

Add port-forwarding example #51

gtaylor opened this issue Dec 12, 2016 · 9 comments
Labels
kind/support Categorizes issue or PR as a support question.

Comments

@gtaylor
Copy link

gtaylor commented Dec 12, 2016

This would be really helpful, as I'm coming from another language. In particular, how to come about the dialer param here:

func New(dialer httpstream.Dialer, ports []string, stopChan <-chan struct{}, readyChan chan struct{}, out, errOut io.Writer) (*PortForwarder, error) {

@caesarxuchao
Copy link
Member

You can take a look at how kubectl use the equivalent packages in the main repo: https://github.com/kubernetes/kubernetes/blob/v1.6.0-alpha.0/pkg/kubectl/cmd/portforward.go#L107

@WilliamDenniss WilliamDenniss added the kind/support Categorizes issue or PR as a support question. label Mar 15, 2017
@ngtuna
Copy link

ngtuna commented Nov 29, 2017

This is still unclear. Did you mean we shouldn't use client-go to execute a port-forward ? @caesarxuchao

@esimonov
Copy link

esimonov commented Nov 6, 2018

@gtaylor Please try this to obtain the dialer :

import(
        "flag"
	"fmt"
	"os"
	"path/filepath"
        "net/http"
	"net/url"
        "strings"

        "k8s.io/client-go/tools/clientcmd"
        "k8s.io/client-go/tools/portforward"
        "k8s.io/client-go/transport/spdy"
        "k8s.io/client-go/util/homedir"
)

...

var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
	kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
	kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()

config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
	panic(err)
}
roundTripper, upgrader, err := spdy.RoundTripperFor(config)
if err != nil {
	panic(err)
}

path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward", "default", podName)
hostIP := strings.TrimLeft(config.Host, "htps:/")
serverURL := url.URL{Scheme: "https", Path: path, Host: hostIP}

dialer := spdy.NewDialer(upgrader, &http.Client{Transport: roundTripper}, http.MethodPost, &serverURL)

What about stopChan, readyChan, out and errOut, you can initialize them like this:

import "bytes"

stopChan, readyChan := make(chan struct{}, 1), make(chan struct{}, 1)
out, errOut := new(bytes.Buffer), new(bytes.Buffer)

The usage is following (with error handling simplified, you would probably want to add more context to the error messages, and/or use log messages instead of panics):

forwarder, err := portforward.New(dialer, ports, stopChan, readyChan, out, errOut)
if err != nil {
	panic(err)
}

go func() {
	for range readyChan { // Kubernetes will close this channel when it has something to tell us.
	}
	if len(errOut.String()) != 0 {
		panic(errOut.String())
	} else if len(out.String()) != 0 {
		fmt.Println(out.String())
	}
}()

if err = forwarder.ForwardPorts(); err != nil { // Locks until stopChan is closed.
	panic(err)
}

Just close the stopChan when you don't need this connection anymore.

@h-abinaya28
Copy link

I am getting an error while trying the above code as error upgrading connection: resource "test" not found

@EronWright
Copy link

@MarcosCela
Copy link

recommended read: #796 if you find any dataraces. I used the safe buffer implementation for the following gist:

@anthhub
Copy link

anthhub commented May 23, 2021

how to forward for service?

@anthhub
Copy link

anthhub commented Jul 28, 2021

Hi, I made a library with example forwarding service or pods! You can see the repo: 😬 https://github.com/anthhub/forwarder

@Svintooo
Copy link

Svintooo commented Sep 8, 2023

Code example given above contains a bug.

// All hosts starting with any of the letters 'h', 'p', 's', or 't', will be erroneously truncated.
hostIP := strings.TrimLeft(config.Host, "htps:/")
// Ex: "http://stamp-high.com"
// ->           "amp-high.com"

Solutions I found:

// Solution 1
hostIP := strings.TrimPrefix(strings.TrimPrefix(config.Host, "http://"), "https://")

// Solution 2
var regexURLScheme = regexp.MustCompile(`(?i)^https?://`)
hostIP := regexURLScheme.ReplaceAllString(config.Host, "")

// Solution 3
hostURL, err := url.Parse(config.Host)
if err != nil {
	panic(err)
}
hostIP := hostURL.Host

I am posting here since I suspect others might end up here while searching for a solution.
I am sorry if this is the wrong place to do it.

Searching github for 'TrimLeft "htps:/"' gives me over 100+ results, so the bug seems somewhat widely spread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/support Categorizes issue or PR as a support question.
Projects
None yet
Development

No branches or pull requests

10 participants