...
1
16
17 package antiaffinity
18
19 import (
20 "context"
21 "fmt"
22 "io"
23
24 "k8s.io/api/core/v1"
25 apierrors "k8s.io/apimachinery/pkg/api/errors"
26 "k8s.io/apiserver/pkg/admission"
27 api "k8s.io/kubernetes/pkg/apis/core"
28 )
29
30
31 const PluginName = "LimitPodHardAntiAffinityTopology"
32
33
34 func Register(plugins *admission.Plugins) {
35 plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
36 return NewInterPodAntiAffinity(), nil
37 })
38 }
39
40
41 type Plugin struct {
42 *admission.Handler
43 }
44
45 var _ admission.ValidationInterface = &Plugin{}
46
47
48 func NewInterPodAntiAffinity() *Plugin {
49 return &Plugin{
50 Handler: admission.NewHandler(admission.Create, admission.Update),
51 }
52 }
53
54
55
56 func (p *Plugin) Validate(ctx context.Context, attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
57
58 if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") {
59 return nil
60 }
61 pod, ok := attributes.GetObject().(*api.Pod)
62 if !ok {
63 return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
64 }
65 affinity := pod.Spec.Affinity
66 if affinity != nil && affinity.PodAntiAffinity != nil {
67 var podAntiAffinityTerms []api.PodAffinityTerm
68 if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
69 podAntiAffinityTerms = affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution
70 }
71
72
73
74
75 for _, v := range podAntiAffinityTerms {
76 if v.TopologyKey != v1.LabelHostname {
77 return apierrors.NewForbidden(attributes.GetResource().GroupResource(), pod.Name, fmt.Errorf("affinity.PodAntiAffinity.RequiredDuringScheduling has TopologyKey %v but only key %v is allowed", v.TopologyKey, v1.LabelHostname))
78 }
79 }
80 }
81 return nil
82 }
83
View as plain text