2019-07-15 16:07:56 -07:00
package webhooks
import (
"github.com/golang/glog"
engine "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/info"
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"
"k8s.io/apimachinery/pkg/labels"
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-08-14 19:00:37 -07:00
func ( ws * WebhookServer ) HandleMutation ( request * v1beta1 . AdmissionRequest ) ( bool , engine . EngineResponse ) {
2019-08-09 12:59:37 -07:00
var patches [ ] [ ] byte
2019-08-09 16:55:43 -07:00
var policyInfos [ ] info . PolicyInfo
2019-08-20 12:51:25 -07:00
var policyStats [ ] policyctr . PolicyStat
// gather stats from the engine response
gatherStat := func ( policyName string , er engine . EngineResponse ) {
ps := policyctr . PolicyStat { }
ps . PolicyName = policyName
ps . MutationExecutionTime = er . ExecutionTime
ps . RulesAppliedCount = er . RulesAppliedCount
policyStats = append ( policyStats , ps )
}
// send stats for aggregation
sendStat := func ( blocked bool ) {
for _ , stat := range policyStats {
stat . ResourceBlocked = blocked
//SEND
ws . policyStatus . SendStat ( stat )
}
}
2019-08-14 11:51:01 -07:00
2019-08-14 19:00:37 -07:00
glog . V ( 5 ) . 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
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 {
glog . Errorf ( "unable to convert raw resource to unstructured: %v" , err )
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,
// 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 } )
//TODO: check if the name and namespace is also passed right in the resource?
2019-08-14 19:00:37 -07:00
engineResponse := engine . EngineResponse { PatchedResource : * resource }
2019-07-21 14:13:00 -07:00
2019-08-14 19:00:37 -07:00
policies , err := ws . pLister . List ( labels . NewSelector ( ) )
2019-07-15 16:07:56 -07:00
if err != nil {
2019-08-14 19:00:37 -07:00
//TODO check if the CRD is created ?
2019-07-15 16:07:56 -07:00
// Unable to connect to policy Lister to access policies
2019-08-14 11:51:01 -07:00
glog . Errorln ( "Unable to connect to policy controller to access policies. Mutation Rules are NOT being applied" )
2019-07-15 16:07:56 -07:00
glog . Warning ( err )
2019-08-14 15:18:46 -07:00
return true , engineResponse
2019-07-15 16:07:56 -07:00
}
2019-08-14 11:51:01 -07:00
2019-07-15 16:07:56 -07:00
for _ , policy := range policies {
2019-08-14 11:51:01 -07:00
2019-07-15 16:07:56 -07:00
// check if policy has a rule for the admission request kind
2019-08-17 09:45:57 -07:00
if ! utils . Contains ( getApplicableKindsForPolicy ( policy ) , request . Kind . Kind ) {
2019-07-15 16:07:56 -07:00
continue
}
2019-08-09 13:41:56 -07:00
policyInfo := info . NewPolicyInfo ( policy . Name , resource . GetKind ( ) , resource . GetName ( ) , resource . GetNamespace ( ) , policy . Spec . ValidationFailureAction )
2019-07-15 16:07:56 -07:00
2019-08-09 12:59:37 -07:00
glog . V ( 4 ) . Infof ( "Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s" ,
resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , request . UID , request . Operation )
glog . V ( 4 ) . Infof ( "Applying policy %s with %d rules\n" , policy . ObjectMeta . Name , len ( policy . Spec . Rules ) )
2019-07-15 16:07:56 -07:00
2019-08-14 19:00:37 -07:00
engineResponse = engine . Mutate ( * policy , * resource )
2019-08-14 15:18:46 -07:00
policyInfo . AddRuleInfos ( engineResponse . RuleInfos )
2019-08-20 12:51:25 -07:00
// Gather policy application statistics
gatherStat ( policy . Name , engineResponse )
// ps := policyctr.NewPolicyStat(policy.Name, engineResponse.ExecutionTime, nil, engineResponse.RulesAppliedCount)
2019-07-15 16:07:56 -07:00
if ! policyInfo . IsSuccessful ( ) {
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
glog . V ( 4 ) . Info ( "Failed rule details" )
2019-08-14 15:18:46 -07:00
for _ , r := range engineResponse . RuleInfos {
2019-08-09 12:59:37 -07:00
glog . V ( 4 ) . Infof ( "%s: %s\n" , r . Name , r . Msgs )
2019-07-15 16:07:56 -07:00
}
2019-08-09 12:59:37 -07:00
continue
2019-07-15 16:07:56 -07:00
}
2019-08-19 16:10:10 -07:00
2019-08-14 19:00:37 -07:00
patches = append ( patches , engineResponse . Patches ... )
2019-08-19 16:10:10 -07:00
policyInfos = append ( policyInfos , policyInfo )
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-20 12:51:25 -07:00
2019-07-15 16:07:56 -07:00
}
2019-08-09 12:59:37 -07:00
// ADD ANNOTATIONS
// ADD EVENTS
2019-08-09 17:28:49 -07:00
if len ( patches ) > 0 {
2019-08-14 10:01:47 -07:00
eventsInfo := newEventInfoFromPolicyInfo ( policyInfos , ( request . Operation == v1beta1 . Update ) , info . Mutation )
2019-08-09 17:28:49 -07:00
ws . eventGen . Add ( eventsInfo ... )
2019-08-19 16:10:10 -07:00
annotation := prepareAnnotationPatches ( resource , policyInfos )
patches = append ( patches , annotation )
2019-07-15 16:07:56 -07:00
}
2019-08-14 11:51:01 -07:00
2019-07-15 16:07:56 -07:00
ok , msg := isAdmSuccesful ( policyInfos )
2019-08-20 12:51:25 -07:00
// Send policy engine Stats
2019-07-15 16:07:56 -07:00
if ok {
2019-08-20 12:51:25 -07:00
sendStat ( false )
2019-08-14 19:00:37 -07:00
engineResponse . Patches = patches
2019-08-14 15:18:46 -07:00
return true , engineResponse
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-14 11:51:01 -07:00
glog . Errorf ( "Failed to mutate the resource: %s\n" , msg )
2019-08-14 15:18:46 -07:00
return false , engineResponse
2019-07-15 16:07:56 -07:00
}