2019-08-13 13:15:04 -07:00
package policy
import (
"fmt"
2019-08-14 10:01:47 -07:00
"github.com/golang/glog"
2019-11-13 13:41:08 -08:00
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
2019-08-26 13:34:42 -07:00
"github.com/nirmata/kyverno/pkg/engine"
2019-08-13 13:15:04 -07:00
"github.com/nirmata/kyverno/pkg/event"
2019-11-18 17:13:48 -08:00
"github.com/nirmata/kyverno/pkg/policyviolation"
2019-08-13 13:15:04 -07:00
)
2019-11-08 20:45:26 -08:00
// for each policy-resource response
// - has violation -> report
// - no violation -> cleanup policy violations(resource or resource owner)
func ( pc * PolicyController ) cleanupAndReport ( engineResponses [ ] engine . EngineResponse ) {
2019-11-12 14:41:29 -08:00
// generate Events
eventInfos := generateEvents ( engineResponses )
pc . eventGen . Add ( eventInfos ... )
// create policy violation
pvInfos := generatePVs ( engineResponses )
pc . pvGenerator . Add ( pvInfos ... )
// cleanup existing violations if any
// if there is any error in clean up, we dont re-queue the resource
// it will be re-tried in the next controller cache resync
pc . cleanUp ( engineResponses )
}
func ( pc * PolicyController ) cleanUp ( ers [ ] engine . EngineResponse ) {
for _ , er := range ers {
2019-11-12 16:01:09 -08:00
if ! er . IsSuccesful ( ) {
2019-11-12 14:41:29 -08:00
continue
}
2019-11-12 16:49:05 -08:00
if len ( er . PolicyResponse . Rules ) == 0 {
continue
}
2019-11-12 16:01:09 -08:00
// clean up after the policy has been corrected
2019-11-12 14:41:29 -08:00
pc . cleanUpPolicyViolation ( er . PolicyResponse )
}
}
func generatePVs ( ers [ ] engine . EngineResponse ) [ ] policyviolation . Info {
var pvInfos [ ] policyviolation . Info
for _ , er := range ers {
// ignore creation of PV for resoruces that are yet to be assigned a name
if er . PolicyResponse . Resource . Name == "" {
glog . V ( 4 ) . Infof ( "resource %v, has not been assigned a name, not creating a policy violation for it" , er . PolicyResponse . Resource )
continue
2019-11-08 20:45:26 -08:00
}
2019-11-12 14:41:29 -08:00
if er . IsSuccesful ( ) {
continue
}
glog . V ( 4 ) . Infof ( "Building policy violation for engine response %v" , er )
// build policy violation info
pvInfos = append ( pvInfos , buildPVInfo ( er ) )
2019-08-13 13:15:04 -07:00
}
2019-11-12 14:41:29 -08:00
return pvInfos
2019-08-13 13:15:04 -07:00
}
2019-11-12 14:41:29 -08:00
func buildPVInfo ( er engine . EngineResponse ) policyviolation . Info {
info := policyviolation . Info {
Blocked : false ,
PolicyName : er . PolicyResponse . Policy ,
Resource : er . PatchedResource ,
Rules : buildViolatedRules ( er ) ,
2019-08-13 13:15:04 -07:00
}
2019-11-12 14:41:29 -08:00
return info
}
func buildViolatedRules ( er engine . EngineResponse ) [ ] kyverno . ViolatedRule {
var violatedRules [ ] kyverno . ViolatedRule
for _ , rule := range er . PolicyResponse . Rules {
2019-08-26 13:34:42 -07:00
if rule . Success {
2019-11-12 14:41:29 -08:00
continue
}
vrule := kyverno . ViolatedRule {
Name : rule . Name ,
Type : rule . Type ,
Message : rule . Message ,
2019-08-13 13:15:04 -07:00
}
2019-11-12 14:41:29 -08:00
violatedRules = append ( violatedRules , vrule )
}
return violatedRules
}
func generateEvents ( ers [ ] engine . EngineResponse ) [ ] event . Info {
var eventInfos [ ] event . Info
for _ , er := range ers {
if er . IsSuccesful ( ) {
continue
}
eventInfos = append ( eventInfos , generateEventsPerEr ( er ) ... )
}
return eventInfos
}
2019-08-13 13:15:04 -07:00
2019-11-12 14:41:29 -08:00
func generateEventsPerEr ( er engine . EngineResponse ) [ ] event . Info {
var eventInfos [ ] event . Info
glog . V ( 4 ) . Infof ( "reporting results for policy '%s' application on resource '%s/%s/%s'" , er . PolicyResponse . Policy , er . PolicyResponse . Resource . Kind , er . PolicyResponse . Resource . Namespace , er . PolicyResponse . Resource . Name )
for _ , rule := range er . PolicyResponse . Rules {
if rule . Success {
continue
}
2019-08-13 13:15:04 -07:00
// generate event on resource for each failed rule
2019-11-12 14:41:29 -08:00
glog . V ( 4 ) . Infof ( "generation event on resource '%s/%s/%s' for policy '%s'" , er . PolicyResponse . Resource . Kind , er . PolicyResponse . Resource . Namespace , er . PolicyResponse . Resource . Name , er . PolicyResponse . Policy )
2019-08-26 13:34:42 -07:00
e := event . Info { }
2019-11-12 14:41:29 -08:00
e . Kind = er . PolicyResponse . Resource . Kind
e . Namespace = er . PolicyResponse . Resource . Namespace
e . Name = er . PolicyResponse . Resource . Name
2019-11-18 17:13:48 -08:00
e . Reason = event . PolicyViolation . String ( )
e . Message = fmt . Sprintf ( "policy '%s' (%s) rule '%s' not satisfied. %v" , er . PolicyResponse . Policy , rule . Type , rule . Name , rule . Message )
2019-11-12 14:41:29 -08:00
eventInfos = append ( eventInfos , e )
}
if er . IsSuccesful ( ) {
return eventInfos
2019-08-13 13:15:04 -07:00
}
2019-11-12 14:41:29 -08:00
2019-08-13 13:15:04 -07:00
// generate a event on policy for all failed rules
2019-11-12 14:41:29 -08:00
glog . V ( 4 ) . Infof ( "generation event on policy '%s'" , er . PolicyResponse . Policy )
2019-08-26 13:34:42 -07:00
e := event . Info { }
2019-09-12 15:04:35 -07:00
e . Kind = "ClusterPolicy"
2019-08-13 13:15:04 -07:00
e . Namespace = ""
2019-11-12 14:41:29 -08:00
e . Name = er . PolicyResponse . Policy
2019-11-18 17:13:48 -08:00
e . Reason = event . PolicyViolation . String ( )
e . Message = fmt . Sprintf ( "policy '%s' rules '%v' not satisfied on resource '%s/%s/%s'" , er . PolicyResponse . Policy , er . GetFailedRules ( ) , er . PolicyResponse . Resource . Kind , er . PolicyResponse . Resource . Namespace , er . PolicyResponse . Resource . Name )
2019-11-12 14:41:29 -08:00
eventInfos = append ( eventInfos , e )
return eventInfos
2019-08-13 13:15:04 -07:00
}