Skip to content

Commit 914b5c9

Browse files
committed
add oc status warning for missing liveness probe
This patch iterates through pod specs, listing specs with no liveness probes set. Ignores podspec nodes with a controlling edge kind.
1 parent 8f6030a commit 914b5c9

File tree

6 files changed

+103
-2
lines changed

6 files changed

+103
-2
lines changed

pkg/api/kubegraph/analysis/hpa.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
osgraph "github.com/openshift/origin/pkg/api/graph"
1313
"github.com/openshift/origin/pkg/api/kubegraph"
14+
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
1415
kubenodes "github.com/openshift/origin/pkg/api/kubegraph/nodes"
1516
deploygraph "github.com/openshift/origin/pkg/deploy/graph"
1617
deploynodes "github.com/openshift/origin/pkg/deploy/graph/nodes"
@@ -117,6 +118,7 @@ func FindOverlappingHPAs(graph osgraph.Graph, namer osgraph.Namer) []osgraph.Mar
117118
edgeFilter := osgraph.EdgesOfKind(
118119
kubegraph.ScalingEdgeKind,
119120
deploygraph.DeploymentEdgeKind,
121+
kubeedges.ManagedByControllerEdgeKind,
120122
)
121123

122124
hpaSubGraph := graph.Subgraph(nodeFilter, edgeFilter)

pkg/api/kubegraph/analysis/podspec.go

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111
)
1212

1313
const (
14-
UnmountableSecretWarning = "UnmountableSecret"
15-
MissingSecretWarning = "MissingSecret"
14+
UnmountableSecretWarning = "UnmountableSecret"
15+
MissingSecretWarning = "MissingSecret"
16+
MissingLivenessProbeWarning = "MissingLivenessProbe"
1617
)
1718

1819
// FindUnmountableSecrets inspects all PodSpecs for any Secret reference that isn't listed as mountable by the referenced ServiceAccount
@@ -75,6 +76,58 @@ func FindMissingSecrets(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
7576
return markers
7677
}
7778

79+
// FindMissingLivenessProbes inspects all PodSpecs for missing liveness probes and generates a list of non-duplicate markers
80+
func FindMissingLivenessProbes(g osgraph.Graph, f osgraph.Namer, setProbeCommand string) []osgraph.Marker {
81+
markers := []osgraph.Marker{}
82+
83+
for _, uncastPodSpecNode := range g.NodesByKind(kubegraph.PodSpecNodeKind) {
84+
podSpecNode := uncastPodSpecNode.(*kubegraph.PodSpecNode)
85+
if hasLivenessProbe(podSpecNode) {
86+
continue
87+
}
88+
89+
topLevelNode := osgraph.GetTopLevelContainerNode(g, podSpecNode)
90+
91+
// skip any podSpec nodes that are managed by other nodes.
92+
// Liveness probes should only be applied to a controlling
93+
// podSpec node, and not to any of its children.
94+
if hasControllerRefEdge(g, topLevelNode) {
95+
continue
96+
}
97+
98+
topLevelString := f.ResourceName(topLevelNode)
99+
markers = append(markers, osgraph.Marker{
100+
Node: podSpecNode,
101+
RelatedNodes: []graph.Node{topLevelNode},
102+
103+
Severity: osgraph.WarningSeverity,
104+
Key: MissingLivenessProbeWarning,
105+
Message: fmt.Sprintf("%s has no liveness probe to verify pods are still running.",
106+
topLevelString),
107+
Suggestion: osgraph.Suggestion(fmt.Sprintf("%s %s --liveness ...", setProbeCommand, topLevelString)),
108+
})
109+
}
110+
111+
return markers
112+
}
113+
114+
// hasLivenessProbe iterates through all of the containers in a podSpecNode returning true
115+
// if at least one container has a liveness probe, or false otherwise
116+
func hasLivenessProbe(podSpecNode *kubegraph.PodSpecNode) bool {
117+
for _, container := range podSpecNode.PodSpec.Containers {
118+
if container.LivenessProbe != nil {
119+
return true
120+
}
121+
}
122+
return false
123+
}
124+
125+
// hasControllerRefEdge returns true if a given node contains one or more "ManagedByController" outbound edges
126+
func hasControllerRefEdge(g osgraph.Graph, node graph.Node) bool {
127+
managedEdges := g.OutboundEdges(node, kubeedges.ManagedByControllerEdgeKind)
128+
return len(managedEdges) > 0
129+
}
130+
78131
// CheckForUnmountableSecrets checks to be sure that all the referenced secrets are mountable (by service account)
79132
func CheckForUnmountableSecrets(g osgraph.Graph, podSpecNode *kubegraph.PodSpecNode) []*kubegraph.SecretNode {
80133
saNodes := g.SuccessorNodesByNodeAndEdgeKind(podSpecNode, kubegraph.ServiceAccountNodeKind, kubeedges.ReferencedServiceAccountEdgeKind)

pkg/api/kubegraph/analysis/podspec_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,23 @@ func TestUnmountableSecrets(t *testing.T) {
8080
t.Errorf("expected %v, got %v", expectedSecret2, markers)
8181
}
8282
}
83+
84+
func TestMissingLivenessProbes(t *testing.T) {
85+
g, _, err := osgraphtest.BuildGraph("../../../api/graph/test/simple-deployment.yaml")
86+
if err != nil {
87+
t.Fatalf("unexpected error: %v", err)
88+
}
89+
90+
kubeedges.AddAllExposedPodEdges(g)
91+
92+
markers := FindMissingLivenessProbes(g, osgraph.DefaultNamer, "oc set probe")
93+
if e, a := 1, len(markers); e != a {
94+
t.Fatalf("expected %v, got %v", e, a)
95+
}
96+
97+
actualDC := osgraph.GetTopLevelContainerNode(g, markers[0].Node)
98+
expectedDC := g.Find(osgraph.UniqueName("DeploymentConfig|/simple-deployment"))
99+
if e, a := expectedDC.ID(), actualDC.ID(); e != a {
100+
t.Errorf("expected %v, got %v", e, a)
101+
}
102+
}

