Support tcp/http liveness/readiness probe (#1449)

This commit is contained in:
ichx
2021-11-03 23:30:38 +08:00
committed by GitHub
parent ce46a5ba01
commit d55071e9d6
14 changed files with 1529 additions and 221 deletions
+142 -46
View File
@@ -41,61 +41,157 @@ func durationTypesPtr(value time.Duration) *types.Duration {
func TestParseHealthCheck(t *testing.T) {
helperValue := uint64(2)
check := types.HealthCheckConfig{
Test: []string{"CMD-SHELL", "echo", "foobar"},
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
type input struct {
healthCheck types.HealthCheckConfig
labels types.Labels
}
testCases := map[string]struct {
input input
expected kobject.HealthCheck
}{
"Exec": {
input: input{
healthCheck: types.HealthCheckConfig{
Test: []string{"CMD-SHELL", "echo", "foobar"},
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
},
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected: kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"HTTPGet": {
input: input{
healthCheck: types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
labels: types.Labels{
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
},
},
expected: kobject.HealthCheck{
HTTPPath: "/health",
HTTPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"TCPSocket": {
input: input{
healthCheck: types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
labels: types.Labels{
"kompose.service.healthcheck.liveness.tcp_port": "8080",
},
},
expected: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
}
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected := kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
}
output, err := parseHealthCheck(check, nil)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
for name, testCase := range testCases {
t.Log("Test case:", name)
output, err := parseHealthCheck(testCase.input.healthCheck, testCase.input.labels)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", expected, output)
if !reflect.DeepEqual(output, testCase.expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", testCase.expected, output)
}
}
}
func TestParseHttpHealthCheck(t *testing.T) {
helperValue := uint64(2)
check := types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
}
label := types.Labels{
HealthCheckLivenessHTTPGetPath: "ping",
HealthCheckLivenessHTTPGetPort: "80",
func TestParseHealthCheckReadiness(t *testing.T) {
testCases := map[string]struct {
input types.Labels
expected kobject.HealthCheck
}{
"Exec": {
input: types.Labels{
"kompose.service.healthcheck.readiness.test": "echo foobar",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"HTTPGet": {
input: types.Labels{
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
HTTPPath: "/ready",
HTTPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"TCPSocket": {
input: types.Labels{
"kompose.service.healthcheck.readiness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
}
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected := kobject.HealthCheck{
HTTPPath: "ping",
HTTPPort: 80,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
}
output, err := parseHealthCheck(check, label)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
for name, testCase := range testCases {
t.Log("Test case:", name)
output, err := parseHealthCheckReadiness(testCase.input)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", expected, output)
if !reflect.DeepEqual(output, testCase.expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", testCase.expected, output)
}
}
}
+8
View File
@@ -60,10 +60,18 @@ const (
HealthCheckReadinessRetries = "kompose.service.healthcheck.readiness.retries"
// HealthCheckReadinessStartPeriod defines readiness health check start period
HealthCheckReadinessStartPeriod = "kompose.service.healthcheck.readiness.start_period"
// HealthCheckReadinessHTTPGetPath defines readiness health check HttpGet path
HealthCheckReadinessHTTPGetPath = "kompose.service.healthcheck.readiness.http_get_path"
// HealthCheckReadinessHTTPGetPort defines readiness health check HttpGet port
HealthCheckReadinessHTTPGetPort = "kompose.service.healthcheck.readiness.http_get_port"
// HealthCheckReadinessTCPPort defines readiness health check tcp port
HealthCheckReadinessTCPPort = "kompose.service.healthcheck.readiness.tcp_port"
// HealthCheckLivenessHTTPGetPath defines liveness health check HttpGet path
HealthCheckLivenessHTTPGetPath = "kompose.service.healthcheck.liveness.http_get_path"
// HealthCheckLivenessHTTPGetPort defines liveness health check HttpGet port
HealthCheckLivenessHTTPGetPort = "kompose.service.healthcheck.liveness.http_get_port"
// HealthCheckLivenessTCPPort defines liveness health check tcp port
HealthCheckLivenessTCPPort = "kompose.service.healthcheck.liveness.tcp_port"
// ServiceTypeHeadless ...
ServiceTypeHeadless = "Headless"
+26 -13
View File
@@ -245,9 +245,9 @@ func loadV3Ports(ports []types.ServicePortConfig, expose []string) []kobject.Por
a Kubernetes-compatible format.
*/
func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error) {
// initialize with CMD as default to not break at return (will be ignored if no test is informed)
test := []string{"CMD"}
var timeout, interval, retries, startPeriod int32
var test []string
var httpPath string
var httpPort, tcpPort, timeout, interval, retries, startPeriod int32
var disable bool
for key, value := range labels {
@@ -258,6 +258,12 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
if len(value) > 0 {
test, _ = shlex.Split(value)
}
case HealthCheckReadinessHTTPGetPath:
httpPath = value
case HealthCheckReadinessHTTPGetPort:
httpPort = cast.ToInt32(value)
case HealthCheckReadinessTCPPort:
tcpPort = cast.ToInt32(value)
case HealthCheckReadinessInterval:
parse, err := time.ParseDuration(value)
if err != nil {
@@ -281,17 +287,22 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
}
}
if test[0] == "NONE" {
disable = true
test = test[1:]
}
if test[0] == "CMD" || test[0] == "CMD-SHELL" {
test = test[1:]
if len(test) > 0 {
if test[0] == "NONE" {
disable = true
test = test[1:]
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
if test[0] == "CMD" || test[0] == "CMD-SHELL" {
test = test[1:]
}
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
return kobject.HealthCheck{
Test: test,
HTTPPath: httpPath,
HTTPPort: httpPort,
TCPPort: tcpPort,
Timeout: timeout,
Interval: interval,
Retries: retries,
@@ -304,9 +315,8 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
a Kubernetes-compatible format.
*/
func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.Labels) (kobject.HealthCheck, error) {
var timeout, interval, retries, startPeriod int32
var httpPort, tcpPort, timeout, interval, retries, startPeriod int32
var test []string
var httpPort int32
var httpPath string
// Here we convert the timeout from 1h30s (example) to 36030 seconds.
@@ -348,12 +358,15 @@ func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.L
httpPath = value
case HealthCheckLivenessHTTPGetPort:
httpPort = cast.ToInt32(value)
case HealthCheckLivenessTCPPort:
tcpPort = cast.ToInt32(value)
}
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
return kobject.HealthCheck{
Test: test,
TCPPort: tcpPort,
HTTPPath: httpPath,
HTTPPort: httpPort,
Timeout: timeout,
@@ -426,7 +439,7 @@ func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.Kompose
// HealthCheck Readiness
var readiness, errReadiness = parseHealthCheckReadiness(*&composeServiceConfig.Labels)
if readiness.Test != nil && len(readiness.Test) > 0 && len(readiness.Test[0]) > 0 && !readiness.Disable {
if !readiness.Disable {
serviceConfig.HealthChecks.Readiness = readiness
if errReadiness != nil {
return kobject.KomposeObject{}, errors.Wrap(errReadiness, "Unable to parse health check")