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

WIP: Catch kubelet-master hostname mismatch during health check #4497

Merged
merged 1 commit into from Feb 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions hack/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ kube::log::status "Starting kubelet in masterless mode"
--really_crash_for_testing=true \
--root_dir=/tmp/kubelet.$$ \
--docker_endpoint="fake://" \
--hostname_override="127.0.0.1" \
--address="127.0.0.1" \
--port="$KUBELET_PORT" 1>&2 &
KUBELET_PID=$!
Expand Down
5 changes: 5 additions & 0 deletions pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,11 @@ func (kl *Kubelet) GetKubeletContainerLogs(podFullName, containerName, tail stri
return dockertools.GetKubeletDockerContainerLogs(kl.dockerClient, dockerContainerID, tail, follow, stdout, stderr)
}

// GetHostname Returns the hostname as the kubelet sees it.
func (kl *Kubelet) GetHostname() string {
return kl.hostname
}

// GetBoundPods returns all pods bound to the kubelet and their spec
func (kl *Kubelet) GetBoundPods() ([]api.BoundPod, error) {
kl.podLock.RLock()
Expand Down
20 changes: 20 additions & 0 deletions pkg/kubelet/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type HostInterface interface {
ServeLogs(w http.ResponseWriter, req *http.Request)
PortForward(name string, uid types.UID, port uint16, stream io.ReadWriteCloser) error
StreamingConnectionIdleTimeout() time.Duration
GetHostname() string
}

// NewServer initializes and configures a kubelet.Server object to handle HTTP requests.
Expand Down Expand Up @@ -148,6 +149,25 @@ func (s *Server) handleHealthz(w http.ResponseWriter, req *http.Request) {
s.error(w, errors.New("Docker version is too old ("+version+")"))
return
}

masterHostname, _, err := net.SplitHostPort(req.Host)
if err != nil {
if !strings.Contains(req.Host, ":") {
masterHostname = req.Host
} else {
msg := fmt.Sprintf("Could not parse hostname from http request: %v", err)
s.error(w, errors.New(msg))
return
}
}

// Check that the hostname known by the master matches the hostname
// the kubelet knows
hostname := s.host.GetHostname()
if masterHostname != hostname {
s.error(w, errors.New("Kubelet hostname \""+hostname+"\" does not match the hostname expected by the master \""+masterHostname+"\""))
return
}
w.Write([]byte("ok"))
}

Expand Down
62 changes: 62 additions & 0 deletions pkg/kubelet/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type fakeKubelet struct {
portForwardFunc func(name string, uid types.UID, port uint16, stream io.ReadWriteCloser) error
containerLogsFunc func(podFullName, containerName, tail string, follow bool, stdout, stderr io.Writer) error
streamingConnectionIdleTimeoutFunc func() time.Duration
hostnameFunc func() string
}

func (fk *fakeKubelet) GetPodByName(namespace, name string) (*api.BoundPod, bool) {
Expand Down Expand Up @@ -89,6 +90,10 @@ func (fk *fakeKubelet) GetKubeletContainerLogs(podFullName, containerName, tail
return fk.containerLogsFunc(podFullName, containerName, tail, follow, stdout, stderr)
}

func (fk *fakeKubelet) GetHostname() string {
return fk.hostnameFunc()
}

func (fk *fakeKubelet) RunInContainer(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error) {
return fk.runFunc(podFullName, uid, containerName, cmd)
}
Expand Down Expand Up @@ -441,6 +446,63 @@ func TestPodsInfo(t *testing.T) {
}
}

func TestHealthCheck(t *testing.T) {
fw := newServerTest()
fw.fakeKubelet.dockerVersionFunc = func() ([]uint, error) {
return []uint{1, 15}, nil
}
fw.fakeKubelet.hostnameFunc = func() string {
return "127.0.0.1"
}

// Test with correct hostname, Docker version
resp, err := http.Get(fw.testHTTPServer.URL + "/healthz")
if err != nil {
t.Fatalf("Got error GETing: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// copying the response body did not work
t.Fatalf("Cannot copy resp: %#v", err)
}
result := string(body)
if !strings.Contains(result, "ok") {
t.Errorf("expected body contains %s, got %d", "ok", result)
}

//Test with incorrect hostname
fw.fakeKubelet.hostnameFunc = func() string {
return "fake"
}
resp, err = http.Get(fw.testHTTPServer.URL + "/healthz")
if err != nil {
t.Fatalf("Got error GETing: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusInternalServerError {
t.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode)
}

//Test with old docker version
fw.fakeKubelet.dockerVersionFunc = func() ([]uint, error) {
return []uint{1, 1}, nil
}

resp, err = http.Get(fw.testHTTPServer.URL + "/healthz")
if err != nil {
t.Fatalf("Got error GETing: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusInternalServerError {
t.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode)
}

}

func setPodByNameFunc(fw *serverTestFramework, namespace, pod, container string) {
fw.fakeKubelet.podByNameFunc = func(namespace, name string) (*api.BoundPod, bool) {
return &api.BoundPod{
Expand Down