pkg/cmd/cli/describe/projectstatus.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,9 @@ func getMarkerScanners(logsCommandName, securityPolicyCommandFormat, setProbeCom
383383
func(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
384384
return deployanalysis.FindDeploymentConfigReadinessWarnings(g, f, setProbeCommandName)
385385
},
386+
func(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
387+
return kubeanalysis.FindMissingLivenessProbes(g, f, setProbeCommandName)
388+
},
386389
routeanalysis.FindPortMappingIssues,
387390
routeanalysis.FindMissingTLSTerminationType,
388391
routeanalysis.FindPathBasedPassthroughRoutes,

pkg/deploy/graph/edges.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
kapi "k8s.io/kubernetes/pkg/api"
77

88
osgraph "github.com/openshift/origin/pkg/api/graph"
9+
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
910
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
1011
deployapi "github.com/openshift/origin/pkg/deploy/api"
1112
deploygraph "github.com/openshift/origin/pkg/deploy/graph/nodes"
@@ -73,6 +74,7 @@ func AddDeploymentEdges(g osgraph.MutableUniqueGraph, node *deploygraph.Deployme
7374
}
7475
if BelongsToDeploymentConfig(node.DeploymentConfig, rcNode.ReplicationController) {
7576
g.AddEdge(node, rcNode, DeploymentEdgeKind)
77+
g.AddEdge(rcNode, node, kubeedges.ManagedByControllerEdgeKind)
7678
}
7779
}
7880
}

test/cmd/set-liveness-probe.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh"
3+
trap os::test::junit::reconcile_output EXIT
4+
5+
# Cleanup cluster resources created by this test
6+
(
7+
set +e
8+
oc delete all,templates --all
9+
exit 0
10+
) &>/dev/null
11+
12+
13+
os::test::junit::declare_suite_start "cmd/set-probe-liveness"
14+
# This test setting a liveness probe, without warning about replication controllers whose deployment depends on deployment configs
15+
os::cmd::expect_success_and_text 'oc create -f pkg/api/graph/test/simple-deployment.yaml' 'deploymentconfig "simple-deployment" created'
16+
os::cmd::expect_success_and_text 'oc status -v' 'dc/simple-deployment has no liveness probe'
17+
os::cmd::expect_success_and_not_text 'oc status -v' 'rc/simple-deployment-1 has no liveness probe'
18+
os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80' 'deploymentconfig "simple-deployment" updated'
19+
os::cmd::expect_success_and_not_text 'oc status -v' 'dc/simple-deployment has no liveness probe'
20+
echo "set-probe-liveness: ok"
21+
os::test::junit::declare_suite_end

0 commit comments

Comments
 (0)