1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-10 09:56:55 +00:00
kyverno/cmd/cli/kubectl-kyverno/apply/report.go

155 lines
4.8 KiB
Go
Raw Normal View History

2020-10-15 17:29:07 -07:00
package apply
import (
"encoding/json"
"fmt"
"strings"
"time"
2020-10-15 17:29:07 -07:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2020-10-15 17:29:07 -07:00
corev1 "k8s.io/api/core/v1"
2020-10-16 16:27:04 -07:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-10-15 17:29:07 -07:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
2020-10-15 17:29:07 -07:00
)
const clusterpolicyreport = "clusterpolicyreport"
2020-10-27 00:41:16 +05:30
// resps is the engine responses generated for a single policy
func buildPolicyReports(auditWarn bool, engineResponses ...engineapi.EngineResponse) (res []*unstructured.Unstructured) {
2020-10-15 17:29:07 -07:00
var raw []byte
var err error
resultsMap := buildPolicyResults(auditWarn, engineResponses...)
2020-10-15 17:29:07 -07:00
for scope, result := range resultsMap {
if scope == clusterpolicyreport {
report := &policyreportv1alpha2.ClusterPolicyReport{
2020-10-16 16:27:04 -07:00
TypeMeta: metav1.TypeMeta{
APIVersion: policyreportv1alpha2.SchemeGroupVersion.String(),
2020-10-16 16:27:04 -07:00
Kind: "ClusterPolicyReport",
},
2020-10-15 17:29:07 -07:00
Results: result,
Summary: calculateSummary(result),
}
report.SetName(scope)
if raw, err = json.Marshal(report); err != nil {
log.Log.V(3).Info("failed to serialize policy report", "name", report.Name, "scope", scope, "error", err)
2020-10-15 17:29:07 -07:00
}
} else {
report := &policyreportv1alpha2.PolicyReport{
2020-10-16 16:27:04 -07:00
TypeMeta: metav1.TypeMeta{
APIVersion: policyreportv1alpha2.SchemeGroupVersion.String(),
2020-10-16 16:27:04 -07:00
Kind: "PolicyReport",
},
2020-10-15 17:29:07 -07:00
Results: result,
Summary: calculateSummary(result),
}
ns := strings.ReplaceAll(scope, "policyreport-ns-", "")
report.SetName(scope)
report.SetNamespace(ns)
2020-10-16 16:27:04 -07:00
if raw, err = json.Marshal(report); err != nil {
log.Log.V(3).Info("failed to serialize policy report", "name", report.Name, "scope", scope, "error", err)
2020-10-16 16:27:04 -07:00
}
2020-10-15 17:29:07 -07:00
}
reportUnstructured, err := kubeutils.BytesToUnstructured(raw)
2020-10-15 17:29:07 -07:00
if err != nil {
2020-11-19 15:56:14 +05:30
log.Log.V(3).Info("failed to convert policy report", "scope", scope, "error", err)
2020-10-15 17:29:07 -07:00
continue
}
2020-10-16 16:27:04 -07:00
2020-10-15 17:29:07 -07:00
res = append(res, reportUnstructured)
}
return
}
// buildPolicyResults returns a string-PolicyReportResult map
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>"
func buildPolicyResults(auditWarn bool, engineResponses ...engineapi.EngineResponse) map[string][]policyreportv1alpha2.PolicyReportResult {
results := make(map[string][]policyreportv1alpha2.PolicyReportResult)
now := metav1.Timestamp{Seconds: time.Now().Unix()}
2020-10-15 17:29:07 -07:00
for _, engineResponse := range engineResponses {
policy := engineResponse.Policy
2020-10-15 17:29:07 -07:00
var appname string
ns := policy.GetNamespace()
2020-10-15 17:29:07 -07:00
if ns != "" {
appname = fmt.Sprintf("policyreport-ns-%s", ns)
} else {
appname = clusterpolicyreport
2020-10-15 17:29:07 -07:00
}
for _, ruleResponse := range engineResponse.PolicyResponse.Rules {
if ruleResponse.RuleType() != engineapi.Validation {
continue
}
result := policyreportv1alpha2.PolicyReportResult{
Policy: policy.GetName(),
Resources: []corev1.ObjectReference{
{
Kind: engineResponse.Resource.GetKind(),
Namespace: engineResponse.Resource.GetNamespace(),
APIVersion: engineResponse.Resource.GetAPIVersion(),
Name: engineResponse.Resource.GetName(),
UID: engineResponse.Resource.GetUID(),
2020-10-16 16:27:04 -07:00
},
},
Scored: true,
}
2020-10-15 17:29:07 -07:00
ann := engineResponse.Policy.GetAnnotations()
if ruleResponse.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if ruleResponse.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else if ruleResponse.Status() == engineapi.RuleStatusPass {
result.Result = policyreportv1alpha2.StatusPass
} else if ruleResponse.Status() == engineapi.RuleStatusFail {
if scored, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
result.Result = policyreportv1alpha2.StatusWarn
} else if auditWarn && engineResponse.GetValidationFailureAction().Audit() {
result.Result = policyreportv1alpha2.StatusWarn
} else {
result.Result = policyreportv1alpha2.StatusFail
}
} else {
fmt.Println(ruleResponse)
}
result.Rule = ruleResponse.Name()
result.Message = ruleResponse.Message()
result.Source = kyvernov1.ValueKyvernoApp
result.Timestamp = now
results[appname] = append(results[appname], result)
2020-10-15 17:29:07 -07:00
}
}
2020-10-31 01:55:05 +05:30
return results
2020-10-15 17:29:07 -07:00
}
func calculateSummary(results []policyreportv1alpha2.PolicyReportResult) (summary policyreportv1alpha2.PolicyReportSummary) {
2020-10-15 17:29:07 -07:00
for _, res := range results {
switch string(res.Result) {
case policyreportv1alpha2.StatusPass:
2020-11-10 10:49:29 +05:30
summary.Pass++
case policyreportv1alpha2.StatusFail:
2020-10-15 17:29:07 -07:00
summary.Fail++
2020-10-16 16:27:04 -07:00
case "warn":
2020-10-15 17:29:07 -07:00
summary.Warn++
2020-10-16 16:27:04 -07:00
case "error":
2020-10-15 17:29:07 -07:00
summary.Error++
2020-10-16 16:27:04 -07:00
case "skip":
2020-10-15 17:29:07 -07:00
summary.Skip++
}
}
return
}