mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 02:09:56 +00:00
remove pkg/health and move everything over to pkg/probe
This commit is contained in:
parent
5ee4071cf1
commit
a298402bd4
@ -39,11 +39,11 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
nodeControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
nodeControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
||||||
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/empty_dir"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/empty_dir"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/standalone"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/standalone"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -84,8 +84,8 @@ func (fakeKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.Pod
|
|||||||
return c.GetPodStatus("localhost", podNamespace, podID)
|
return c.GetPodStatus("localhost", podNamespace, podID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeKubeletClient) HealthCheck(host string) (health.Status, error) {
|
func (fakeKubeletClient) HealthCheck(host string) (probe.Status, error) {
|
||||||
return health.Healthy, nil
|
return probe.Healthy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type delegateHandler struct {
|
type delegateHandler struct {
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: this basic interface is duplicated in N places. consolidate?
|
// TODO: this basic interface is duplicated in N places. consolidate?
|
||||||
@ -45,27 +45,28 @@ type validator struct {
|
|||||||
client httpGet
|
client httpGet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) check(client httpGet) (health.Status, string, error) {
|
// TODO: can this use pkg/probe/http
|
||||||
|
func (s *Server) check(client httpGet) (probe.Status, string, error) {
|
||||||
resp, err := client.Get("http://" + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path)
|
resp, err := client.Get("http://" + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return health.Unknown, "", err
|
return probe.Unknown, "", err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return health.Unknown, string(data), err
|
return probe.Unknown, string(data), err
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return health.Unhealthy, string(data),
|
return probe.Unhealthy, string(data),
|
||||||
fmt.Errorf("unhealthy http status code: %d (%s)", resp.StatusCode, resp.Status)
|
fmt.Errorf("unhealthy http status code: %d (%s)", resp.StatusCode, resp.Status)
|
||||||
}
|
}
|
||||||
return health.Healthy, string(data), nil
|
return probe.Healthy, string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerStatus struct {
|
type ServerStatus struct {
|
||||||
Component string `json:"component,omitempty"`
|
Component string `json:"component,omitempty"`
|
||||||
Health string `json:"health,omitempty"`
|
Health string `json:"health,omitempty"`
|
||||||
HealthCode health.Status `json:"healthCode,omitempty"`
|
HealthCode probe.Status `json:"healthCode,omitempty"`
|
||||||
Msg string `json:"msg,omitempty"`
|
Msg string `json:"msg,omitempty"`
|
||||||
Err string `json:"err,omitempty"`
|
Err string `json:"err,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,13 +54,13 @@ func TestValidate(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
err error
|
err error
|
||||||
data string
|
data string
|
||||||
expectedStatus health.Status
|
expectedStatus probe.Status
|
||||||
code int
|
code int
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
{fmt.Errorf("test error"), "", health.Unknown, 500 /*ignored*/, true},
|
{fmt.Errorf("test error"), "", probe.Unknown, 500 /*ignored*/, true},
|
||||||
{nil, "foo", health.Healthy, 200, false},
|
{nil, "foo", probe.Healthy, 200, false},
|
||||||
{nil, "foo", health.Unhealthy, 500, true},
|
{nil, "foo", probe.Unhealthy, 500, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"}
|
s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"}
|
||||||
|
@ -26,7 +26,8 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
|
httprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrPodInfoNotAvailable may be returned when the requested pod info is not available.
|
// ErrPodInfoNotAvailable may be returned when the requested pod info is not available.
|
||||||
@ -40,7 +41,7 @@ type KubeletClient interface {
|
|||||||
|
|
||||||
// KubeletHealthchecker is an interface for healthchecking kubelets
|
// KubeletHealthchecker is an interface for healthchecking kubelets
|
||||||
type KubeletHealthChecker interface {
|
type KubeletHealthChecker interface {
|
||||||
HealthCheck(host string) (health.Status, error)
|
HealthCheck(host string) (probe.Status, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodInfoGetter is an interface for things that can get information about a pod's containers.
|
// PodInfoGetter is an interface for things that can get information about a pod's containers.
|
||||||
@ -146,8 +147,8 @@ func (c *HTTPKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.
|
|||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTTPKubeletClient) HealthCheck(host string) (health.Status, error) {
|
func (c *HTTPKubeletClient) HealthCheck(host string) (probe.Status, error) {
|
||||||
return health.DoHTTPCheck(fmt.Sprintf("%s/healthz", c.url(host)), c.Client)
|
return httprobe.DoHTTPProbe(fmt.Sprintf("%s/healthz", c.url(host)), c.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FakeKubeletClient is a fake implementation of KubeletClient which returns an error
|
// FakeKubeletClient is a fake implementation of KubeletClient which returns an error
|
||||||
@ -160,6 +161,6 @@ func (c FakeKubeletClient) GetPodStatus(host, podNamespace string, podID string)
|
|||||||
return api.PodStatusResult{}, errors.New("Not Implemented")
|
return api.PodStatusResult{}, errors.New("Not Implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c FakeKubeletClient) HealthCheck(host string) (health.Status, error) {
|
func (c FakeKubeletClient) HealthCheck(host string) (probe.Status, error) {
|
||||||
return health.Unknown, errors.New("Not Implemented")
|
return probe.Unknown, errors.New("Not Implemented")
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -134,8 +134,8 @@ func TestNewKubeletClient(t *testing.T) {
|
|||||||
|
|
||||||
host := "127.0.0.1"
|
host := "127.0.0.1"
|
||||||
healthStatus, err := client.HealthCheck(host)
|
healthStatus, err := client.HealthCheck(host)
|
||||||
if healthStatus != health.Unhealthy {
|
if healthStatus != probe.Unhealthy {
|
||||||
t.Errorf("Expected %v and got %v.", health.Unhealthy, healthStatus)
|
t.Errorf("Expected %v and got %v.", probe.Unhealthy, healthStatus)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Expected a nil error")
|
t.Error("Expected a nil error")
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package health contains utilities for health checking, as well as health status information.
|
|
||||||
package health
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultHealthyOutput = "ok"
|
|
||||||
|
|
||||||
type CommandRunner interface {
|
|
||||||
RunInContainer(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExecHealthChecker struct {
|
|
||||||
runner CommandRunner
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewExecHealthChecker(runner CommandRunner) HealthChecker {
|
|
||||||
return &ExecHealthChecker{runner}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExecHealthChecker) HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (Status, error) {
|
|
||||||
if container.LivenessProbe.Exec == nil {
|
|
||||||
return Unknown, fmt.Errorf("missing exec parameters")
|
|
||||||
}
|
|
||||||
data, err := e.runner.RunInContainer(podFullName, podUID, container.Name, container.LivenessProbe.Exec.Command)
|
|
||||||
glog.V(1).Infof("container %s health check response: %s", podFullName, string(data))
|
|
||||||
if err != nil {
|
|
||||||
return Unknown, err
|
|
||||||
}
|
|
||||||
if strings.ToLower(string(data)) != defaultHealthyOutput {
|
|
||||||
return Unhealthy, nil
|
|
||||||
}
|
|
||||||
return Healthy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExecHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
||||||
return probe.Exec != nil
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FakeExec struct {
|
|
||||||
cmd []string
|
|
||||||
out []byte
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExec) RunInContainer(podFullName string, uid types.UID, container string, cmd []string) ([]byte, error) {
|
|
||||||
f.cmd = cmd
|
|
||||||
return f.out, f.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type healthCheckTest struct {
|
|
||||||
expectedStatus Status
|
|
||||||
probe *api.LivenessProbe
|
|
||||||
expectError bool
|
|
||||||
output []byte
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExec(t *testing.T) {
|
|
||||||
fake := FakeExec{}
|
|
||||||
checker := ExecHealthChecker{&fake}
|
|
||||||
tests := []healthCheckTest{
|
|
||||||
// Missing parameters
|
|
||||||
{Unknown, &api.LivenessProbe{}, true, nil, nil},
|
|
||||||
// Ok
|
|
||||||
{Healthy, &api.LivenessProbe{
|
|
||||||
Exec: &api.ExecAction{Command: []string{"ls", "-l"}},
|
|
||||||
}, false, []byte("OK"), nil},
|
|
||||||
// Run returns error
|
|
||||||
{Unknown, &api.LivenessProbe{
|
|
||||||
Exec: &api.ExecAction{
|
|
||||||
Command: []string{"ls", "-l"},
|
|
||||||
},
|
|
||||||
}, true, []byte("OK, NOT"), fmt.Errorf("test error")},
|
|
||||||
// Unhealthy
|
|
||||||
{Unhealthy, &api.LivenessProbe{
|
|
||||||
Exec: &api.ExecAction{Command: []string{"ls", "-l"}},
|
|
||||||
}, false, []byte("Fail"), nil},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
fake.out = test.output
|
|
||||||
fake.err = test.err
|
|
||||||
status, err := checker.HealthCheck("test", "", api.PodStatus{}, api.Container{LivenessProbe: test.probe})
|
|
||||||
if status != test.expectedStatus {
|
|
||||||
t.Errorf("expected %v, got %v", test.expectedStatus, status)
|
|
||||||
}
|
|
||||||
if err != nil && test.expectError == false {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err == nil && test.expectError == true {
|
|
||||||
t.Errorf("unexpected non-error")
|
|
||||||
}
|
|
||||||
if test.probe.Exec != nil && !reflect.DeepEqual(fake.cmd, test.probe.Exec.Command) {
|
|
||||||
t.Errorf("expected: %v, got %v", test.probe.Exec.Command, fake.cmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Status represents the result of a single health-check operation.
|
|
||||||
type Status int
|
|
||||||
|
|
||||||
// Status values must be one of these constants.
|
|
||||||
const (
|
|
||||||
Healthy Status = iota
|
|
||||||
Unhealthy
|
|
||||||
Unknown
|
|
||||||
)
|
|
||||||
|
|
||||||
// HealthChecker defines an abstract interface for checking container health.
|
|
||||||
type HealthChecker interface {
|
|
||||||
HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (Status, error)
|
|
||||||
CanCheck(probe *api.LivenessProbe) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// protects allCheckers
|
|
||||||
var checkerLock = sync.Mutex{}
|
|
||||||
var allCheckers = []HealthChecker{}
|
|
||||||
|
|
||||||
// AddHealthChecker adds a health checker to the list of known HealthChecker objects.
|
|
||||||
// Any subsequent call to NewHealthChecker will know about this HealthChecker.
|
|
||||||
func AddHealthChecker(checker HealthChecker) {
|
|
||||||
checkerLock.Lock()
|
|
||||||
defer checkerLock.Unlock()
|
|
||||||
allCheckers = append(allCheckers, checker)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHealthChecker creates a new HealthChecker which supports multiple types of liveness probes.
|
|
||||||
func NewHealthChecker() HealthChecker {
|
|
||||||
checkerLock.Lock()
|
|
||||||
defer checkerLock.Unlock()
|
|
||||||
return &muxHealthChecker{
|
|
||||||
checkers: append([]HealthChecker{}, allCheckers...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// muxHealthChecker bundles multiple implementations of HealthChecker of different types.
|
|
||||||
type muxHealthChecker struct {
|
|
||||||
// Given a LivenessProbe, cycle through each known checker and see if it supports
|
|
||||||
// the specific kind of probe (by returning non-nil).
|
|
||||||
checkers []HealthChecker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *muxHealthChecker) findCheckerFor(probe *api.LivenessProbe) HealthChecker {
|
|
||||||
for i := range m.checkers {
|
|
||||||
if m.checkers[i].CanCheck(probe) {
|
|
||||||
return m.checkers[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthCheck delegates the health-checking of the container to one of the bundled implementations.
|
|
||||||
// If there is no health checker that can check container it returns Unknown, nil.
|
|
||||||
func (m *muxHealthChecker) HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (Status, error) {
|
|
||||||
checker := m.findCheckerFor(container.LivenessProbe)
|
|
||||||
if checker == nil {
|
|
||||||
glog.Warningf("Failed to find health checker for %s %+v", container.Name, container.LivenessProbe)
|
|
||||||
return Unknown, nil
|
|
||||||
}
|
|
||||||
return checker.HealthCheck(podFullName, podUID, status, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *muxHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
||||||
return m.findCheckerFor(probe) != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findPortByName is a helper function to look up a port in a container by name.
|
|
||||||
// Returns the HostPort if found, -1 if not found.
|
|
||||||
func findPortByName(container api.Container, portName string) int {
|
|
||||||
for _, port := range container.Ports {
|
|
||||||
if port.Name == portName {
|
|
||||||
return port.HostPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Status) String() string {
|
|
||||||
switch s {
|
|
||||||
case Healthy:
|
|
||||||
return "healthy"
|
|
||||||
case Unhealthy:
|
|
||||||
return "unhealthy"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
const statusServerEarlyShutdown = -1
|
|
||||||
|
|
||||||
func TestHealthChecker(t *testing.T) {
|
|
||||||
AddHealthChecker(&HTTPHealthChecker{client: &http.Client{}})
|
|
||||||
var healthCheckerTests = []struct {
|
|
||||||
status int
|
|
||||||
health Status
|
|
||||||
}{
|
|
||||||
{http.StatusOK, Healthy},
|
|
||||||
{statusServerEarlyShutdown, Unhealthy},
|
|
||||||
{http.StatusBadRequest, Unhealthy},
|
|
||||||
{http.StatusBadGateway, Unhealthy},
|
|
||||||
{http.StatusInternalServerError, Unhealthy},
|
|
||||||
}
|
|
||||||
for _, healthCheckerTest := range healthCheckerTests {
|
|
||||||
tt := healthCheckerTest
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(tt.status)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
u, err := url.Parse(ts.URL)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if tt.status == statusServerEarlyShutdown {
|
|
||||||
ts.Close()
|
|
||||||
}
|
|
||||||
container := api.Container{
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
HTTPGet: &api.HTTPGetAction{
|
|
||||||
Port: util.NewIntOrStringFromString(port),
|
|
||||||
Path: "/foo/bar",
|
|
||||||
Host: host,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
hc := NewHealthChecker()
|
|
||||||
health, err := hc.HealthCheck("test", "", api.PodStatus{}, container)
|
|
||||||
if err != nil && tt.health != Unhealthy {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if health != tt.health {
|
|
||||||
t.Errorf("Expected %v, got %v", tt.health, health)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindPortByName(t *testing.T) {
|
|
||||||
container := api.Container{
|
|
||||||
Ports: []api.Port{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
HostPort: 8080,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "bar",
|
|
||||||
HostPort: 9000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
want := 8080
|
|
||||||
got := findPortByName(container, "foo")
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Expected %v, got %v", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMuxHealthChecker(t *testing.T) {
|
|
||||||
muxHealthCheckerTests := []struct {
|
|
||||||
health Status
|
|
||||||
}{
|
|
||||||
// TODO: This test should run through a few different checker types.
|
|
||||||
{Healthy},
|
|
||||||
}
|
|
||||||
mc := &muxHealthChecker{
|
|
||||||
checkers: []HealthChecker{
|
|
||||||
&HTTPHealthChecker{client: &http.Client{}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, muxHealthCheckerTest := range muxHealthCheckerTests {
|
|
||||||
tt := muxHealthCheckerTest
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
u, err := url.Parse(ts.URL)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
container := api.Container{
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
HTTPGet: &api.HTTPGetAction{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
container.LivenessProbe.HTTPGet.Port = util.NewIntOrStringFromString(port)
|
|
||||||
container.LivenessProbe.HTTPGet.Host = host
|
|
||||||
health, err := mc.HealthCheck("test", "", api.PodStatus{}, container)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if health != tt.health {
|
|
||||||
t.Errorf("Expected %v, got %v", tt.health, health)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTTPGetInterface is an abstract interface for testability. It abstracts the interface of http.Client.Get.
|
|
||||||
// This is exported because some other packages may want to do direct HTTP checks.
|
|
||||||
type HTTPGetInterface interface {
|
|
||||||
Get(url string) (*http.Response, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPHealthChecker is an implementation of HealthChecker which checks container health by sending HTTP Get requests.
|
|
||||||
type HTTPHealthChecker struct {
|
|
||||||
client HTTPGetInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPHealthChecker(client *http.Client) HealthChecker {
|
|
||||||
return &HTTPHealthChecker{client: &http.Client{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getURLParts parses the components of the target URL. For testability.
|
|
||||||
func getURLParts(status api.PodStatus, container api.Container) (string, int, string, error) {
|
|
||||||
params := container.LivenessProbe.HTTPGet
|
|
||||||
if params == nil {
|
|
||||||
return "", -1, "", fmt.Errorf("no HTTP parameters specified: %v", container)
|
|
||||||
}
|
|
||||||
port := -1
|
|
||||||
switch params.Port.Kind {
|
|
||||||
case util.IntstrInt:
|
|
||||||
port = params.Port.IntVal
|
|
||||||
case util.IntstrString:
|
|
||||||
port = findPortByName(container, params.Port.StrVal)
|
|
||||||
if port == -1 {
|
|
||||||
// Last ditch effort - maybe it was an int stored as string?
|
|
||||||
var err error
|
|
||||||
if port, err = strconv.Atoi(params.Port.StrVal); err != nil {
|
|
||||||
return "", -1, "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if port == -1 {
|
|
||||||
return "", -1, "", fmt.Errorf("unknown port: %v", params.Port)
|
|
||||||
}
|
|
||||||
var host string
|
|
||||||
if len(params.Host) > 0 {
|
|
||||||
host = params.Host
|
|
||||||
} else {
|
|
||||||
host = status.PodIP
|
|
||||||
}
|
|
||||||
|
|
||||||
return host, port, params.Path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatURL formats a URL from args. For testability.
|
|
||||||
func formatURL(host string, port int, path string) string {
|
|
||||||
u := url.URL{
|
|
||||||
Scheme: "http",
|
|
||||||
Host: net.JoinHostPort(host, strconv.Itoa(port)),
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
return u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoHTTPCheck checks if a GET request to the url succeeds.
|
|
||||||
// If the HTTP response code is successful (i.e. 400 > code >= 200), it returns Healthy.
|
|
||||||
// If the HTTP response code is unsuccessful or HTTP communication fails, it returns Unhealthy.
|
|
||||||
// This is exported because some other packages may want to do direct HTTP checks.
|
|
||||||
func DoHTTPCheck(url string, client HTTPGetInterface) (Status, error) {
|
|
||||||
res, err := client.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(1).Infof("HTTP probe error: %v", err)
|
|
||||||
return Unhealthy, nil
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest {
|
|
||||||
return Healthy, nil
|
|
||||||
}
|
|
||||||
glog.V(1).Infof("Health check failed for %s, Response: %v", url, *res)
|
|
||||||
return Unhealthy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthCheck checks if the container is healthy by trying sending HTTP Get requests to the container.
|
|
||||||
func (h *HTTPHealthChecker) HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (Status, error) {
|
|
||||||
host, port, path, err := getURLParts(status, container)
|
|
||||||
if err != nil {
|
|
||||||
return Unknown, err
|
|
||||||
}
|
|
||||||
return DoHTTPCheck(formatURL(host, port, path), h.client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTPHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
||||||
return probe.HTTPGet != nil
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetURLParts(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
probe *api.HTTPGetAction
|
|
||||||
ok bool
|
|
||||||
host string
|
|
||||||
port int
|
|
||||||
path string
|
|
||||||
}{
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromInt(-1), Path: ""}, false, "", -1, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString(""), Path: ""}, false, "", -1, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("-1"), Path: ""}, false, "", -1, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("not-found"), Path: ""}, false, "", -1, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("found"), Path: ""}, true, "127.0.0.1", 93, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromInt(76), Path: ""}, true, "127.0.0.1", 76, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("118"), Path: ""}, true, "127.0.0.1", 118, ""},
|
|
||||||
{&api.HTTPGetAction{Host: "hostname", Port: util.NewIntOrStringFromInt(76), Path: "path"}, true, "hostname", 76, "path"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range testCases {
|
|
||||||
state := api.PodStatus{PodIP: "127.0.0.1"}
|
|
||||||
container := api.Container{
|
|
||||||
Ports: []api.Port{{Name: "found", HostPort: 93}},
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
HTTPGet: test.probe,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
host, port, path, err := getURLParts(state, container)
|
|
||||||
if !test.ok && err == nil {
|
|
||||||
t.Errorf("Expected error for %+v, got %s:%d/%s", test, host, port, path)
|
|
||||||
}
|
|
||||||
if test.ok && err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if test.ok {
|
|
||||||
if host != test.host || port != test.port || path != test.path {
|
|
||||||
t.Errorf("Expected %s:%d/%s, got %s:%d/%s",
|
|
||||||
test.host, test.port, test.path, host, port, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatURL(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
host string
|
|
||||||
port int
|
|
||||||
path string
|
|
||||||
result string
|
|
||||||
}{
|
|
||||||
{"localhost", 93, "", "http://localhost:93"},
|
|
||||||
{"localhost", 93, "/path", "http://localhost:93/path"},
|
|
||||||
}
|
|
||||||
for _, test := range testCases {
|
|
||||||
url := formatURL(test.host, test.port, test.path)
|
|
||||||
if url != test.result {
|
|
||||||
t.Errorf("Expected %s, got %s", test.result, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHTTPHealthChecker(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
probe *api.HTTPGetAction
|
|
||||||
status int
|
|
||||||
health Status
|
|
||||||
}{
|
|
||||||
// The probe will be filled in below. This is primarily testing that an HTTP GET happens.
|
|
||||||
{&api.HTTPGetAction{}, http.StatusOK, Healthy},
|
|
||||||
{&api.HTTPGetAction{}, -1, Unhealthy},
|
|
||||||
{nil, -1, Unknown},
|
|
||||||
}
|
|
||||||
hc := &HTTPHealthChecker{
|
|
||||||
client: &http.Client{},
|
|
||||||
}
|
|
||||||
for _, test := range testCases {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(test.status)
|
|
||||||
}))
|
|
||||||
u, err := url.Parse(ts.URL)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
container := api.Container{
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
HTTPGet: test.probe,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
params := container.LivenessProbe.HTTPGet
|
|
||||||
if params != nil {
|
|
||||||
params.Port = util.NewIntOrStringFromString(port)
|
|
||||||
params.Host = host
|
|
||||||
}
|
|
||||||
health, err := hc.HealthCheck("test", "", api.PodStatus{PodIP: host}, container)
|
|
||||||
if test.health == Unknown && err == nil {
|
|
||||||
t.Errorf("Expected error")
|
|
||||||
}
|
|
||||||
if test.health != Unknown && err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if health != test.health {
|
|
||||||
t.Errorf("Expected %v, got %v", test.health, health)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TCPHealthChecker struct{}
|
|
||||||
|
|
||||||
// getTCPAddrParts parses the components of a TCP connection address. For testability.
|
|
||||||
func getTCPAddrParts(status api.PodStatus, container api.Container) (string, int, error) {
|
|
||||||
params := container.LivenessProbe.TCPSocket
|
|
||||||
if params == nil {
|
|
||||||
return "", -1, fmt.Errorf("error, no TCP parameters specified: %v", container)
|
|
||||||
}
|
|
||||||
port := -1
|
|
||||||
switch params.Port.Kind {
|
|
||||||
case util.IntstrInt:
|
|
||||||
port = params.Port.IntVal
|
|
||||||
case util.IntstrString:
|
|
||||||
port = findPortByName(container, params.Port.StrVal)
|
|
||||||
if port == -1 {
|
|
||||||
// Last ditch effort - maybe it was an int stored as string?
|
|
||||||
var err error
|
|
||||||
if port, err = strconv.Atoi(params.Port.StrVal); err != nil {
|
|
||||||
return "", -1, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if port == -1 {
|
|
||||||
return "", -1, fmt.Errorf("unknown port: %v", params.Port)
|
|
||||||
}
|
|
||||||
if len(status.PodIP) == 0 {
|
|
||||||
return "", -1, fmt.Errorf("no host specified.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return status.PodIP, port, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoTCPCheck checks that a TCP socket to the address can be opened.
|
|
||||||
// If the socket can be opened, it returns Healthy.
|
|
||||||
// If the socket fails to open, it returns Unhealthy.
|
|
||||||
// This is exported because some other packages may want to do direct TCP checks.
|
|
||||||
func DoTCPCheck(addr string) (Status, error) {
|
|
||||||
conn, err := net.Dial("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return Unhealthy, nil
|
|
||||||
}
|
|
||||||
err = conn.Close()
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error closing health check socket: %v (%#v)", err, err)
|
|
||||||
}
|
|
||||||
return Healthy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TCPHealthChecker) HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (Status, error) {
|
|
||||||
host, port, err := getTCPAddrParts(status, container)
|
|
||||||
if err != nil {
|
|
||||||
return Unknown, err
|
|
||||||
}
|
|
||||||
return DoTCPCheck(net.JoinHostPort(host, strconv.Itoa(port)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TCPHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
||||||
return probe.TCPSocket != nil
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package health
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetTCPAddrParts(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
probe *api.TCPSocketAction
|
|
||||||
ok bool
|
|
||||||
host string
|
|
||||||
port int
|
|
||||||
}{
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromInt(-1)}, false, "", -1},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromString("")}, false, "", -1},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromString("-1")}, false, "", -1},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromString("not-found")}, false, "", -1},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromString("found")}, true, "1.2.3.4", 93},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromInt(76)}, true, "1.2.3.4", 76},
|
|
||||||
{&api.TCPSocketAction{Port: util.NewIntOrStringFromString("118")}, true, "1.2.3.4", 118},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range testCases {
|
|
||||||
state := api.PodStatus{PodIP: "1.2.3.4"}
|
|
||||||
container := api.Container{
|
|
||||||
Ports: []api.Port{{Name: "found", HostPort: 93}},
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
TCPSocket: test.probe,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
host, port, err := getTCPAddrParts(state, container)
|
|
||||||
if !test.ok && err == nil {
|
|
||||||
t.Errorf("Expected error for %+v, got %s:%d", test, host, port)
|
|
||||||
}
|
|
||||||
if test.ok && err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if test.ok {
|
|
||||||
if host != test.host || port != test.port {
|
|
||||||
t.Errorf("Expected %s:%d, got %s:%d", test.host, test.port, host, port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTcpHealthChecker(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
probe *api.TCPSocketAction
|
|
||||||
expectedStatus Status
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
// The probe will be filled in below. This is primarily testing that a connection is made.
|
|
||||||
{&api.TCPSocketAction{}, Healthy, false},
|
|
||||||
{&api.TCPSocketAction{}, Unhealthy, false},
|
|
||||||
{nil, Unknown, true},
|
|
||||||
}
|
|
||||||
|
|
||||||
checker := &TCPHealthChecker{}
|
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}))
|
|
||||||
defer server.Close()
|
|
||||||
u, err := url.Parse(server.URL)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
container := api.Container{
|
|
||||||
LivenessProbe: &api.LivenessProbe{
|
|
||||||
TCPSocket: test.probe,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
params := container.LivenessProbe.TCPSocket
|
|
||||||
if params != nil && test.expectedStatus == Healthy {
|
|
||||||
params.Port = util.NewIntOrStringFromString(port)
|
|
||||||
}
|
|
||||||
status, err := checker.HealthCheck("test", "", api.PodStatus{PodIP: host}, container)
|
|
||||||
if status != test.expectedStatus {
|
|
||||||
t.Errorf("expected: %v, got: %v", test.expectedStatus, status)
|
|
||||||
}
|
|
||||||
if err != nil && !test.expectError {
|
|
||||||
t.Errorf("unexpected error: %#v", err)
|
|
||||||
}
|
|
||||||
if err == nil && test.expectError {
|
|
||||||
t.Errorf("unexpected non-error.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,11 +36,11 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -164,8 +164,6 @@ type Kubelet struct {
|
|||||||
|
|
||||||
// Optional, no events will be sent without it
|
// Optional, no events will be sent without it
|
||||||
etcdClient tools.EtcdClient
|
etcdClient tools.EtcdClient
|
||||||
// Optional, defaults to simple implementaiton
|
|
||||||
healthChecker health.HealthChecker
|
|
||||||
// Optional, defaults to simple Docker implementation
|
// Optional, defaults to simple Docker implementation
|
||||||
dockerPuller dockertools.DockerPuller
|
dockerPuller dockertools.DockerPuller
|
||||||
// Optional, defaults to /logs/ from /var/log
|
// Optional, defaults to /logs/ from /var/log
|
||||||
@ -427,9 +425,6 @@ func (kl *Kubelet) Run(updates <-chan PodUpdate) {
|
|||||||
if kl.dockerPuller == nil {
|
if kl.dockerPuller == nil {
|
||||||
kl.dockerPuller = dockertools.NewDockerPuller(kl.dockerClient, kl.pullQPS, kl.pullBurst)
|
kl.dockerPuller = dockertools.NewDockerPuller(kl.dockerClient, kl.pullQPS, kl.pullBurst)
|
||||||
}
|
}
|
||||||
if kl.healthChecker == nil {
|
|
||||||
kl.healthChecker = health.NewHealthChecker()
|
|
||||||
}
|
|
||||||
kl.syncLoop(updates, kl)
|
kl.syncLoop(updates, kl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1038,13 +1033,13 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
|
|||||||
// look for changes in the container.
|
// look for changes in the container.
|
||||||
if hash == 0 || hash == expectedHash {
|
if hash == 0 || hash == expectedHash {
|
||||||
// TODO: This should probably be separated out into a separate goroutine.
|
// TODO: This should probably be separated out into a separate goroutine.
|
||||||
healthy, err := kl.healthy(podFullName, uid, podStatus, container, dockerContainer)
|
healthy, err := kl.probeLiveness(podFullName, uid, podStatus, container, dockerContainer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(1).Infof("health check errored: %v", err)
|
glog.V(1).Infof("health check errored: %v", err)
|
||||||
containersToKeep[containerID] = empty{}
|
containersToKeep[containerID] = empty{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if healthy == health.Healthy {
|
if healthy == probe.Healthy {
|
||||||
containersToKeep[containerID] = empty{}
|
containersToKeep[containerID] = empty{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1403,18 +1398,15 @@ func (kl *Kubelet) GetPodStatus(podFullName string, uid types.UID) (api.PodStatu
|
|||||||
return podStatus, err
|
return podStatus, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kl *Kubelet) healthy(podFullName string, podUID types.UID, status api.PodStatus, container api.Container, dockerContainer *docker.APIContainers) (health.Status, error) {
|
func (kl *Kubelet) probeLiveness(podFullName string, podUID types.UID, status api.PodStatus, container api.Container, dockerContainer *docker.APIContainers) (probe.Status, error) {
|
||||||
// Give the container 60 seconds to start up.
|
// Give the container 60 seconds to start up.
|
||||||
if container.LivenessProbe == nil {
|
if container.LivenessProbe == nil {
|
||||||
return health.Healthy, nil
|
return probe.Healthy, nil
|
||||||
}
|
}
|
||||||
if time.Now().Unix()-dockerContainer.Created < container.LivenessProbe.InitialDelaySeconds {
|
if time.Now().Unix()-dockerContainer.Created < container.LivenessProbe.InitialDelaySeconds {
|
||||||
return health.Healthy, nil
|
return probe.Healthy, nil
|
||||||
}
|
}
|
||||||
if kl.healthChecker == nil {
|
return kl.probeContainer(container.LivenessProbe, podFullName, podUID, status, container)
|
||||||
return health.Healthy, nil
|
|
||||||
}
|
|
||||||
return kl.healthChecker.HealthCheck(podFullName, podUID, status, container)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns logs of current machine.
|
// Returns logs of current machine.
|
||||||
|
@ -31,7 +31,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
||||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/host_path"
|
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/host_path"
|
||||||
@ -845,19 +844,8 @@ func TestSyncPodDeletesDuplicate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FalseHealthChecker struct{}
|
|
||||||
|
|
||||||
func (f *FalseHealthChecker) HealthCheck(podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (health.Status, error) {
|
|
||||||
return health.Unhealthy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FalseHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSyncPodBadHash(t *testing.T) {
|
func TestSyncPodBadHash(t *testing.T) {
|
||||||
kubelet, fakeDocker := newTestKubelet(t)
|
kubelet, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.healthChecker = &FalseHealthChecker{}
|
|
||||||
dockerContainers := dockertools.DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"1234": &docker.APIContainers{
|
"1234": &docker.APIContainers{
|
||||||
// the k8s prefix is required for the kubelet to manage the container
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
@ -904,7 +892,6 @@ func TestSyncPodBadHash(t *testing.T) {
|
|||||||
|
|
||||||
func TestSyncPodUnhealthy(t *testing.T) {
|
func TestSyncPodUnhealthy(t *testing.T) {
|
||||||
kubelet, fakeDocker := newTestKubelet(t)
|
kubelet, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.healthChecker = &FalseHealthChecker{}
|
|
||||||
dockerContainers := dockertools.DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"1234": &docker.APIContainers{
|
"1234": &docker.APIContainers{
|
||||||
// the k8s prefix is required for the kubelet to manage the container
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (kl *Kubelet) makeLivenessProbeRunner(p *api.LivenessProbe, podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (probe.Status, error) {
|
func (kl *Kubelet) probeContainer(p *api.LivenessProbe, podFullName string, podUID types.UID, status api.PodStatus, container api.Container) (probe.Status, error) {
|
||||||
if p.Exec != nil {
|
if p.Exec != nil {
|
||||||
return execprobe.Probe(kl.newExecInContainer(podFullName, podUID, container))
|
return execprobe.Probe(kl.newExecInContainer(podFullName, podUID, container))
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,12 @@ limitations under the License.
|
|||||||
package kubelet
|
package kubelet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/coreos/go-etcd/etcd"
|
"github.com/coreos/go-etcd/etcd"
|
||||||
@ -46,15 +44,6 @@ func MonitorCAdvisor(k *Kubelet, cp uint) {
|
|||||||
k.SetCadvisorClient(cadvisorClient)
|
k.SetCadvisorClient(cadvisorClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this into the kubelet itself
|
|
||||||
func InitHealthChecking(k *Kubelet) {
|
|
||||||
// TODO: These should probably become more plugin-ish: register a factory func
|
|
||||||
// in each checker's init(), iterate those here.
|
|
||||||
health.AddHealthChecker(health.NewExecHealthChecker(k))
|
|
||||||
health.AddHealthChecker(health.NewHTTPHealthChecker(&http.Client{}))
|
|
||||||
health.AddHealthChecker(&health.TCPHealthChecker{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move this into a pkg/tools/etcd_tools
|
// TODO: move this into a pkg/tools/etcd_tools
|
||||||
func EtcdClientOrDie(etcdServerList util.StringList, etcdConfigFile string) tools.EtcdClient {
|
func EtcdClientOrDie(etcdServerList util.StringList, etcdConfigFile string) tools.EtcdClient {
|
||||||
if len(etcdServerList) > 0 {
|
if len(etcdServerList) > 0 {
|
||||||
|
@ -22,8 +22,8 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ func (r *HealthyRegistry) doCheck(key string) util.T {
|
|||||||
case err != nil:
|
case err != nil:
|
||||||
glog.V(2).Infof("HealthyRegistry: node %q health check error: %v", key, err)
|
glog.V(2).Infof("HealthyRegistry: node %q health check error: %v", key, err)
|
||||||
nodeStatus = api.ConditionUnknown
|
nodeStatus = api.ConditionUnknown
|
||||||
case status == health.Unhealthy:
|
case status == probe.Unhealthy:
|
||||||
nodeStatus = api.ConditionNone
|
nodeStatus = api.ConditionNone
|
||||||
default:
|
default:
|
||||||
nodeStatus = api.ConditionFull
|
nodeStatus = api.ConditionFull
|
||||||
|
@ -22,15 +22,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type alwaysYes struct{}
|
type alwaysYes struct{}
|
||||||
|
|
||||||
func (alwaysYes) HealthCheck(host string) (health.Status, error) {
|
func (alwaysYes) HealthCheck(host string) (probe.Status, error) {
|
||||||
return health.Healthy, nil
|
return probe.Healthy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicDelegation(t *testing.T) {
|
func TestBasicDelegation(t *testing.T) {
|
||||||
@ -75,11 +75,11 @@ type notMinion struct {
|
|||||||
minion string
|
minion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *notMinion) HealthCheck(host string) (health.Status, error) {
|
func (n *notMinion) HealthCheck(host string) (probe.Status, error) {
|
||||||
if host != n.minion {
|
if host != n.minion {
|
||||||
return health.Healthy, nil
|
return probe.Healthy, nil
|
||||||
} else {
|
} else {
|
||||||
return health.Unhealthy, nil
|
return probe.Unhealthy, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +302,6 @@ func createAndInitKubelet(kc *KubeletConfig, pc *config.PodConfig) (*kubelet.Kub
|
|||||||
|
|
||||||
go k.GarbageCollectLoop()
|
go k.GarbageCollectLoop()
|
||||||
go kubelet.MonitorCAdvisor(k, kc.CAdvisorPort)
|
go kubelet.MonitorCAdvisor(k, kc.CAdvisorPort)
|
||||||
kubelet.InitHealthChecking(k)
|
|
||||||
|
|
||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user