@@ -4,11 +4,13 @@ import (
44 "context"
55 "fmt"
66 "net/http"
7+ "strconv"
78 "strings"
89
910 admissionv1 "k8s.io/api/admission/v1"
1011 appsv1 "k8s.io/api/apps/v1"
1112 corev1 "k8s.io/api/core/v1"
13+ apierrors "k8s.io/apimachinery/pkg/api/errors"
1214 "k8s.io/apimachinery/pkg/api/resource"
1315 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1416
@@ -18,6 +20,7 @@ import (
1820)
1921
2022// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch
23+ // +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
2124
2225// RatioValidator checks for every action in a namespace whether the Memory to CPU ratio limit is exceeded and will return a warning if it is.
2326type RatioValidator struct {
@@ -27,6 +30,9 @@ type RatioValidator struct {
2730 RatioLimit * resource.Quantity
2831}
2932
33+ // RatioValidatiorDisableAnnotation is the key for an annotion on a namespace to disable request ratio warnings
34+ var RatioValidatiorDisableAnnotation = "validate-request-ratio.appuio.io/disable"
35+
3036// Handle handles the admission requests
3137func (v * RatioValidator ) Handle (ctx context.Context , req admission.Request ) admission.Response {
3238 l := log .FromContext (ctx ).
@@ -40,6 +46,19 @@ func (v *RatioValidator) Handle(ctx context.Context, req admission.Request) admi
4046 return admission .Allowed ("system user" )
4147 }
4248
49+ disabled , err := v .isNamespaceDisabled (ctx , req .Namespace )
50+ if err != nil {
51+ l .Error (err , "failed to get namespace" )
52+ if apierrors .IsNotFound (err ) {
53+ return errored (http .StatusNotFound , err )
54+ }
55+ return errored (http .StatusInternalServerError , err )
56+ }
57+ if disabled {
58+ l .V (1 ).Info ("allowed: warning disabled" )
59+ return admission .Allowed ("system user" )
60+ }
61+
4362 r , err := v .getRatio (ctx , req .Namespace )
4463 if err != nil {
4564 l .Error (err , "failed to get ratio" )
@@ -50,28 +69,10 @@ func (v *RatioValidator) Handle(ctx context.Context, req admission.Request) admi
5069 // If we are creating an object with resource requests, we add them to the current ratio
5170 // We cannot easily do this when updating resources.
5271 if req .Operation == admissionv1 .Create {
53- switch req .Kind .Kind {
54- case "Pod" :
55- pod := corev1.Pod {}
56- if err := v .decoder .Decode (req , & pod ); err != nil {
57- l .Error (err , "failed to decode pod" )
58- return errored (http .StatusBadRequest , err )
59- }
60- r = r .RecordPod (pod )
61- case "Deployment" :
62- deploy := appsv1.Deployment {}
63- if err := v .decoder .Decode (req , & deploy ); err != nil {
64- l .Error (err , "failed to decode deployment" )
65- return errored (http .StatusBadRequest , err )
66- }
67- r = r .RecordDeployment (deploy )
68- case "StatefulSet" :
69- sts := appsv1.StatefulSet {}
70- if err := v .decoder .Decode (req , & sts ); err != nil {
71- l .Error (err , "failed to decode statefulset" )
72- return errored (http .StatusBadRequest , err )
73- }
74- r = r .RecordStatefulSet (sts )
72+ r , err = v .recordObject (ctx , r , req )
73+ if err != nil {
74+ l .Error (err , "failed to record object" )
75+ return errored (http .StatusBadRequest , err )
7576 }
7677 }
7778 l = l .WithValues ("ratio" , r .String ())
@@ -91,6 +92,46 @@ func (v *RatioValidator) Handle(ctx context.Context, req admission.Request) admi
9192 return admission .Allowed ("ok" )
9293}
9394
95+ func (v * RatioValidator ) recordObject (ctx context.Context , r * Ratio , req admission.Request ) (* Ratio , error ) {
96+ switch req .Kind .Kind {
97+ case "Pod" :
98+ pod := corev1.Pod {}
99+ if err := v .decoder .Decode (req , & pod ); err != nil {
100+ return r , err
101+ }
102+ r = r .RecordPod (pod )
103+ case "Deployment" :
104+ deploy := appsv1.Deployment {}
105+ if err := v .decoder .Decode (req , & deploy ); err != nil {
106+ return r , err
107+ }
108+ r = r .RecordDeployment (deploy )
109+ case "StatefulSet" :
110+ sts := appsv1.StatefulSet {}
111+ if err := v .decoder .Decode (req , & sts ); err != nil {
112+ return r , err
113+ }
114+ r = r .RecordStatefulSet (sts )
115+ }
116+ return r , nil
117+ }
118+
119+ func (v * RatioValidator ) isNamespaceDisabled (ctx context.Context , nsName string ) (bool , error ) {
120+ ns := corev1.Namespace {}
121+ err := v .client .Get (ctx , client.ObjectKey {
122+ Name : nsName ,
123+ }, & ns )
124+ if err != nil {
125+ return false , err
126+ }
127+
128+ disabled , ok := ns .Annotations [RatioValidatiorDisableAnnotation ]
129+ if ! ok {
130+ return false , nil
131+ }
132+ return strconv .ParseBool (disabled )
133+ }
134+
94135func (v * RatioValidator ) getRatio (ctx context.Context , ns string ) (* Ratio , error ) {
95136 r := NewRatio ()
96137 pods := corev1.PodList {}
0 commit comments