mirror of https://github.com/helm/helm
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
1.8 KiB
95 lines
1.8 KiB
package kube
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
|
|
"k8s.io/kubernetes/pkg/client/unversioned/portforward"
|
|
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
|
)
|
|
|
|
// Tunnel describes a ssh-like tunnel to a kubernetes pod
|
|
type Tunnel struct {
|
|
Local int
|
|
Remote int
|
|
stopChan chan struct{}
|
|
}
|
|
|
|
// Close disconnects a tunnel connection
|
|
func (t *Tunnel) Close() {
|
|
close(t.stopChan)
|
|
}
|
|
|
|
// ForwardPort opens a tunnel to a kubernetes pod
|
|
func (c *Client) ForwardPort(namespace, podName string, remote int) (*Tunnel, error) {
|
|
client, err := c.Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config, err := c.ClientConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Build a url to the portforward endpoing
|
|
// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-rc-9itlq/portforward
|
|
u := client.RESTClient.Post().
|
|
Resource("pods").
|
|
Namespace(namespace).
|
|
Name(podName).
|
|
SubResource("portforward").URL()
|
|
|
|
dialer, err := remotecommand.NewExecutor(config, "POST", u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
local, err := getAvailablePort()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
t := &Tunnel{
|
|
Local: local,
|
|
Remote: remote,
|
|
stopChan: make(chan struct{}, 1),
|
|
}
|
|
|
|
ports := []string{fmt.Sprintf("%d:%d", local, remote)}
|
|
|
|
var b bytes.Buffer
|
|
pf, err := portforward.New(dialer, ports, t.stopChan, &b, &b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
go func() {
|
|
if err := pf.ForwardPorts(); err != nil {
|
|
fmt.Printf("Error forwarding ports: %v\n", err)
|
|
}
|
|
}()
|
|
|
|
// wait for listeners to start
|
|
<-pf.Ready
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func getAvailablePort() (int, error) {
|
|
l, err := net.Listen("tcp", ":0")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer l.Close()
|
|
|
|
_, p, err := net.SplitHostPort(l.Addr().String())
|
|
port, err := strconv.Atoi(p)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return port, err
|
|
}
|