2019-07-15 16:07:56 -07:00
package webhooks
import (
"github.com/golang/glog"
2019-11-07 12:13:16 -08:00
"github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
2019-07-15 16:07:56 -07:00
engine "github.com/nirmata/kyverno/pkg/engine"
2019-08-20 12:51:25 -07:00
policyctr "github.com/nirmata/kyverno/pkg/policy"
2019-08-17 09:45:57 -07:00
"github.com/nirmata/kyverno/pkg/utils"
2019-07-15 16:07:56 -07:00
v1beta1 "k8s.io/api/admission/v1beta1"
2019-08-09 12:59:37 -07:00
"k8s.io/apimachinery/pkg/runtime/schema"
2019-07-15 16:07:56 -07:00
)
// HandleMutation handles mutating webhook admission request
2019-11-08 18:57:27 -08:00
func ( ws * WebhookServer ) HandleMutation ( request * v1beta1 . AdmissionRequest ,
policies [ ] * v1alpha1 . ClusterPolicy , roles , clusterRoles [ ] string ) ( bool , [ ] byte , string ) {
2019-08-23 18:34:23 -07:00
glog . V ( 4 ) . Infof ( "Receive request in mutating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s" ,
request . Kind . Kind , request . Namespace , request . Name , request . UID , request . Operation )
2019-08-09 12:59:37 -07:00
var patches [ ] [ ] byte
2019-08-20 12:51:25 -07:00
var policyStats [ ] policyctr . PolicyStat
2019-08-23 18:34:23 -07:00
2019-08-20 12:51:25 -07:00
// gather stats from the engine response
2019-08-23 18:34:23 -07:00
gatherStat := func ( policyName string , policyResponse engine . PolicyResponse ) {
2019-08-20 12:51:25 -07:00
ps := policyctr . PolicyStat { }
ps . PolicyName = policyName
2019-08-23 18:34:23 -07:00
ps . Stats . MutationExecutionTime = policyResponse . ProcessingTime
ps . Stats . RulesAppliedCount = policyResponse . RulesAppliedCount
2019-09-03 17:43:36 -07:00
// capture rule level stats
for _ , rule := range policyResponse . Rules {
rs := policyctr . RuleStatinfo { }
rs . RuleName = rule . Name
rs . ExecutionTime = rule . RuleStats . ProcessingTime
if rule . Success {
rs . RuleAppliedCount ++
} else {
rs . RulesFailedCount ++
}
2019-09-03 18:31:57 -07:00
if rule . Patches != nil {
rs . MutationCount ++
}
2019-09-03 17:43:36 -07:00
ps . Stats . Rules = append ( ps . Stats . Rules , rs )
}
2019-08-20 12:51:25 -07:00
policyStats = append ( policyStats , ps )
}
// send stats for aggregation
sendStat := func ( blocked bool ) {
for _ , stat := range policyStats {
2019-08-20 16:40:20 -07:00
stat . Stats . ResourceBlocked = utils . Btoi ( blocked )
2019-08-20 12:51:25 -07:00
//SEND
ws . policyStatus . SendStat ( stat )
}
}
2019-08-23 18:34:23 -07:00
// convert RAW to unstructured
2019-08-14 19:00:37 -07:00
resource , err := engine . ConvertToUnstructured ( request . Object . Raw )
2019-08-09 12:59:37 -07:00
if err != nil {
2019-08-23 18:34:23 -07:00
//TODO: skip applying the amiddions control ?
2019-08-09 12:59:37 -07:00
glog . Errorf ( "unable to convert raw resource to unstructured: %v" , err )
2019-08-23 18:34:23 -07:00
return true , nil , ""
2019-08-14 11:51:01 -07:00
}
2019-07-15 16:07:56 -07:00
2019-08-09 12:59:37 -07:00
//TODO: check if resource gvk is available in raw resource,
2019-08-23 18:34:23 -07:00
//TODO: check if the name and namespace is also passed right in the resource?
2019-08-09 12:59:37 -07:00
// if not then set it from the api request
resource . SetGroupVersionKind ( schema . GroupVersionKind { Group : request . Kind . Group , Version : request . Kind . Version , Kind : request . Kind . Kind } )
2019-08-14 11:51:01 -07:00
2019-10-08 10:57:24 -07:00
var engineResponses [ ] engine . EngineResponse
2019-11-08 18:57:27 -08:00
policyContext := engine . PolicyContext {
Resource : * resource ,
AdmissionInfo : engine . RequestInfo {
Roles : roles ,
ClusterRoles : clusterRoles ,
AdmissionUserInfo : request . UserInfo } ,
}
2019-08-14 11:51:01 -07:00
2019-11-08 18:57:27 -08:00
for _ , policy := range policies {
policyContext . Policy = * policy
2019-07-15 16:07:56 -07:00
// check if policy has a rule for the admission request kind
2019-09-12 17:11:55 -07:00
if ! utils . ContainsString ( getApplicableKindsForPolicy ( policy ) , request . Kind . Kind ) {
2019-07-15 16:07:56 -07:00
continue
}
2019-10-23 23:18:58 -07:00
glog . V ( 2 ) . Infof ( "Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s" ,
2019-08-09 12:59:37 -07:00
resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , request . UID , request . Operation )
2019-08-23 18:34:23 -07:00
// TODO: this can be
2019-11-08 18:57:27 -08:00
engineResponse := engine . Mutate ( policyContext )
2019-08-23 18:34:23 -07:00
engineResponses = append ( engineResponses , engineResponse )
2019-08-20 12:51:25 -07:00
// Gather policy application statistics
2019-08-23 18:34:23 -07:00
gatherStat ( policy . Name , engineResponse . PolicyResponse )
if ! engineResponse . IsSuccesful ( ) {
2019-08-14 19:00:37 -07:00
glog . V ( 4 ) . Infof ( "Failed to apply policy %s on resource %s/%s\n" , policy . Name , resource . GetNamespace ( ) , resource . GetName ( ) )
2019-08-09 12:59:37 -07:00
continue
2019-07-15 16:07:56 -07:00
}
2019-08-23 18:34:23 -07:00
// gather patches
2019-08-26 16:10:19 -07:00
patches = append ( patches , engineResponse . GetPatches ( ) ... )
2019-10-07 18:31:14 -07:00
2019-08-09 12:59:37 -07:00
glog . V ( 4 ) . Infof ( "Mutation from policy %s has applied succesfully to %s %s/%s" , policy . Name , request . Kind . Kind , resource . GetNamespace ( ) , resource . GetName ( ) )
2019-08-23 18:34:23 -07:00
//TODO: check if there is an order to policy application on resource
// resource = &engineResponse.PatchedResource
2019-07-15 16:07:56 -07:00
}
2019-10-07 18:31:14 -07:00
// generate annotations
2019-11-11 18:52:26 -08:00
if annPatches := generateAnnotationPatches ( engineResponses ) ; annPatches != nil {
2019-10-07 18:31:14 -07:00
patches = append ( patches , annPatches )
}
2019-08-09 12:59:37 -07:00
// ADD EVENTS
2019-08-26 13:34:42 -07:00
events := generateEvents ( engineResponses , ( request . Operation == v1beta1 . Update ) )
ws . eventGen . Add ( events ... )
2019-08-23 18:34:23 -07:00
if isResponseSuccesful ( engineResponses ) {
2019-08-20 12:51:25 -07:00
sendStat ( false )
2019-08-23 18:34:23 -07:00
patch := engine . JoinPatches ( patches )
return true , patch , ""
2019-07-15 16:07:56 -07:00
}
2019-08-14 11:51:01 -07:00
2019-08-20 12:51:25 -07:00
sendStat ( true )
2019-08-23 18:34:23 -07:00
glog . Errorf ( "Failed to mutate the resource\n" )
return false , nil , getErrorMsg ( engineResponses )
2019-07-15 16:07:56 -07:00
}