diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 49ade9490bd..e77d86d05c9 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -99,7 +99,7 @@ func NewAPIServer() *APIServer { RuntimeConfig: make(util.ConfigurationMap), KubeletConfig: client.KubeletConfig{ Port: 10250, - EnableHttps: false, + EnableHttps: true, HTTPTimeout: time.Duration(5) * time.Second, }, } diff --git a/cmd/kube-controller-manager/app/controllermanager.go b/cmd/kube-controller-manager/app/controllermanager.go index 13a94d8c2fa..1eecd81ee5b 100644 --- a/cmd/kube-controller-manager/app/controllermanager.go +++ b/cmd/kube-controller-manager/app/controllermanager.go @@ -83,7 +83,7 @@ func NewCMServer() *CMServer { SyncNodeStatus: false, KubeletConfig: client.KubeletConfig{ Port: ports.KubeletPort, - EnableHttps: false, + EnableHttps: true, HTTPTimeout: time.Duration(5) * time.Second, }, } diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index c92b9b4deda..a3d0b56976d 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -139,14 +139,7 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container) error { // TODO: Convert to go-restful func InstallValidator(mux Mux, servers func() map[string]Server) { - validator, err := NewValidator(servers) - if err != nil { - glog.Errorf("failed to set up validator: %v", err) - return - } - if validator != nil { - mux.Handle("/validate", validator) - } + mux.Handle("/validate", NewValidator(servers)) } // TODO: document all handlers diff --git a/pkg/apiserver/validator.go b/pkg/apiserver/validator.go index 037204a540f..368ea66d67f 100644 --- a/pkg/apiserver/validator.go +++ b/pkg/apiserver/validator.go @@ -17,6 +17,7 @@ limitations under the License. package apiserver import ( + "crypto/tls" "encoding/json" "fmt" "io/ioutil" @@ -34,21 +35,26 @@ type httpGet interface { } type Server struct { - Addr string - Port int - Path string + Addr string + Port int + Path string + EnableHTTPS bool } // validator is responsible for validating the cluster and serving type validator struct { // a list of servers to health check servers func() map[string]Server - client httpGet + rt http.RoundTripper } // TODO: can this use pkg/probe/http func (s *Server) check(client httpGet) (probe.Result, string, error) { - resp, err := client.Get("http://" + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path) + scheme := "http://" + if s.EnableHTTPS { + scheme = "https://" + } + resp, err := client.Get(scheme + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path) if err != nil { return probe.Unknown, "", err } @@ -81,7 +87,22 @@ func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) { reply := []ServerStatus{} for name, server := range v.servers() { - status, msg, err := server.check(v.client) + transport := v.rt + if server.EnableHTTPS { + // TODO(roberthbailey): The servers that use HTTPS are currently the + // kubelets, and we should be using a standard kubelet client library + // to talk to them rather than a separate http client. + transport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + } + status, msg, err := server.check(&http.Client{Transport: transport}) var errorMsg string if err != nil { errorMsg = err.Error() @@ -103,30 +124,6 @@ func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // NewValidator creates a validator for a set of servers. -func NewValidator(servers func() map[string]Server) (http.Handler, error) { - return &validator{ - servers: servers, - client: &http.Client{}, - }, nil -} - -func makeTestValidator(servers map[string]string, get httpGet) (http.Handler, error) { - result := map[string]Server{} - for name, value := range servers { - host, port, err := net.SplitHostPort(value) - if err != nil { - return nil, fmt.Errorf("invalid server spec: %s (%v)", value, err) - } - val, err := strconv.Atoi(port) - if err != nil { - return nil, fmt.Errorf("invalid server spec: %s (%v)", port, err) - } - result[name] = Server{Addr: host, Port: val, Path: "/healthz"} - } - - v, e := NewValidator(func() map[string]Server { return result }) - if e == nil { - v.(*validator).client = get - } - return v, e +func NewValidator(servers func() map[string]Server) http.Handler { + return &validator{servers: servers, rt: http.DefaultTransport} } diff --git a/pkg/apiserver/validator_test.go b/pkg/apiserver/validator_test.go index 35b991aee0e..6d0c3a2a0e0 100644 --- a/pkg/apiserver/validator_test.go +++ b/pkg/apiserver/validator_test.go @@ -21,35 +21,27 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net" "net/http" "net/http/httptest" + "strconv" "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) -type fakeHttpGet struct { +type fakeRoundTripper struct { err error resp *http.Response url string } -func (f *fakeHttpGet) Get(url string) (*http.Response, error) { - f.url = url +func (f *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + f.url = req.URL.String() return f.resp, f.err } -func makeFake(data string, statusCode int, err error) *fakeHttpGet { - return &fakeHttpGet{ - err: err, - resp: &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString(data)), - StatusCode: statusCode, - }, - } -} - func TestValidate(t *testing.T) { tests := []struct { err error @@ -66,11 +58,18 @@ func TestValidate(t *testing.T) { s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"} for _, test := range tests { - fake := makeFake(test.data, test.code, test.err) + fakeRT := &fakeRoundTripper{ + err: test.err, + resp: &http.Response{ + Body: ioutil.NopCloser(bytes.NewBufferString(test.data)), + StatusCode: test.code, + }, + } + fake := &http.Client{Transport: fakeRT} status, data, err := s.check(fake) expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port) - if fake.url != expect { - t.Errorf("expected %s, got %s", expect, fake.url) + if fakeRT.url != expect { + t.Errorf("expected %s, got %s", expect, fakeRT.url) } if test.expectErr && err == nil { t.Errorf("unexpected non-error") @@ -87,8 +86,30 @@ func TestValidate(t *testing.T) { } } +func makeTestValidator(servers map[string]string, rt http.RoundTripper) (http.Handler, error) { + result := map[string]Server{} + for name, value := range servers { + host, port, err := net.SplitHostPort(value) + if err != nil { + return nil, fmt.Errorf("invalid server spec: %s (%v)", value, err) + } + val, err := strconv.Atoi(port) + if err != nil { + return nil, fmt.Errorf("invalid server spec: %s (%v)", port, err) + } + result[name] = Server{Addr: host, Port: val, Path: "/healthz"} + } + + return &validator{servers: func() map[string]Server { return result }, rt: rt}, nil +} + func TestValidator(t *testing.T) { - fake := makeFake("foo", 200, nil) + fake := &fakeRoundTripper{ + resp: &http.Response{ + Body: ioutil.NopCloser(bytes.NewBufferString("foo")), + StatusCode: 200, + }, + } validator, err := makeTestValidator(map[string]string{ "foo": "foo.com:80", "bar": "bar.com:8080", @@ -101,7 +122,6 @@ func TestValidator(t *testing.T) { defer testServer.Close() resp, err := http.Get(testServer.URL + "/validatez") - if err != nil { t.Errorf("unexpected error: %v", err) } @@ -113,13 +133,15 @@ func TestValidator(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - status := []ServerStatus{} - err = json.Unmarshal(data, &status) - if err != nil { + var status []ServerStatus + if err := json.Unmarshal(data, &status); err != nil { t.Errorf("unexpected error: %v", err) } components := util.StringSet{} for _, s := range status { + if s.Err != "nil" { + t.Errorf("Component %v is unhealthy: %v", s.Component, s.Err) + } components.Insert(s.Component) } if len(status) != 2 || !components.Has("foo") || !components.Has("bar") { diff --git a/pkg/client/kubelet.go b/pkg/client/kubelet.go index 07e34f8e8e3..4ad6ef614a2 100644 --- a/pkg/client/kubelet.go +++ b/pkg/client/kubelet.go @@ -75,9 +75,14 @@ type HTTPKubeletClient struct { func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) { transport := http.DefaultTransport - tlsConfig, err := TLSConfigFor(&Config{ - TLSClientConfig: config.TLSClientConfig, - }) + cfg := &Config{TLSClientConfig: config.TLSClientConfig} + if config.EnableHttps { + hasCA := len(config.CAFile) > 0 || len(config.CAData) > 0 + if !hasCA { + cfg.Insecure = true + } + } + tlsConfig, err := TLSConfigFor(cfg) if err != nil { return nil, err } diff --git a/pkg/master/master.go b/pkg/master/master.go index 6c55b320872..ebcc9b6f9c1 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -561,7 +561,7 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server { glog.Errorf("Failed to list minions: %v", err) } for ix, node := range nodes.Items { - serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.Name, Port: ports.KubeletPort, Path: "/healthz"} + serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.Name, Port: ports.KubeletPort, Path: "/healthz", EnableHTTPS: true} } return serversToValidate }