1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-08 18:15:48 +00:00

cleanup event messages and sources (#3741)

* cleanup events

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix sonatype issues

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Jim Bugwadia 2022-05-01 22:14:32 -07:00 committed by GitHub
parent 655e2a74d7
commit 4f8eab76ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 176 additions and 293 deletions

View file

@ -1,47 +0,0 @@
package common
import (
"fmt"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/event"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
var ErrEmptyPatch error = fmt.Errorf("empty resource to patch")
func FailedEvents(err error, policy, rule string, source event.Source, resource *unstructured.Unstructured, logger logr.Logger) []event.Info {
if resource == nil {
logger.WithName("FailedEvents").Error(ErrEmptyPatch, "", "rule", rule)
return nil
}
re := newEvent(policy, rule, source, *resource)
re.Reason = event.PolicyFailed.String()
re.Message = fmt.Sprintf("policy %s/%s failed to apply to %s/%s/%s: %v", policy, rule, resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
return []event.Info{re}
}
func SucceedEvents(policy, rule string, source event.Source, resource *unstructured.Unstructured, logger logr.Logger) []event.Info {
if resource == nil {
logger.WithName("SucceedEvents").Error(ErrEmptyPatch, "", "rule", rule)
return nil
}
re := newEvent(policy, rule, source, *resource)
re.Reason = event.PolicyApplied.String()
re.Message = fmt.Sprintf("policy %s/%s applied to %s/%s/%s successfully", policy, rule, resource.GetKind(), resource.GetNamespace(), resource.GetName())
return []event.Info{re}
}
func newEvent(policy, rule string, source event.Source, resource unstructured.Unstructured) (re event.Info) {
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Source = source
return
}

View file

@ -168,7 +168,7 @@ func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
}
// 3 - Report failure Events
events := common.FailedEvents(err, ur.Spec.Policy, "", event.GeneratePolicyController, resource, logger)
events := event.NewBackgroundFailedEvent(err, ur.Spec.Policy, "", event.GeneratePolicyController, resource)
c.eventGen.Add(events...)
}

View file

@ -23,6 +23,8 @@ import (
cache "k8s.io/client-go/tools/cache"
)
var ErrEmptyPatch error = fmt.Errorf("empty resource to patch")
type MutateExistingController struct {
client *dclient.Client
@ -128,7 +130,7 @@ func (c *MutateExistingController) ProcessUR(ur *urkyverno.UpdateRequest) error
}
if patchedNew == nil {
logger.Error(common.ErrEmptyPatch, "", "rule", r.Name, "message", r.Message)
logger.Error(ErrEmptyPatch, "", "rule", r.Name, "message", r.Message)
errs = append(errs, err)
continue
}
@ -172,9 +174,9 @@ func (c *MutateExistingController) report(err error, policy, rule string, target
}
if err != nil {
events = common.FailedEvents(err, policy, rule, event.MutateExistingController, target, c.log)
events = event.NewBackgroundFailedEvent(err, policy, rule, event.MutateExistingController, target)
} else {
events = common.SucceedEvents(policy, rule, event.MutateExistingController, target, c.log)
events = event.NewBackgroundSuccessEvent(policy, rule, event.MutateExistingController, target)
}
c.eventGen.Add(events...)

View file

@ -127,7 +127,7 @@ type RuleStats struct {
RuleExecutionTimestamp int64 `json:"ruleExecutionTimestamp"`
}
//IsSuccessful checks if any rule has failed or not
//IsSuccessful checks if any rule has failed or produced an error during execution
func (er EngineResponse) IsSuccessful() bool {
for _, r := range er.PolicyResponse.Rules {
if r.Status == RuleStatusFail || r.Status == RuleStatusError {

View file

@ -1,24 +0,0 @@
package event
import (
"fmt"
"testing"
"gotest.tools/assert"
)
func TestPositive(t *testing.T) {
resourceName := "test_resource"
ruleName := "test_rule"
expectedMsg := fmt.Sprintf("Rule(s) '%s' failed to apply on resource %s", ruleName, resourceName)
msg, err := getEventMsg(FPolicyApply, ruleName, resourceName)
assert.NilError(t, err)
assert.Equal(t, expectedMsg, msg)
}
// passing incorrect args
func TestIncorrectArgs(t *testing.T) {
resourceName := "test_resource"
_, err := getEventMsg(FPolicyApply, resourceName, "extra_args1", "extra_args2")
assert.Error(t, err, "message expects 2 arguments, but 3 arguments passed")
}

View file

@ -73,7 +73,7 @@ func rateLimiter() workqueue.RateLimiter {
}
func initRecorder(client *client.Client, eventSource Source, log logr.Logger) record.EventRecorder {
// Initliaze Event Broadcaster
// Initialize Event Broadcaster
err := scheme.AddToScheme(scheme.Scheme)
if err != nil {
log.Error(err, "failed to add to scheme")
@ -234,28 +234,3 @@ func (gen *Generator) syncHandler(key Info) error {
}
return nil
}
//NewEvent builds a event creation request
func NewEvent(
log logr.Logger,
rkind,
rapiVersion,
rnamespace,
rname,
reason string,
source Source,
message MsgKey,
args ...interface{}) Info {
msgText, err := getEventMsg(message, args...)
if err != nil {
log.Error(err, "failed to get event message")
}
return Info{
Kind: rkind,
Name: rname,
Namespace: rnamespace,
Reason: reason,
Source: source,
Message: msgText,
}
}

124
pkg/event/events.go Normal file
View file

@ -0,0 +1,124 @@
package event
import (
"fmt"
"strings"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func NewPolicyFailEvent(source Source, reason Reason, engineResponse *response.EngineResponse, ruleResp *response.RuleResponse, blocked bool) *Info {
msg := buildPolicyEventMessage(ruleResp, engineResponse.GetResourceSpec(), blocked)
return &Info{
Kind: getPolicyKind(engineResponse.Policy),
Name: engineResponse.PolicyResponse.Policy.Name,
Namespace: engineResponse.PolicyResponse.Policy.Namespace,
Reason: reason.String(),
Source: source,
Message: msg,
}
}
func buildPolicyEventMessage(resp *response.RuleResponse, resource response.ResourceSpec, blocked bool) string {
var b strings.Builder
if resource.Namespace != "" {
fmt.Fprintf(&b, "%s %s/%s", resource.Kind, resource.Namespace, resource.Name)
} else {
fmt.Fprintf(&b, "%s %s", resource.Kind, resource.Name)
}
fmt.Fprintf(&b, ": %s", resp.Status.String())
if blocked {
fmt.Fprintf(&b, " (blocked)")
}
if resp.Status == response.RuleStatusError && resp.Message != "" {
fmt.Fprintf(&b, "; %s", resp.Status.String())
}
return b.String()
}
func getPolicyKind(policy v1.PolicyInterface) string {
if policy.IsNamespaced() {
return "Policy"
}
return "ClusterPolicy"
}
func NewPolicyAppliedEvent(source Source, engineResponse *response.EngineResponse) *Info {
resource := engineResponse.PolicyResponse.Resource
var msg string
if resource.Namespace != "" {
msg = fmt.Sprintf("%s %s/%s: pass", resource.Kind, resource.Namespace, resource.Name)
} else {
msg = fmt.Sprintf("%s %s: pass", resource.Kind, resource.Name)
}
return &Info{
Kind: getPolicyKind(engineResponse.Policy),
Name: engineResponse.PolicyResponse.Policy.Name,
Namespace: engineResponse.PolicyResponse.Policy.Namespace,
Reason: PolicyApplied.String(),
Source: source,
Message: msg,
}
}
func NewResourceViolationEvent(source Source, reason Reason, engineResponse *response.EngineResponse, ruleResp *response.RuleResponse) *Info {
policyName := engineResponse.Policy.GetName()
status := ruleResp.Status.String()
msg := fmt.Sprintf("policy %s/%s %s: %s", policyName, ruleResp.Name, status, ruleResp.Message)
resource := engineResponse.GetResourceSpec()
return &Info{
Kind: resource.Kind,
Name: resource.Name,
Namespace: resource.Namespace,
Reason: reason.String(),
Source: source,
Message: msg,
}
}
func NewBackgroundFailedEvent(err error, policy, rule string, source Source, r *unstructured.Unstructured) []Info {
if r == nil {
return nil
}
var events []Info
events = append(events, Info{
Kind: r.GetKind(),
Namespace: r.GetNamespace(),
Name: r.GetName(),
Source: source,
Reason: PolicyError.String(),
Message: fmt.Sprintf("policy %s/%s error: %v", policy, rule, err),
})
return events
}
func NewBackgroundSuccessEvent(policy, rule string, source Source, r *unstructured.Unstructured) []Info {
if r == nil {
return nil
}
var events []Info
msg := fmt.Sprintf("policy %s/%s applied", policy, rule)
events = append(events, Info{
Kind: r.GetKind(),
Namespace: r.GetNamespace(),
Name: r.GetName(),
Source: source,
Reason: PolicyApplied.String(),
Message: msg,
})
return events
}

View file

@ -1,39 +0,0 @@
package event
import (
"fmt"
"regexp"
)
//MsgKey is an identifier to determine the preset message formats
type MsgKey int
//Message id for pre-defined messages
const (
FPolicyApply = iota
FResourcePolicyApply
SPolicyApply
)
func (k MsgKey) String() string {
return [...]string{
"Rule(s) '%s' failed to apply on resource %s",
"Rule(s) '%s' of policy '%s' failed to apply on the resource",
"Rule(s) '%s' successfully applied on resource %s",
}[k]
}
const argRegex = "%[s,d,v]"
var re = regexp.MustCompile(argRegex)
//GetEventMsg return the application message based on the message id and the arguments,
// if the number of arguments passed to the message are incorrect generate an error
func getEventMsg(key MsgKey, args ...interface{}) (string, error) {
// Verify the number of arguments
argsCount := len(re.FindAllString(key.String(), -1))
if argsCount != len(args) {
return "", fmt.Errorf("message expects %d arguments, but %d arguments passed", argsCount, len(args))
}
return fmt.Sprintf(key.String(), args...), nil
}

View file

@ -4,18 +4,15 @@ package event
type Reason int
const (
//PolicyViolation there is a violation of policy
PolicyViolation Reason = iota
//PolicyApplied policy applied
PolicyApplied
//PolicyFailed policy failed
PolicyFailed
PolicyError
)
func (r Reason) String() string {
return [...]string{
"PolicyViolation",
"PolicyApplied",
"PolicyFailed",
"PolicyError",
}[r]
}

View file

@ -16,9 +16,9 @@ const (
func (s Source) String() string {
return [...]string{
"admission-controller",
"policy-controller",
"generate-policy-controller",
"mutate-existing-controller",
"kyverno-admission",
"kyverno-scan",
"kyverno-generate",
"kyverno-mutate",
}[s]
}

View file

@ -167,25 +167,13 @@ func (pc *PolicyController) requeuePolicies() {
func generateSuccessEvents(log logr.Logger, ers []*response.EngineResponse) (eventInfos []event.Info) {
for _, er := range ers {
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)
logger.V(4).Info("reporting success results for policy")
if !er.IsFailed() {
// generate event on policy for success rules
logger.V(4).Info("generating event on policy for success rules")
e := event.Info{}
kind := "ClusterPolicy"
if er.PolicyResponse.Policy.Namespace != "" {
kind = "Policy"
}
e.Kind = kind
e.Namespace = er.PolicyResponse.Policy.Namespace
e.Name = er.PolicyResponse.Policy.Name
e.Reason = event.PolicyApplied.String()
e.Source = event.PolicyController
e.Message = fmt.Sprintf("rules '%v' successfully applied on resource '%s/%s/%s'", er.GetSuccessRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
eventInfos = append(eventInfos, e)
e := event.NewPolicyAppliedEvent(event.PolicyController, er)
eventInfos = append(eventInfos, *e)
}
}
return eventInfos
}
@ -198,59 +186,26 @@ func generateFailEvents(log logr.Logger, ers []*response.EngineResponse) (eventI
func generateFailEventsPerEr(log logr.Logger, er *response.EngineResponse) []event.Info {
var eventInfos []event.Info
logger := log.WithValues("policy", er.PolicyResponse.Policy.Name,
"kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace,
"name", er.PolicyResponse.Resource.Name)
logger := log.WithValues("policy", er.PolicyResponse.Policy.Name, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)
logger.V(4).Info("reporting fail results for policy")
for _, rule := range er.PolicyResponse.Rules {
for i, rule := range er.PolicyResponse.Rules {
if rule.Status == response.RuleStatusPass {
continue
}
// generate event on resource for each failed rule
logger.V(4).Info("generating event on resource")
e := event.Info{}
e.Kind = er.PolicyResponse.Resource.Kind
e.Namespace = er.PolicyResponse.Resource.Namespace
e.Name = er.PolicyResponse.Resource.Name
e.Reason = event.PolicyViolation.String()
e.Source = event.PolicyController
e.Message = fmt.Sprintf("policy '%s' (%s) rule '%s' failed. %v", er.PolicyResponse.Policy.Name, rule.Type, rule.Name, rule.Message)
eventInfos = append(eventInfos, e)
eventResource := event.NewResourceViolationEvent(event.PolicyController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i])
eventInfos = append(eventInfos, *eventResource)
eventPolicy := event.NewPolicyFailEvent(event.PolicyController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i], false)
eventInfos = append(eventInfos, *eventPolicy)
}
if !er.IsFailed() {
// generate event on policy for success rules
logger.V(4).Info("generating event on policy for success rules")
e := event.Info{}
kind := "ClusterPolicy"
if er.PolicyResponse.Policy.Namespace != "" {
kind = "Policy"
}
e.Kind = kind
e.Namespace = er.PolicyResponse.Policy.Namespace
e.Name = er.PolicyResponse.Policy.Name
e.Reason = event.PolicyApplied.String()
e.Source = event.PolicyController
e.Message = fmt.Sprintf("rules '%v' successfully applied on resource '%s/%s/%s'", er.GetSuccessRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
eventInfos = append(eventInfos, e)
if len(eventInfos) > 0 {
logger.V(4).Info("generating events for policy", "events", eventInfos)
}
if !er.IsSuccessful() {
// generate event on policy for failed rules
logger.V(4).Info("generating event on policy")
e := event.Info{}
kind := "ClusterPolicy"
if er.PolicyResponse.Policy.Namespace != "" {
kind = "Policy"
}
e.Kind = kind
e.Name = er.PolicyResponse.Policy.Name
e.Namespace = er.PolicyResponse.Policy.Namespace
e.Reason = event.PolicyViolation.String()
e.Source = event.PolicyController
e.Message = fmt.Sprintf("rules '%v' not satisfied on resource '%s/%s/%s'", er.GetFailedRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
eventInfos = append(eventInfos, e)
}
return eventInfos
}

View file

@ -78,8 +78,9 @@ func (ws *WebhookServer) handleGenerate(
if failedResponse := applyUpdateRequest(request, urkyverno.Generate, ws.urGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
// report failure event
for _, failedUR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create Update Request: %v", failedUR.err), failedUR.ur, policyContext.NewResource)
ws.eventGen.Add(events...)
err := fmt.Errorf("failed to create Update Request: %v", failedUR.err)
e := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &policyContext.NewResource)
ws.eventGen.Add(e...)
}
}
}
@ -435,15 +436,3 @@ type updateRequestResponse struct {
ur urkyverno.UpdateRequestSpec
err error
}
func failedEvents(err error, ur urkyverno.UpdateRequestSpec, resource unstructured.Unstructured) []event.Info {
re := event.Info{}
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Reason = event.PolicyFailed.String()
re.Source = event.GeneratePolicyController
re.Message = fmt.Sprintf("policy %s failed to apply: %v", ur.Policy, err)
return []event.Info{re}
}

View file

@ -1,10 +1,7 @@
package webhooks
import (
"strings"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/event"
)
@ -13,79 +10,30 @@ import (
func generateEvents(engineResponses []*response.EngineResponse, blocked bool, log logr.Logger) []event.Info {
var events []event.Info
// - Admission-Response is SUCCESS
// - Some/All policies failed (policy violations generated)
// - report failure event on policy
// - report failure event on resource
// - Some/All policies fail or error
// - report failure events on policy
// - report failure events on resource
// - Some/All policies succeeded
// - report success event on policy
// - report success event on resource
for _, er := range engineResponses {
pKind := "ClusterPolicy"
if er.Policy.IsNamespaced() {
pKind = "Policy"
}
if !er.IsSuccessful() {
for i, ruleResp := range er.PolicyResponse.Rules {
if ruleResp.Status == response.RuleStatusFail || ruleResp.Status == response.RuleStatusError {
e := event.NewPolicyFailEvent(event.AdmissionController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i], blocked)
events = append(events, *e)
}
// Rules that failed
failedRules := er.GetFailedRules()
failedRulesStr := strings.Join(failedRules, ";")
// Event on the policy
pe := event.NewEvent(
log,
pKind,
kyvernov1.SchemeGroupVersion.String(),
er.PolicyResponse.Policy.Namespace,
er.PolicyResponse.Policy.Name,
event.PolicyViolation.String(),
event.AdmissionController,
event.FPolicyApply,
failedRulesStr,
er.PolicyResponse.Resource.GetKey(),
)
events = append(events, pe)
if blocked {
continue
if !blocked {
e := event.NewResourceViolationEvent(event.AdmissionController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i])
events = append(events, *e)
}
}
// Event on the resource
re := event.NewEvent(
log,
er.PolicyResponse.Resource.Kind,
er.PolicyResponse.Resource.APIVersion,
er.PolicyResponse.Resource.Namespace,
er.PolicyResponse.Resource.Name,
event.PolicyViolation.String(),
event.AdmissionController,
event.FResourcePolicyApply,
failedRulesStr,
er.PolicyResponse.Policy.Name,
)
events = append(events, pe, re)
}
if !er.IsFailed() {
successRules := er.GetSuccessRules()
successRulesStr := strings.Join(successRules, ";")
// Event on the policy
e := event.NewEvent(
log,
pKind,
kyvernov1.SchemeGroupVersion.String(),
er.PolicyResponse.Policy.Namespace,
er.PolicyResponse.Policy.Name,
event.PolicyApplied.String(),
event.AdmissionController,
event.SPolicyApply,
successRulesStr,
er.PolicyResponse.Resource.GetKey(),
)
events = append(events, e)
} else {
e := event.NewPolicyAppliedEvent(event.AdmissionController, er)
events = append(events, *e)
}
}
return events
}

View file

@ -4,6 +4,8 @@ import (
"fmt"
"time"
"github.com/kyverno/kyverno/pkg/event"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
@ -60,7 +62,8 @@ func (ws *WebhookServer) handleMutateExisting(request *admissionv1.AdmissionRequ
if failedResponse := applyUpdateRequest(request, urkyverno.Mutate, ws.urGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
for _, failedUR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create update request: %v", failedUR.err), failedUR.ur, policyContext.NewResource)
err := fmt.Errorf("failed to create update request: %v", failedUR.err)
events := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &policyContext.NewResource)
ws.eventGen.Add(events...)
}
}