Make kubectl proxy support picking a random port

This commit is contained in:
Jeff Lowdermilk 2015-07-06 22:04:39 -07:00
parent 74b78d537d
commit f71a662dc6
5 changed files with 36 additions and 13 deletions

View File

@ -60,7 +60,7 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods'
.PP
\fB\-p\fP, \fB\-\-port\fP=8001
The port on which to run the proxy.
The port on which to run the proxy. Set to 0 to pick a random port.
.PP
\fB\-\-reject\-methods\fP="POST,PUT,PATCH"
@ -185,6 +185,10 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods'
// Run a proxy to kubernetes apiserver on port 8011, serving static content from ./local/www/
$ kubectl proxy \-\-port=8011 \-\-www=./local/www/
// Run a proxy to kubernetes apiserver on an arbitrary local port.
// The chosen port for the server will be output to stdout.
$ kubectl proxy \-\-port=0
// Run a proxy to kubernetes apiserver, changing the api prefix to k8s\-api
// This makes e.g. the pods api available at localhost:8011/k8s\-api/v1/pods/
$ kubectl proxy \-\-api\-prefix=/k8s\-api

View File

@ -65,6 +65,10 @@ kubectl proxy [--port=PORT] [--www=static-dir] [--www-prefix=prefix] [--api-pref
// Run a proxy to kubernetes apiserver on port 8011, serving static content from ./local/www/
$ kubectl proxy --port=8011 --www=./local/www/
// Run a proxy to kubernetes apiserver on an arbitrary local port.
// The chosen port for the server will be output to stdout.
$ kubectl proxy --port=0
// Run a proxy to kubernetes apiserver, changing the api prefix to k8s-api
// This makes e.g. the pods api available at localhost:8011/k8s-api/v1/pods/
$ kubectl proxy --api-prefix=/k8s-api
@ -78,7 +82,7 @@ $ kubectl proxy --api-prefix=/k8s-api
--api-prefix="/api/": Prefix to serve the proxied API under.
--disable-filter=false: If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks. Use with caution.
-h, --help=false: help for proxy
-p, --port=8001: The port on which to run the proxy.
-p, --port=8001: The port on which to run the proxy. Set to 0 to pick a random port.
--reject-methods="POST,PUT,PATCH": Regular expression for HTTP methods that the proxy should reject.
--reject-paths="^/api/.*/exec,^/api/.*/run": Regular expression for paths that the proxy should reject.
-w, --www="": Also serve static files from the given directory under the specified prefix.

View File

@ -31,6 +31,10 @@ const (
proxy_example = `// Run a proxy to kubernetes apiserver on port 8011, serving static content from ./local/www/
$ kubectl proxy --port=8011 --www=./local/www/
// Run a proxy to kubernetes apiserver on an arbitrary local port.
// The chosen port for the server will be output to stdout.
$ kubectl proxy --port=0
// Run a proxy to kubernetes apiserver, changing the api prefix to k8s-api
// This makes e.g. the pods api available at localhost:8011/k8s-api/v1/pods/
$ kubectl proxy --api-prefix=/k8s-api`
@ -69,14 +73,13 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods'
cmd.Flags().String("reject-paths", kubectl.DefaultPathRejectRE, "Regular expression for paths that the proxy should reject.")
cmd.Flags().String("accept-hosts", kubectl.DefaultHostAcceptRE, "Regular expression for hosts that the proxy should accept.")
cmd.Flags().String("reject-methods", kubectl.DefaultMethodRejectRE, "Regular expression for HTTP methods that the proxy should reject.")
cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy.")
cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy. Set to 0 to pick a random port.")
cmd.Flags().Bool("disable-filter", false, "If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks. Use with caution.")
return cmd
}
func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
port := cmdutil.GetFlagInt(cmd, "port")
fmt.Fprintf(out, "Starting to serve on localhost:%d", port)
clientConfig, err := f.ClientConfig()
if err != nil {
@ -102,11 +105,18 @@ func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
filter = nil
}
server, err := kubectl.NewProxyServer(cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig)
server, err := kubectl.NewProxyServer(port, cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig)
if err != nil {
return err
}
glog.Fatal(server.Serve(port))
// Separate listening from serving so we can report the bound port
// when it is chosen by os (port == 0)
l, err := server.Listen()
if err != nil {
glog.Fatal(err)
}
fmt.Fprintf(out, "Starting to serve on %s", l.Addr().String())
glog.Fatal(server.ServeOnListener(l))
return nil
}

View File

@ -139,12 +139,13 @@ func (f *FilterServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// ProxyServer is a http.Handler which proxies Kubernetes APIs to remote API server.
type ProxyServer struct {
handler http.Handler
port int
}
// NewProxyServer creates and installs a new ProxyServer.
// It automatically registers the created ProxyServer to http.DefaultServeMux.
// 'filter', if non-nil, protects requests to the api only.
func NewProxyServer(filebase string, apiProxyPrefix string, staticPrefix string, filter *FilterServer, cfg *client.Config) (*ProxyServer, error) {
func NewProxyServer(port int, filebase string, apiProxyPrefix string, staticPrefix string, filter *FilterServer, cfg *client.Config) (*ProxyServer, error) {
host := cfg.Host
if !strings.HasSuffix(host, "/") {
host = host + "/"
@ -173,16 +174,20 @@ func NewProxyServer(filebase string, apiProxyPrefix string, staticPrefix string,
// serving their working directory by default.
mux.Handle(staticPrefix, newFileHandler(staticPrefix, filebase))
}
return &ProxyServer{handler: mux}, nil
return &ProxyServer{handler: mux, port: port}, nil
}
// Serve starts the server (http.DefaultServeMux) on given port, loops forever.
func (s *ProxyServer) Serve(port int) error {
// Listen is a simple wrapper around net.Listen.
func (s *ProxyServer) Listen() (net.Listener, error) {
return net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", s.port))
}
// Serve starts the server using given listener, loops forever.
func (s *ProxyServer) ServeOnListener(l net.Listener) error {
server := http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: s.handler,
}
return server.ListenAndServe()
return server.Serve(l)
}
func newProxy(target *url.URL) *httputil.ReverseProxy {

View File

@ -287,7 +287,7 @@ func TestPathHandling(t *testing.T) {
for _, item := range table {
func() {
p, err := NewProxyServer("", item.prefix, "/not/used/for/this/test", nil, cc)
p, err := NewProxyServer(0, "", item.prefix, "/not/used/for/this/test", nil, cc)
if err != nil {
t.Fatalf("%#v: %v", item, err)
}