mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 22:46:12 +00:00
Use IntOrString for TCP health check ports
Clean up code to be more testable. Add test cases for named and numeric ports in TCP health checks. Improve tests.
This commit is contained in:
parent
7201227cb1
commit
c67c1edfb4
@ -146,8 +146,8 @@ type HTTPGetProbe struct {
|
||||
|
||||
// TCPSocketProbe describes a liveness probe based on opening a socket
|
||||
type TCPSocketProbe struct {
|
||||
// Port is the port to connect to. Required.
|
||||
Port int `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
// Required: Port to connect to.
|
||||
Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
}
|
||||
|
||||
// LivenessProbe describes a liveness probe to be examined to the container.
|
||||
|
@ -149,8 +149,8 @@ type HTTPGetProbe struct {
|
||||
|
||||
// TCPSocketProbe describes a liveness probe based on opening a socket
|
||||
type TCPSocketProbe struct {
|
||||
// Port is the port to connect to. Required.
|
||||
Port int `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
// Required: Port to connect to.
|
||||
Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
}
|
||||
|
||||
// LivenessProbe describes a liveness probe to be examined to the container.
|
||||
|
@ -126,15 +126,41 @@ func (h *HTTPHealthChecker) HealthCheck(currentState api.PodState, container api
|
||||
|
||||
type TCPHealthChecker struct{}
|
||||
|
||||
func (t *TCPHealthChecker) HealthCheck(currentState api.PodState, container api.Container) (Status, error) {
|
||||
// Get the components of a TCP connection address. For testability.
|
||||
func getTCPAddrParts(currentState api.PodState, container api.Container) (string, int, error) {
|
||||
params := container.LivenessProbe.TCPSocket
|
||||
if params == nil {
|
||||
return Unknown, fmt.Errorf("error, no TCP parameters specified: %v", container)
|
||||
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(currentState.PodIP) == 0 {
|
||||
return Unknown, fmt.Errorf("no host specified.")
|
||||
return "", -1, fmt.Errorf("no host specified.")
|
||||
}
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort(currentState.PodIP, strconv.Itoa(params.Port)))
|
||||
|
||||
return currentState.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.
|
||||
func DoTCPCheck(addr string) (Status, error) {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return Unhealthy, nil
|
||||
}
|
||||
@ -144,3 +170,11 @@ func (t *TCPHealthChecker) HealthCheck(currentState api.PodState, container api.
|
||||
}
|
||||
return Healthy, nil
|
||||
}
|
||||
|
||||
func (t *TCPHealthChecker) HealthCheck(currentState api.PodState, container api.Container) (Status, error) {
|
||||
host, port, err := getTCPAddrParts(currentState, container)
|
||||
if err != nil {
|
||||
return Unknown, err
|
||||
}
|
||||
return DoTCPCheck(net.JoinHostPort(host, strconv.Itoa(port)))
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
@ -209,11 +208,56 @@ func TestHTTPHealthChecker(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTCPAddrParts(t *testing.T) {
|
||||
testCases := []struct {
|
||||
probe *api.TCPSocketProbe
|
||||
ok bool
|
||||
host string
|
||||
port int
|
||||
}{
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromInt(-1)}, false, "", -1},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromString("")}, false, "", -1},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromString("-1")}, false, "", -1},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromString("not-found")}, false, "", -1},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromString("found")}, true, "1.2.3.4", 93},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromInt(76)}, true, "1.2.3.4", 76},
|
||||
{&api.TCPSocketProbe{Port: util.MakeIntOrStringFromString("118")}, true, "1.2.3.4", 118},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
state := api.PodState{PodIP: "1.2.3.4"}
|
||||
container := api.Container{
|
||||
Ports: []api.Port{{Name: "found", HostPort: 93}},
|
||||
LivenessProbe: &api.LivenessProbe{
|
||||
TCPSocket: test.probe,
|
||||
Type: "tcp",
|
||||
},
|
||||
}
|
||||
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) {
|
||||
type tcpHealthTest struct {
|
||||
probe *api.LivenessProbe
|
||||
tests := []struct {
|
||||
probe *api.TCPSocketProbe
|
||||
expectedStatus Status
|
||||
expectError bool
|
||||
}{
|
||||
// The probe will be filled in below. This is primarily testing that a connection is made.
|
||||
{&api.TCPSocketProbe{}, Healthy, false},
|
||||
{&api.TCPSocketProbe{}, Unhealthy, false},
|
||||
{nil, Unknown, true},
|
||||
}
|
||||
|
||||
checker := &TCPHealthChecker{}
|
||||
@ -225,17 +269,19 @@ func TestTcpHealthChecker(t *testing.T) {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
host, port, err := net.SplitHostPort(u.Host)
|
||||
portNum, _ := strconv.Atoi(port)
|
||||
|
||||
tests := []tcpHealthTest{
|
||||
{&api.LivenessProbe{TCPSocket: &api.TCPSocketProbe{Port: portNum}}, Healthy, false},
|
||||
{&api.LivenessProbe{TCPSocket: &api.TCPSocketProbe{Port: 100000}}, Unhealthy, false},
|
||||
{&api.LivenessProbe{}, Unknown, true},
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
for _, test := range tests {
|
||||
probe := test.probe
|
||||
container := api.Container{
|
||||
LivenessProbe: probe,
|
||||
LivenessProbe: &api.LivenessProbe{
|
||||
TCPSocket: test.probe,
|
||||
Type: "tcp",
|
||||
},
|
||||
}
|
||||
params := container.LivenessProbe.TCPSocket
|
||||
if params != nil && test.expectedStatus == Healthy {
|
||||
params.Port = util.MakeIntOrStringFromString(port)
|
||||
}
|
||||
status, err := checker.HealthCheck(api.PodState{PodIP: host}, container)
|
||||
if status != test.expectedStatus {
|
||||
|
Loading…
Reference in New Issue
Block a user