Skip to content

Commit

Permalink
Merge #317
Browse files Browse the repository at this point in the history
317: score/apps: StatefulSets should have a valid headless serviceName  r=zegl a=neglect-yp

<!--
    Optional: Add this change to the release notes by adding a RELNOTE comment
    If this shouldn't appear in the notes, simply remove this.
-->

```
RELNOTE: Validate serviceName of a StatefulSet 
```

This PR closes #315 

This adds `statefulset-has-servicename` that checks following rules:
- StatefulSets `.spec.serviceName` matches a Service in the same namespace.
- The Service is a Headless Service.
    > StatefulSets currently require a Headless Service to be responsible for the network identity of the Pods. You are responsible for creating this Service.
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#limitations
- The Service has a selector that matches the StatefulSet.

Co-authored-by: neglect-yp <[email protected]>
  • Loading branch information
bors[bot] and neglect-yp authored Oct 3, 2020
2 parents cedb806 + 4d47a1d commit ac55fb0
Show file tree
Hide file tree
Showing 10 changed files with 548 additions and 2 deletions.
1 change: 1 addition & 0 deletions README_CHECKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
| deployment-has-host-podantiaffinity | Deployment | Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node. https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ | default |
| statefulset-has-host-podantiaffinity | StatefulSet | Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node. https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ | default |
| deployment-targeted-by-hpa-does-not-have-replicas-configured | Deployment | Makes sure that Deployments using a HorizontalPodAutoscaler doesn't have a statically configured replica count set | default |
| statefulset-has-servicename | StatefulSet | Makes sure that StatefulSets have a existing serviceName that is headless. | default |
| label-values | all | Validates label values | default |
| horizontalpodautoscaler-has-target | HorizontalPodAutoscaler | Makes sure that the HPA targets a valid object | default |
27 changes: 26 additions & 1 deletion score/apps/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
"github.com/zegl/kube-score/scorecard"
)

func Register(allChecks *checks.Checks, allHPAs []ks.HpaTargeter) {
func Register(allChecks *checks.Checks, allHPAs []ks.HpaTargeter, allServices []ks.Service) {
allChecks.RegisterDeploymentCheck("Deployment has host PodAntiAffinity", "Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node. https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", deploymentHasAntiAffinity)
allChecks.RegisterStatefulSetCheck("StatefulSet has host PodAntiAffinity", "Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node. https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", statefulsetHasAntiAffinity)
allChecks.RegisterDeploymentCheck("Deployment targeted by HPA does not have replicas configured", "Makes sure that Deployments using a HorizontalPodAutoscaler doesn't have a statically configured replica count set", hpaDeploymentNoReplicas(allHPAs))
allChecks.RegisterStatefulSetCheck("StatefulSet has ServiceName", "Makes sure that StatefulSets have a existing headless serviceName.", statefulsetHasServiceName(allServices))
}

func hpaDeploymentNoReplicas(allHPAs []ks.HpaTargeter) func(deployment appsv1.Deployment) (scorecard.TestScore, error) {
Expand Down Expand Up @@ -133,3 +134,27 @@ func hasPodAntiAffinity(selfLables internal.MapLables, affinity *corev1.Affinity

return false
}

func statefulsetHasServiceName(allServices []ks.Service) func(statefulset appsv1.StatefulSet) (scorecard.TestScore, error) {
return func(statefulset appsv1.StatefulSet) (score scorecard.TestScore, err error) {
for _, service := range allServices {
if service.Service().Namespace != statefulset.Namespace ||
service.Service().Name != statefulset.Spec.ServiceName ||
service.Service().Spec.ClusterIP != "None" {
continue
}

if internal.LabelSelectorMatchesLabels(
service.Service().Spec.Selector,
statefulset.Spec.Template.GetObjectMeta().GetLabels(),
) {
score.Grade = scorecard.GradeAllOK
return
}
}

score.Grade = scorecard.GradeCritical
score.AddComment("", "StatefulSet does not have a valid serviceName", "StatefulSets currently require a Headless Service to be responsible for the network identity of the Pods. You are responsible for creating this Service. https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#limitations")
return
}
}
Loading

0 comments on commit ac55fb0

Please sign in to comment.