Skip to content

Commit

Permalink
Create new check for liveness port (#661)
Browse files Browse the repository at this point in the history
* Create new check for liveness port

Want to ensure the port is correctly set for liveness probe since it's
easy to make a typo when people are doing copy pasta. This will let you
know it's failing airier and not have to wait for a failed deployment.

Want to do this also for startup and readiness checks. Assume it make
sense to have them as other checks and was planning on doing that in a
follow up.
  • Loading branch information
charlesoconor authored Dec 22, 2023
1 parent f3522bd commit d1ffb0a
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 3 deletions.
9 changes: 9 additions & 0 deletions docs/generated/checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,15 @@ BlockList:
- ^[^:]*$
- (.*/[^:]+)$
```
## liveness-port
**Enabled by default**: Yes
**Description**: Indicates when containers have a liveness probe to a not exposed port.
**Remediation**: Check which ports you've opened and ensure they match what you have specified in the liveness probe.
**Template**: [liveness-http-port](templates.md#liveness-port-not-open)
## minimum-three-replicas
**Enabled by default**: No
Expand Down
9 changes: 9 additions & 0 deletions docs/generated/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,15 @@ KubeLinter supports the following templates:
type: array
```

## Liveness Port Not Open

**Key**: `liveness-http-port`

**Description**: Flag containers with an HTTP liveness probe to not exposed port.

**Supported Objects**: DeploymentLike


## Liveness Probe Not Specified

**Key**: `liveness-probe`
Expand Down
26 changes: 24 additions & 2 deletions e2etests/bats-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,28 @@ get_value_from() {
[[ "${count}" == "2" ]]
}

@test "liveness-port" {
tmp="tests/checks/liveness-port.yml"
cmd="${KUBE_LINTER_BIN} lint --include liveness-port --do-not-auto-add-defaults --format json ${tmp}"
run ${cmd}

print_info "${status}" "${output}" "${cmd}" "${tmp}"
[ "$status" -eq 1 ]

message1=$(get_value_from "${lines[0]}" '.Reports[0].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[0].Diagnostic.Message')
message2=$(get_value_from "${lines[0]}" '.Reports[1].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[1].Diagnostic.Message')
message3=$(get_value_from "${lines[0]}" '.Reports[2].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[2].Diagnostic.Message')
message4=$(get_value_from "${lines[0]}" '.Reports[3].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[3].Diagnostic.Message')
count=$(get_value_from "${lines[0]}" '.Reports | length')

[[ "${message1}" == "Deployment: container \"fire-deployment-name\" does not expose port http for the HTTPGet" ]]
[[ "${message2}" == "Deployment: container \"fire-deployment-int\" does not expose port 8080 for the HTTPGet" ]]
[[ "${message3}" == "Deployment: container \"fire-deployment-udp\" does not expose port udp for the TCPSocket" ]]
[[ "${message4}" == "StatefulSet: container \"fire-stateful-name\" does not expose port healthcheck for the HTTPGet" ]]
[[ "${count}" == "4" ]]
}


@test "minimum-three-replicas" {
tmp="tests/checks/minimum-three-replicas.yml"
cmd="${KUBE_LINTER_BIN} lint --include minimum-three-replicas --do-not-auto-add-defaults --format json ${tmp}"
Expand Down Expand Up @@ -603,7 +625,7 @@ get_value_from() {
run ${cmd}

message1=$(get_value_from "${lines[0]}" '.Reports[0].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[0].Diagnostic.Message')

[[ "${message1}" == "PodDisruptionBudget: MaxUnavailable is set to 0" ]]

}
Expand All @@ -614,7 +636,7 @@ get_value_from() {
cmd="${KUBE_LINTER_BIN} lint --include pdb-min-available --do-not-auto-add-defaults --format json ${tmp}"
run ${cmd}


message1=$(get_value_from "${lines[0]}" '.Reports[0].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[0].Diagnostic.Message')

[[ "${message1}" == "PodDisruptionBudget: The current number of replicas for deployment foo is equal to or lower than the minimum number of replicas specified by its PDB." ]]
Expand Down
1 change: 1 addition & 0 deletions internal/defaultchecks/default_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var (
"host-pid",
"invalid-target-ports",
"latest-tag",
"liveness-port",
"mismatching-selector",
"no-anti-affinity",
"no-extensions-v1beta",
Expand Down
9 changes: 9 additions & 0 deletions pkg/builtinchecks/yamls/liveness-port.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: "liveness-port"
description: "Indicates when containers have a liveness probe to a not exposed port."
remediation: >-
Check which ports you've opened and ensure they match what you have specified
in the liveness probe.
scope:
objectKinds:
- DeploymentLike
template: "liveness-http-port"
1 change: 1 addition & 0 deletions pkg/templates/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
_ "golang.stackrox.io/kube-linter/pkg/templates/hpareplicas"
_ "golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy"
_ "golang.stackrox.io/kube-linter/pkg/templates/latesttag"
_ "golang.stackrox.io/kube-linter/pkg/templates/livenessport"
_ "golang.stackrox.io/kube-linter/pkg/templates/livenessprobe"
_ "golang.stackrox.io/kube-linter/pkg/templates/memoryrequirements"
_ "golang.stackrox.io/kube-linter/pkg/templates/mismatchingselector"
Expand Down
52 changes: 52 additions & 0 deletions pkg/templates/livenessport/internal/params/gen-params.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pkg/templates/livenessport/internal/params/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package params

// Params represents the params accepted by this template.
type Params struct{}
65 changes: 65 additions & 0 deletions pkg/templates/livenessport/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package livenessport

import (
"fmt"

"golang.stackrox.io/kube-linter/pkg/check"
"golang.stackrox.io/kube-linter/pkg/config"
"golang.stackrox.io/kube-linter/pkg/diagnostic"
"golang.stackrox.io/kube-linter/pkg/objectkinds"
"golang.stackrox.io/kube-linter/pkg/templates"
"golang.stackrox.io/kube-linter/pkg/templates/livenessport/internal/params"
"golang.stackrox.io/kube-linter/pkg/templates/util"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)

const templateKey = "liveness-http-port"

var sentinel = struct{}{}

func init() {
templates.Register(check.Template{
HumanName: "Liveness Port Not Open",
Key: templateKey,
Description: "Flag containers with an HTTP liveness probe to not exposed port.",
SupportedObjectKinds: config.ObjectKindsDesc{
ObjectKinds: []string{objectkinds.DeploymentLike},
},
Parameters: params.ParamDescs,
ParseAndValidateParams: params.ParseAndValidate,
Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
if container.LivenessProbe == nil {
return nil
}

ports := map[intstr.IntOrString]struct{}{}
for _, port := range container.Ports {
if port.Protocol != "" && port.Protocol != v1.ProtocolTCP {
continue
}
ports[intstr.FromInt32(port.ContainerPort)] = sentinel
ports[intstr.FromString(port.Name)] = sentinel
}

if httpProbe := container.LivenessProbe.ProbeHandler.HTTPGet; httpProbe != nil {
if _, ok := ports[httpProbe.Port]; !ok {
return []diagnostic.Diagnostic{{
Message: fmt.Sprintf("container %q does not expose port %s for the HTTPGet", container.Name, httpProbe.Port.String()),
}}
}
}

if tcpProbe := container.LivenessProbe.ProbeHandler.TCPSocket; tcpProbe != nil {
if _, ok := ports[tcpProbe.Port]; !ok {
return []diagnostic.Diagnostic{{
Message: fmt.Sprintf("container %q does not expose port %s for the TCPSocket", container.Name, tcpProbe.Port.String()),
}}
}
}
return nil
}), nil
}),
})
}
Loading

0 comments on commit d1ffb0a

Please sign in to comment.