2019-07-15 16:07:56 -07:00
package webhooks
import (
2019-07-17 17:53:13 -07:00
jsonpatch "github.com/evanphx/json-patch"
2019-07-15 16:07:56 -07:00
"github.com/golang/glog"
engine "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/info"
v1beta1 "k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)
// HandleValidation handles validating webhook admission request
// If there are no errors in validating rule we apply generation rules
func ( ws * WebhookServer ) HandleValidation ( request * v1beta1 . AdmissionRequest ) * v1beta1 . AdmissionResponse {
2019-07-23 17:54:31 -07:00
glog . V ( 4 ) . Infof ( "Receive request in validating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s" ,
2019-07-21 14:13:00 -07:00
request . Kind . Kind , request . Namespace , request . Name , request . UID , request . Operation )
2019-07-15 16:07:56 -07:00
policyInfos := [ ] * info . PolicyInfo { }
policies , err := ws . policyLister . List ( labels . NewSelector ( ) )
if err != nil {
// Unable to connect to policy Lister to access policies
glog . Error ( "Unable to connect to policy controller to access policies. Validation Rules are NOT being applied" )
glog . Warning ( err )
return & v1beta1 . AdmissionResponse {
Allowed : true ,
}
}
2019-07-17 23:13:28 -07:00
2019-07-17 17:53:13 -07:00
rname := engine . ParseNameFromObject ( request . Object . Raw )
rns := engine . ParseNamespaceFromObject ( request . Object . Raw )
2019-07-20 23:58:46 -07:00
rkind := request . Kind . Kind
if rkind == "" {
2019-07-21 14:13:00 -07:00
glog . Errorf ( "failed to parse KIND from request: Namespace=%s Name=%s UID=%s patchOperation=%s\n" , request . Namespace , request . Name , request . UID , request . Operation )
2019-07-20 23:58:46 -07:00
}
2019-07-15 16:07:56 -07:00
2019-07-17 17:53:13 -07:00
var annPatches [ ] byte
2019-07-15 16:07:56 -07:00
for _ , policy := range policies {
if ! StringInSlice ( request . Kind . Kind , getApplicableKindsForPolicy ( policy ) ) {
continue
}
2019-07-19 12:47:20 -07:00
//TODO: HACK Check if an update of annotations
if checkIfOnlyAnnotationsUpdate ( request ) {
// allow the update of resource to add annotations
return & v1beta1 . AdmissionResponse {
Allowed : true ,
}
}
2019-07-15 16:07:56 -07:00
policyInfo := info . NewPolicyInfo ( policy . Name ,
rkind ,
rname ,
2019-07-15 19:14:42 -07:00
rns ,
policy . Spec . ValidationFailureAction )
2019-07-15 16:07:56 -07:00
glog . V ( 3 ) . Infof ( "Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s" ,
request . Kind . Kind , rns , rname , request . UID , request . Operation )
glog . Infof ( "Validating resource %s/%s/%s with policy %s with %d rules" , rkind , rns , rname , policy . ObjectMeta . Name , len ( policy . Spec . Rules ) )
ruleInfos , err := engine . Validate ( * policy , request . Object . Raw , request . Kind )
if err != nil {
// This is not policy error
// but if unable to parse request raw resource
// TODO : create event ? dont think so
glog . Error ( err )
continue
}
policyInfo . AddRuleInfos ( ruleInfos )
if ! policyInfo . IsSuccessful ( ) {
glog . Infof ( "Failed to apply policy %s on resource %s/%s" , policy . Name , rname , rns )
for _ , r := range ruleInfos {
2019-07-19 17:52:24 -07:00
glog . Warningf ( "%s: %s\n" , r . Name , r . Msgs )
2019-07-15 16:07:56 -07:00
}
} else {
2019-07-18 10:22:20 -07:00
// CleanUp Violations if exists
err := ws . violationBuilder . RemoveInactiveViolation ( policy . Name , request . Kind . Kind , rns , rname , info . Validation )
if err != nil {
glog . Info ( err )
}
2019-07-15 16:07:56 -07:00
if len ( ruleInfos ) > 0 {
glog . Infof ( "Validation from policy %s has applied succesfully to %s %s/%s" , policy . Name , request . Kind . Kind , rname , rns )
}
}
policyInfos = append ( policyInfos , policyInfo )
2019-07-19 15:10:40 -07:00
// annotations
2019-07-17 23:13:28 -07:00
annPatch := addAnnotationsToResource ( request . Object . Raw , policyInfo , info . Validation )
2019-07-17 17:53:13 -07:00
if annPatch != nil {
if annPatches == nil {
annPatches = annPatch
} else {
annPatches , err = jsonpatch . MergePatch ( annPatches , annPatch )
if err != nil {
glog . Error ( err )
}
}
}
2019-07-15 16:07:56 -07:00
}
if len ( policyInfos ) > 0 && len ( policyInfos [ 0 ] . Rules ) != 0 {
2019-07-18 10:22:20 -07:00
eventsInfo , violations := newEventInfoFromPolicyInfo ( policyInfos , ( request . Operation == v1beta1 . Update ) , info . Validation )
2019-07-15 19:14:42 -07:00
// If the validationFailureAction flag is set "report",
// then we dont block the request and report the violations
2019-07-18 10:22:20 -07:00
ws . violationBuilder . Add ( violations ... )
2019-07-15 16:07:56 -07:00
ws . eventController . Add ( eventsInfo ... )
}
2019-07-17 23:13:28 -07:00
// add annotations
2019-07-17 17:53:13 -07:00
if annPatches != nil {
ws . annotationsController . Add ( rkind , rns , rname , annPatches )
}
2019-07-15 16:07:56 -07:00
// If Validation fails then reject the request
ok , msg := isAdmSuccesful ( policyInfos )
2019-07-15 19:14:42 -07:00
// violations are created if "report" flag is set
// and if there are any then we dont bock the resource creation
// Even if one the policy being applied
2019-07-16 15:53:14 -07:00
if ! ok && toBlock ( policyInfos ) {
2019-07-15 16:07:56 -07:00
return & v1beta1 . AdmissionResponse {
Allowed : false ,
Result : & metav1 . Status {
Message : msg ,
} ,
}
}
return & v1beta1 . AdmissionResponse {
Allowed : true ,
}
// Generation rules applied via generation controller
}