1
0
Fork 0
mirror of https://github.com/kyverno/policy-reporter.git synced 2024-12-14 11:57:32 +00:00

Update Event process logic (#162)

* Update Event process logic

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>
This commit is contained in:
Frank Jogeleit 2022-06-29 10:43:59 +02:00 committed by GitHub
parent b6150c30c4
commit 0509aeb75e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 859 additions and 843 deletions

View file

@ -3,6 +3,8 @@
# 2.9.4
* Policy Reporter
* Add [AWS Kinesis](https://aws.amazon.com/kinesis) compatible target
* Add new Helm value `profiling.enabled` to enable pprof profiling, disabled by default
* Improved Informer handling
# 2.9.3
* Policy Reporter

View file

@ -59,6 +59,7 @@ spec:
- --dbfile=/sqlite/database.db
- --metrics-enabled={{ or .Values.metrics.enabled .Values.monitoring.enabled }}
- --rest-enabled={{ or .Values.rest.enabled .Values.ui.enabled }}
- --profile={{ .Values.profiling.enabled }}
ports:
- name: {{ .Values.port.name }}
containerPort: {{ .Values.port.number }}

View file

@ -109,6 +109,9 @@ metrics:
# status:
# exclude: ["pass", "skip"]
profiling:
enabled: false
# Filter PolicyReport resources to process
reportFilter:
namespaces:

View file

@ -1,8 +1,6 @@
package cmd
import (
"context"
"errors"
"flag"
"log"
@ -34,8 +32,6 @@ func newRunCMD() *cobra.Command {
return err
}
ctx := context.Background()
resolver := config.NewResolver(c, k8sConfig)
client, err := resolver.PolicyReportClient()
@ -43,12 +39,12 @@ func newRunCMD() *cobra.Command {
return err
}
server := resolver.APIServer(client.HasSynced)
resolver.RegisterSendResultListener()
g := &errgroup.Group{}
server := resolver.APIServer(client.GetFoundResources())
if c.REST.Enabled {
db, err := resolver.Database()
if err != nil {
@ -79,13 +75,13 @@ func newRunCMD() *cobra.Command {
g.Go(server.Start)
g.Go(func() error {
eventChan := client.WatchPolicyReports(ctx)
stop := make(chan struct{})
defer close(stop)
resolver.EventPublisher().Publish(eventChan)
return errors.New("event publisher stoped")
})
err = client.Run(stop)
if err != nil {
return err
}
return g.Wait()
},

35
go.mod
View file

@ -3,19 +3,20 @@ module github.com/kyverno/policy-reporter
go 1.18
require (
github.com/aws/aws-sdk-go v1.44.27
github.com/aws/aws-sdk-go v1.44.39
github.com/go-redis/redis/v8 v8.11.5
github.com/kyverno/kyverno v1.7.0
github.com/kyverno/kyverno v1.7.1
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/minio/pkg v1.1.24
github.com/minio/pkg v1.1.26
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.12.2
github.com/prometheus/client_model v0.2.0
github.com/spf13/cobra v1.4.0
github.com/segmentio/fasthash v1.0.3
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.12.0
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
k8s.io/apimachinery v0.24.1
k8s.io/client-go v0.24.1
k8s.io/apimachinery v0.24.2
k8s.io/client-go v0.24.2
)
require (
@ -23,6 +24,7 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
@ -45,14 +47,14 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect
@ -60,28 +62,27 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/klog/v2 v2.70.0 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
require (
github.com/emicklei/go-restful v2.15.0+incompatible // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/common v0.35.0 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 // indirect
golang.org/x/net v0.0.0-20220621193019-9d032be2e588 // indirect
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
k8s.io/api v0.24.1
k8s.io/apiextensions-apiserver v0.24.1 // indirect
k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6 // indirect
k8s.io/api v0.24.2
k8s.io/apiextensions-apiserver v0.24.2 // indirect
k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8 // indirect
sigs.k8s.io/controller-runtime v0.12.1 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
)

79
go.sum
View file

@ -68,8 +68,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.44.27 h1:8CMspeZSrewnbvAwgl8qo5R7orDLwQnTGBf/OKPiHxI=
github.com/aws/aws-sdk-go v1.44.27/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.39 h1:pMxYLqnuDidT0ZTDAhYC66fb3W3Yc+oShmfzEL4fTDI=
github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -107,6 +107,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -121,8 +122,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.15.0+incompatible h1:8KpYO/Xl/ZudZs5RNOEhWMBY4hmzlZhhRd9cu+jrZP4=
github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -337,8 +338,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kyverno/go-wildcard v1.0.4 h1:uoIWLnywcLED/nXeNVDj4U7OvNW1O3N4+emC5gK90ug=
github.com/kyverno/go-wildcard v1.0.4/go.mod h1:sZkBvzy+au8C1uiqOH+SdN4psOL+0nhfWgsZzzJKwbs=
github.com/kyverno/kyverno v1.7.0 h1:gp+t1ThTAMmXF1jcEie+ZHvLnOuwwRS6Upq5KzS52z4=
github.com/kyverno/kyverno v1.7.0/go.mod h1:4twhW8CcubmLZ7lQF4+1pYXYTn0GJIiBUyHxsdl86mM=
github.com/kyverno/kyverno v1.7.1 h1:YykyefFmlET8uYrQvOw+/Ki//9RmERcz8BwNPhQabZ8=
github.com/kyverno/kyverno v1.7.1/go.mod h1:4twhW8CcubmLZ7lQF4+1pYXYTn0GJIiBUyHxsdl86mM=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@ -355,8 +356,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/pkg v1.1.24 h1:a2RCb6LgsCi9DvrripuvlFQRCNb5Hp1HIssnsUqLoZY=
github.com/minio/pkg v1.1.24/go.mod h1:z9PfmEI804KFkF6eY4LoGe8IDVvTCsYGVuaf58Dr0WI=
github.com/minio/pkg v1.1.26 h1:a8x4sHNBxCiHEkxZ/0EBTLqvV3nMtM2G/A6lXNfXN3U=
github.com/minio/pkg v1.1.26/go.mod h1:z9PfmEI804KFkF6eY4LoGe8IDVvTCsYGVuaf58Dr0WI=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -403,8 +404,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -435,8 +436,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE=
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khmFBE=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -453,6 +454,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -473,8 +476,9 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -493,8 +497,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
@ -649,8 +653,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220621193019-9d032be2e588 h1:9ubFuySsnAJYGyJrZ3koiEv8FyqofCBdz3G9Mbf2YFc=
golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -665,8 +669,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw=
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb h1:8tDJ3aechhddbdPAxpycgXHJRMLpk/Ab+aa4OgdN5/g=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -747,8 +751,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
@ -768,8 +772,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -992,26 +996,27 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.24.1 h1:BjCMRDcyEYz03joa3K1+rbshwh1Ay6oB53+iUx2H8UY=
k8s.io/api v0.24.1/go.mod h1:JhoOvNiLXKTPQ60zh2g0ewpA+bnEYf5q44Flhquh4vQ=
k8s.io/apiextensions-apiserver v0.24.1 h1:5yBh9+ueTq/kfnHQZa0MAo6uNcPrtxPMpNQgorBaKS0=
k8s.io/apiextensions-apiserver v0.24.1/go.mod h1:A6MHfaLDGfjOc/We2nM7uewD5Oa/FnEbZ6cD7g2ca4Q=
k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I=
k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apiserver v0.24.1/go.mod h1:dQWNMx15S8NqJMp0gpYfssyvhYnkilc1LpExd/dkLh0=
k8s.io/client-go v0.24.1 h1:w1hNdI9PFrzu3OlovVeTnf4oHDt+FJLd9Ndluvnb42E=
k8s.io/client-go v0.24.1/go.mod h1:f1kIDqcEYmwXS/vTbbhopMUbhKp2JhOeVTfxgaCIlF8=
k8s.io/code-generator v0.24.1/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w=
k8s.io/component-base v0.24.1/go.mod h1:DW5vQGYVCog8WYpNob3PMmmsY8A3L9QZNg4j/dV3s38=
k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI=
k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg=
k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k=
k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ=
k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM=
k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI=
k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA=
k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30=
k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w=
k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc=
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.70.0 h1:GMmmjoFOrNepPN0ZeGCzvD2Gh5IKRwdFx8W5PBxVTQU=
k8s.io/klog/v2 v2.70.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6 h1:nBQrWPlrNIiw0BsX6a6MKr1itkm0ZS0Nl97kNLitFfI=
k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M=
k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8 h1:30P0UV8MQgg4f1khIUT09xHmpI5B5Wg0Vg6JNkUqsQ0=
k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8/go.mod h1:PNbiP2hKArDh8cgJZTDL6Ss/z3wsbga8yjj/7VMB+I4=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=

View file

@ -147,7 +147,7 @@ spec:
fsGroup: 1234
containers:
- name: policy-reporter
image: "ghcr.io/kyverno/policy-reporter:2.6.1"
image: "ghcr.io/kyverno/policy-reporter:2.6.2"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -259,7 +259,7 @@ spec:
fsGroup: 1234
containers:
- name: policy-reporter
image: "ghcr.io/kyverno/policy-reporter:2.6.1"
image: "ghcr.io/kyverno/policy-reporter:2.6.2"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -85,7 +85,7 @@ spec:
automountServiceAccountToken: true
containers:
- name: policy-reporter
image: "ghcr.io/kyverno/policy-reporter:2.6.1"
image: "ghcr.io/kyverno/policy-reporter:2.6.2"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -2,20 +2,17 @@ package api
import (
"fmt"
"log"
"net/http"
)
// HealthzHandler for the Halthz REST API
func HealthzHandler(found map[string]string) http.HandlerFunc {
func HealthzHandler(synced func() bool) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if len(found) == 0 {
if !synced() {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusServiceUnavailable)
log.Println("[WARNING] - Healthz Check: No policyreport.wgpolicyk8s.io and clusterpolicyreport.wgpolicyk8s.io crds are found")
fmt.Fprint(w, `{ "error": "No PolicyReport CRDs found" }`)
fmt.Fprint(w, `{ "error": "Informers not in sync" }`)
return
}
@ -28,8 +25,17 @@ func HealthzHandler(found map[string]string) http.HandlerFunc {
}
// ReadyHandler for the Halthz REST API
func ReadyHandler() http.HandlerFunc {
func ReadyHandler(synced func() bool) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if !synced() {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{ "error": "Informers not in sync" }`)
return
}
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")

View file

@ -16,7 +16,7 @@ func Test_HealthzAPI(t *testing.T) {
}
rr := httptest.NewRecorder()
handler := api.HealthzHandler(map[string]string{"wgpolicyk8s.io/v1alpha2": "wgpolicyk8s.io/v1alpha2"})
handler := api.HealthzHandler(func() bool { return true })
handler.ServeHTTP(rr, req)
@ -24,15 +24,14 @@ func Test_HealthzAPI(t *testing.T) {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}
})
t.Run("Unavailable Respose", func(t *testing.T) {
t.Run("Unavailable Response", func(t *testing.T) {
req, err := http.NewRequest("GET", "/healthz", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := api.HealthzHandler(map[string]string{})
handler := api.HealthzHandler(func() bool { return false })
handler.ServeHTTP(rr, req)
@ -43,14 +42,14 @@ func Test_HealthzAPI(t *testing.T) {
}
func Test_ReadyAPI(t *testing.T) {
t.Run("Success Respose", func(t *testing.T) {
t.Run("Success Response", func(t *testing.T) {
req, err := http.NewRequest("GET", "/ready", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := api.ReadyHandler()
handler := api.ReadyHandler(func() bool { return true })
handler.ServeHTTP(rr, req)
@ -58,4 +57,19 @@ func Test_ReadyAPI(t *testing.T) {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}
})
t.Run("Unavailable Response", func(t *testing.T) {
req, err := http.NewRequest("GET", "/ready", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := api.ReadyHandler(func() bool { return false })
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusServiceUnavailable {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusServiceUnavailable)
}
})
}

View file

@ -29,15 +29,15 @@ type Server interface {
}
type httpServer struct {
http http.Server
mux *http.ServeMux
targets []target.Client
foundResources map[string]string
http http.Server
mux *http.ServeMux
targets []target.Client
synced func() bool
}
func (s *httpServer) RegisterLifecycleHandler() {
s.mux.HandleFunc("/healthz", HealthzHandler(s.foundResources))
s.mux.HandleFunc("/ready", ReadyHandler())
s.mux.HandleFunc("/healthz", HealthzHandler(s.synced))
s.mux.HandleFunc("/ready", ReadyHandler(s.synced))
}
func (s *httpServer) RegisterV1Handler(finder v1.PolicyReportFinder) {
@ -84,13 +84,13 @@ func (s *httpServer) Shutdown(ctx context.Context) error {
}
// NewServer constructor for a new API Server
func NewServer(targets []target.Client, port int, foundResources map[string]string) Server {
func NewServer(targets []target.Client, port int, synced func() bool) Server {
mux := http.NewServeMux()
s := &httpServer{
targets: targets,
mux: mux,
foundResources: foundResources,
targets: targets,
synced: synced,
mux: mux,
http: http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,

View file

@ -20,7 +20,7 @@ func Test_NewServer(t *testing.T) {
port := int(rnd * 10000)
server := api.NewServer(make([]target.Client, 0), port, make(map[string]string))
server := api.NewServer(make([]target.Client, 0), port, func() bool { return true })
server.RegisterMetricsHandler()
server.RegisterV1Handler(nil)

View file

@ -14,7 +14,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/loki"
)
var result1 = &report.Result{
var result1 = report.Result{
ID: "123",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -25,7 +25,7 @@ var result1 = &report.Result{
Severity: report.High,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -34,7 +34,7 @@ var result1 = &report.Result{
},
}
var result2 = &report.Result{
var result2 = report.Result{
ID: "124",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -44,7 +44,7 @@ var result2 = &report.Result{
Category: "Best Practices",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Pod",
Name: "nginx",
@ -53,7 +53,7 @@ var result2 = &report.Result{
},
}
var cresult1 = &report.Result{
var cresult1 = report.Result{
ID: "125",
Message: "validation error: The label `test` is required. Rule check-for-labels-on-namespace",
Policy: "require-ns-labels",
@ -64,7 +64,7 @@ var cresult1 = &report.Result{
Severity: report.Medium,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Namespace",
Name: "test",
@ -72,7 +72,7 @@ var cresult1 = &report.Result{
},
}
var cresult2 = &report.Result{
var cresult2 = report.Result{
ID: "126",
Message: "validation error: The label `test` is required. Rule check-for-labels-on-namespace",
Policy: "require-ns-labels",
@ -83,7 +83,7 @@ var cresult2 = &report.Result{
Severity: report.High,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Namespace",
Name: "dev",
@ -91,26 +91,20 @@ var cresult2 = &report.Result{
},
}
var preport = &report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result2.GetIdentifier(): result2,
},
Summary: &report.Summary{Fail: 1},
var preport = report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: []report.Result{result1, result2},
Summary: report.Summary{Fail: 1},
CreationTimestamp: time.Now(),
}
var creport = &report.PolicyReport{
ID: report.GeneratePolicyReportID("cpolr", ""),
Name: "cpolr",
Results: map[string]*report.Result{
cresult1.GetIdentifier(): cresult1,
cresult2.GetIdentifier(): cresult2,
},
Summary: &report.Summary{},
var creport = report.PolicyReport{
ID: report.GeneratePolicyReportID("cpolr", ""),
Name: "cpolr",
Results: []report.Result{cresult1, cresult2},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}

View file

@ -46,11 +46,11 @@ type Resolver struct {
}
// APIServer resolver method
func (r *Resolver) APIServer(foundResources map[string]string) api.Server {
func (r *Resolver) APIServer(synced func() bool) api.Server {
return api.NewServer(
r.TargetClients(),
r.config.API.Port,
foundResources,
synced,
)
}
@ -386,7 +386,7 @@ func (r *Resolver) PolicyReportClient() (report.PolicyReportClient, error) {
return nil, err
}
r.policyReportClient = kubernetes.NewPolicyReportClient(client, r.Mapper(), 5*time.Second, r.ReportFilter())
r.policyReportClient = kubernetes.NewPolicyReportClient(client, r.Mapper(), r.ReportFilter(), r.EventPublisher())
return r.policyReportClient, nil
}

View file

@ -84,6 +84,16 @@ var testConfig = &config.Config{
Prefix: "prefix",
Channels: []config.S3{{}},
},
Kinesis: config.Kinesis{
AccessKeyID: "AccessKey",
SecretAccessKey: "SecretAccessKey",
StreamName: "policy-reporter",
SkipExisting: true,
MinimumPriority: "debug",
Endpoint: "https://yds.serverless.yandexcloud.net",
Region: "ru-central1",
Channels: []config.Kinesis{{}},
},
}
func Test_ResolveTarget(t *testing.T) {
@ -132,13 +142,19 @@ func Test_ResolveTarget(t *testing.T) {
t.Errorf("Expected 2 Client, got %d clients", len(clients))
}
})
t.Run("Kinesis", func(t *testing.T) {
clients := resolver.KinesisClients()
if len(clients) != 2 {
t.Errorf("Expected 2 Client, got %d clients", len(clients))
}
})
}
func Test_ResolveTargets(t *testing.T) {
resolver := config.NewResolver(testConfig, nil)
clients := resolver.TargetClients()
if count := len(clients); count != 15 {
if count := len(clients); count != 17 {
t.Errorf("Expected 15 Clients, got %d", count)
}
}
@ -221,6 +237,15 @@ func Test_ResolveTargetWithoutHost(t *testing.T) {
SkipExisting: true,
MinimumPriority: "debug",
},
Kinesis: config.Kinesis{
Endpoint: "",
Region: "",
AccessKeyID: "",
SecretAccessKey: "",
StreamName: "",
SkipExisting: true,
MinimumPriority: "debug",
},
}
t.Run("Loki", func(t *testing.T) {
@ -281,15 +306,6 @@ func Test_ResolveTargetWithoutHost(t *testing.T) {
t.Error("Expected Client to be nil if no accessKey is configured")
}
})
t.Run("S3.AccessKey", func(t *testing.T) {
config2.S3.Endpoint = "https://storage.yandexcloud.net"
resolver := config.NewResolver(config2, nil)
if len(resolver.S3Clients()) != 0 {
t.Error("Expected Client to be nil if no accessKey is configured")
}
})
t.Run("S3.SecretAccessKey", func(t *testing.T) {
config2.S3.AccessKeyID = "access"
@ -317,6 +333,49 @@ func Test_ResolveTargetWithoutHost(t *testing.T) {
t.Error("Expected Client to be nil if no bucket is configured")
}
})
t.Run("Kinesis.Endoint", func(t *testing.T) {
resolver := config.NewResolver(config2, nil)
if len(resolver.KinesisClients()) != 0 {
t.Error("Expected Client to be nil if no endpoint is configured")
}
})
t.Run("Kinesis.AccessKey", func(t *testing.T) {
config2.Kinesis.Endpoint = "https://yds.serverless.yandexcloud.net"
resolver := config.NewResolver(config2, nil)
if len(resolver.KinesisClients()) != 0 {
t.Error("Expected Client to be nil if no accessKey is configured")
}
})
t.Run("Kinesis.SecretAccessKey", func(t *testing.T) {
config2.Kinesis.AccessKeyID = "access"
resolver := config.NewResolver(config2, nil)
if len(resolver.KinesisClients()) != 0 {
t.Error("Expected Client to be nil if no secretAccessKey is configured")
}
})
t.Run("Kinesis.Region", func(t *testing.T) {
config2.Kinesis.SecretAccessKey = "secret"
resolver := config.NewResolver(config2, nil)
if len(resolver.KinesisClients()) != 0 {
t.Error("Expected Client to be nil if no region is configured")
}
})
t.Run("Kinesis.StreamName", func(t *testing.T) {
config2.Kinesis.Region = "ru-central1"
resolver := config.NewResolver(config2, nil)
if len(resolver.KinesisClients()) != 0 {
t.Error("Expected Client to be nil if no bucket is configured")
}
})
}
func Test_ResolvePolicyClient(t *testing.T) {
@ -352,7 +411,7 @@ func Test_ResolvePolicyStore(t *testing.T) {
func Test_ResolveAPIServer(t *testing.T) {
resolver := config.NewResolver(&config.Config{}, &rest.Config{})
server := resolver.APIServer(make(map[string]string))
server := resolver.APIServer(func() bool { return true })
if server == nil {
t.Error("Error: Should return API Server")
}

View file

@ -9,13 +9,12 @@ import (
type Debouncer interface {
Add(e report.LifecycleEvent)
ReportGroups() *report.Group
}
type debouncer struct {
waitDuration time.Duration
events map[string]report.LifecycleEvent
channel *report.Group
publisher report.EventPublisher
mutx *sync.Mutex
}
@ -27,14 +26,8 @@ func (d *debouncer) Add(event report.LifecycleEvent) {
d.mutx.Unlock()
}
if event.Type == report.Added {
d.channel.Register(event.NewPolicyReport.ID)
d.channel.AddEvent(event)
return
}
if event.Type == report.Deleted {
d.channel.AddEvent(event)
if event.Type == report.Added || event.Type == report.Deleted {
d.publisher.Publish(event)
return
}
@ -48,7 +41,7 @@ func (d *debouncer) Add(event report.LifecycleEvent) {
d.mutx.Lock()
if event, ok := d.events[event.NewPolicyReport.GetIdentifier()]; ok {
d.channel.AddEvent(event)
d.publisher.Publish(event)
delete(d.events, event.NewPolicyReport.GetIdentifier())
}
d.mutx.Unlock()
@ -66,18 +59,14 @@ func (d *debouncer) Add(event report.LifecycleEvent) {
return
}
d.channel.AddEvent(event)
d.publisher.Publish(event)
}
func (d *debouncer) ReportGroups() *report.Group {
return d.channel
}
func NewDebouncer(waitDuration time.Duration) Debouncer {
func NewDebouncer(waitDuration time.Duration, publisher report.EventPublisher) Debouncer {
return &debouncer{
waitDuration: waitDuration,
events: make(map[string]report.LifecycleEvent),
mutx: new(sync.Mutex),
channel: report.NewGroup(),
publisher: publisher,
}
}

View file

@ -11,23 +11,17 @@ import (
func Test_Debouncer(t *testing.T) {
t.Run("Skip Empty Update", func(t *testing.T) {
debouncer := kubernetes.NewDebouncer(200 * time.Millisecond)
counter := 0
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
group := debouncer.ReportGroups()
reportID := <-group.ChannelAdded()
eventChan, _ := group.Listen(reportID)
publisher := report.NewEventPublisher()
publisher.RegisterListener(func(event report.LifecycleEvent) {
counter++
wg.Done()
})
for event := range eventChan {
wg.Done()
if len(event.NewPolicyReport.Results) == 0 {
t.Error("Expected to skip the empty modify event")
}
}
}()
debouncer := kubernetes.NewDebouncer(200*time.Millisecond, publisher)
debouncer.Add(report.LifecycleEvent{
Type: report.Added,
@ -48,6 +42,8 @@ func Test_Debouncer(t *testing.T) {
wg.Wait()
debouncer.ReportGroups().CloseAll()
if counter != 2 {
t.Error("Expected to skip the empty modify event")
}
})
}

View file

@ -118,6 +118,50 @@ var policyReportCRD = &v1alpha2.PolicyReport{
},
}
var multiResourcePolicyReportCRD = &v1alpha2.PolicyReport{
ObjectMeta: v1.ObjectMeta{
Name: "policy-report",
Namespace: "test",
},
Summary: v1alpha2.PolicyReportSummary{
Pass: 1,
Skip: 2,
Warn: 3,
Fail: 4,
Error: 5,
},
Results: []v1alpha2.PolicyReportResult{
{
Message: "message",
Result: v1alpha2.StatusFail,
Scored: true,
Policy: "required-label",
Rule: "app-label-required",
Timestamp: v1.Timestamp{Seconds: 1614093000},
Source: "test",
Category: "test",
Severity: v1alpha2.SeverityHigh,
Resources: []corev1.ObjectReference{
{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
Namespace: "test",
UID: "dfd57c50-f30c-4729-b63f-b1954d8988d1",
},
{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx2",
Namespace: "test",
UID: "dfd57c50-f30c-4729-b63f-b1954d8988d2",
},
},
Properties: map[string]string{"version": "1.2.0"},
},
},
}
var minPolicyReportCRD = &v1alpha2.PolicyReport{
ObjectMeta: v1.ObjectMeta{
Name: "policy-report",
@ -212,6 +256,67 @@ var clusterPolicyReportCRD = &v1alpha2.ClusterPolicyReport{
},
}
var minClusterPolicyReportCRD = &v1alpha2.ClusterPolicyReport{
ObjectMeta: v1.ObjectMeta{
Name: "cluster-policy-report",
},
Summary: v1alpha2.PolicyReportSummary{
Fail: 4,
},
Results: []v1alpha2.PolicyReportResult{
{
Message: "message",
Result: v1alpha2.StatusFail,
Scored: true,
Policy: "cluster-policy",
Rule: "cluster-role",
Timestamp: v1.Timestamp{Seconds: 1614093000},
Source: "test",
Category: "test",
Severity: v1alpha2.SeverityHigh,
},
},
}
var multiResourceClusterPolicyReportCRD = &v1alpha2.ClusterPolicyReport{
ObjectMeta: v1.ObjectMeta{
Name: "cluster-policy-report",
},
Summary: v1alpha2.PolicyReportSummary{
Fail: 4,
},
Results: []v1alpha2.PolicyReportResult{
{
Message: "message",
Result: v1alpha2.StatusFail,
Scored: true,
Policy: "cluster-required-label",
Rule: "ns-label-required",
Timestamp: v1.Timestamp{Seconds: 1614093000},
Source: "test",
Category: "test",
Severity: v1alpha2.SeverityHigh,
Resources: []corev1.ObjectReference{
{
APIVersion: "v1",
Kind: "Namespace",
Name: "policy-reporter",
Namespace: "test",
UID: "dfd57c50-f30c-4729-b63f-b1954d8988d1",
},
{
APIVersion: "v1",
Kind: "Namespace",
Name: "policy-reporter-check",
Namespace: "test",
UID: "dfd57c50-f30c-4729-b63f-b1954d8988d1",
},
},
Properties: map[string]string{"version": "1.2.0"},
},
},
}
var result1ID string = report.GeneratePolicyReportResultID(
string(policyReportCRD.Results[0].Resources[0].UID),
policyReportCRD.Results[0].Resources[0].Name,

View file

@ -6,6 +6,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/report"
"github.com/kyverno/kyverno/api/policyreport/v1alpha2"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -14,28 +15,32 @@ const ResultIDKey = "resultID"
// Mapper converts maps into report structs
type Mapper interface {
// MapPolicyReport maps a v1alpha2.PolicyReport into a PolicyReport
MapPolicyReport(*v1alpha2.PolicyReport) *report.PolicyReport
MapPolicyReport(*v1alpha2.PolicyReport) report.PolicyReport
// MapClusterPolicyReport maps a v1alpha2.ClusterPolicyReport into a PolicyReport
MapClusterPolicyReport(*v1alpha2.ClusterPolicyReport) *report.PolicyReport
MapClusterPolicyReport(*v1alpha2.ClusterPolicyReport) report.PolicyReport
}
type mapper struct {
priorityMap map[string]string
}
func (m *mapper) MapPolicyReport(preport *v1alpha2.PolicyReport) *report.PolicyReport {
r := &report.PolicyReport{
func (m *mapper) MapPolicyReport(preport *v1alpha2.PolicyReport) report.PolicyReport {
r := report.PolicyReport{
Name: preport.Name,
Namespace: preport.Namespace,
Summary: m.mapSummary(preport.Summary),
Results: make(map[string]*report.Result),
Results: make([]report.Result, 0),
CreationTimestamp: preport.CreationTimestamp.Time,
}
for _, resultItem := range preport.Results {
results := m.mapResult(resultItem.DeepCopy())
for _, result := range results {
r.Results[result.GetIdentifier()] = result
for _, result := range preport.Results {
if len(result.Resources) == 0 {
r.Results = append(r.Results, m.mapResult(result, report.Resource{}))
continue
}
for _, res := range result.Resources {
r.Results = append(r.Results, m.mapResult(result, mapResource(res)))
}
}
@ -44,18 +49,22 @@ func (m *mapper) MapPolicyReport(preport *v1alpha2.PolicyReport) *report.PolicyR
return r
}
func (m *mapper) MapClusterPolicyReport(creport *v1alpha2.ClusterPolicyReport) *report.PolicyReport {
r := &report.PolicyReport{
func (m *mapper) MapClusterPolicyReport(creport *v1alpha2.ClusterPolicyReport) report.PolicyReport {
r := report.PolicyReport{
Name: creport.Name,
Summary: m.mapSummary(creport.Summary),
Results: make(map[string]*report.Result),
Results: make([]report.Result, 0),
CreationTimestamp: creport.CreationTimestamp.Time,
}
for _, resultItem := range creport.Results {
results := m.mapResult(resultItem.DeepCopy())
for _, result := range results {
r.Results[result.GetIdentifier()] = result
for _, result := range creport.Results {
if len(result.Resources) == 0 {
r.Results = append(r.Results, m.mapResult(result, report.Resource{}))
continue
}
for _, res := range result.Resources {
r.Results = append(r.Results, m.mapResult(result, mapResource(res)))
}
}
@ -68,8 +77,8 @@ func (m *mapper) SetPriorityMap(priorityMap map[string]string) {
m.priorityMap = priorityMap
}
func (m *mapper) mapSummary(sum v1alpha2.PolicyReportSummary) *report.Summary {
summary := &report.Summary{}
func (m *mapper) mapSummary(sum v1alpha2.PolicyReportSummary) report.Summary {
summary := report.Summary{}
summary.Pass = sum.Pass
summary.Skip = sum.Skip
summary.Warn = sum.Warn
@ -79,72 +88,14 @@ func (m *mapper) mapSummary(sum v1alpha2.PolicyReportSummary) *report.Summary {
return summary
}
func (m *mapper) mapResult(result *v1alpha2.PolicyReportResult) []*report.Result {
var resources []*report.Resource
for _, res := range result.Resources {
r := &report.Resource{
Namespace: res.Namespace,
APIVersion: res.APIVersion,
Kind: res.Kind,
Name: res.Name,
UID: string(res.UID),
}
resources = append(resources, r)
func mapResource(res corev1.ObjectReference) report.Resource {
return report.Resource{
Namespace: res.Namespace,
APIVersion: res.APIVersion,
Kind: res.Kind,
Name: res.Name,
UID: string(res.UID),
}
var results []*report.Result
factory := func(res *report.Resource) *report.Result {
status := string(result.Result)
r := &report.Result{
Policy: result.Policy,
Status: string(result.Result),
Priority: report.PriorityFromStatus(status),
Resource: res,
Properties: make(map[string]string),
Scored: result.Scored,
Severity: string(result.Severity),
Message: result.Message,
Rule: result.Rule,
Category: result.Category,
Source: result.Source,
Timestamp: convertTimestamp(result.Timestamp),
}
if r.Status == report.Fail {
r.Priority = m.resolvePriority(r.Policy, r.Severity)
}
if id, ok := result.Properties[ResultIDKey]; ok {
r.ID = id
delete(result.Properties, ResultIDKey)
}
for property, value := range result.Properties {
if len(value) > 0 {
r.Properties[property] = value
}
}
if r.ID == "" {
r.ID = report.GeneratePolicyReportResultID(r.Resource.UID, r.Resource.Name, r.Policy, r.Rule, r.Status, r.Message)
}
return r
}
for _, resource := range resources {
results = append(results, factory(resource))
}
if len(results) == 0 {
results = append(results, factory(&report.Resource{}))
}
return results
}
func convertTimestamp(timestamp v1.Timestamp) time.Time {
@ -171,6 +122,48 @@ func (m *mapper) resolvePriority(policy string, severity report.Severity) report
return report.Priority(report.WarningPriority)
}
func (m *mapper) mapResult(result v1alpha2.PolicyReportResult, res report.Resource) report.Result {
status := string(result.Result)
r := report.Result{
Policy: result.Policy,
Status: string(result.Result),
Priority: report.PriorityFromStatus(status),
Resource: res,
Properties: make(map[string]string),
Scored: result.Scored,
Severity: string(result.Severity),
Message: result.Message,
Rule: result.Rule,
Category: result.Category,
Source: result.Source,
Timestamp: convertTimestamp(result.Timestamp),
}
if r.Status == report.Fail {
r.Priority = m.resolvePriority(r.Policy, r.Severity)
}
if id, ok := result.Properties[ResultIDKey]; ok {
r.ID = id
}
for property, value := range result.Properties {
if property == ResultIDKey {
continue
}
if value != "" {
r.Properties[property] = value
}
}
if r.ID == "" {
r.ID = report.GeneratePolicyReportResultID(r.Resource.UID, r.Resource.Name, r.Policy, r.Rule, r.Status, r.Message)
}
return r
}
// NewMapper creates an new Mapper instance
func NewMapper(priorities map[string]string) Mapper {
m := &mapper{}

View file

@ -34,8 +34,8 @@ func Test_MapPolicyReport(t *testing.T) {
t.Errorf("Unexpected Summary.Error value %d (expected 5)", preport.Summary.Error)
}
result1, ok := preport.Results[result1ID]
if !ok {
result1 := preport.GetResult(result1ID)
if result1.ID == "" {
t.Error("Expected result not found")
}
@ -90,8 +90,8 @@ func Test_MapPolicyReport(t *testing.T) {
t.Errorf("Expected Resource.Namespace 'dfd57c50-f30c-4729-b63f-b1954d8988d1' (acutal %s)", resource.UID)
}
result2, ok := preport.Results[result2ID]
if !ok {
result2 := preport.GetResult(result2ID)
if result1.ID == "" {
t.Error("Expected result not found")
}
@ -140,8 +140,8 @@ func Test_MapClusterPolicyReport(t *testing.T) {
t.Errorf("Unexpected Summary.Error value %d (expected 5)", preport.Summary.Error)
}
result1, ok := preport.Results[cresult1ID]
if !ok {
result1 := preport.GetResult(cresult1ID)
if result1.ID == "" {
t.Error("Expected result not found")
}
@ -189,6 +189,11 @@ func Test_MapClusterPolicyReport(t *testing.T) {
if resource.UID != "dfd57c50-f30c-4729-b63f-b1954d8988d1" {
t.Errorf("Expected Resource.Namespace 'dfd57c50-f30c-4729-b63f-b1954d8988d1' (acutal %s)", resource.UID)
}
report2 := mapper.MapClusterPolicyReport(minClusterPolicyReportCRD)
if len(report2.Results) != 1 || report2.Results[0].HasResource() {
t.Error("Expected one result withour resource")
}
}
func Test_ResultIDPropertyMapping(t *testing.T) {
@ -196,9 +201,9 @@ func Test_ResultIDPropertyMapping(t *testing.T) {
preport := mapper.MapPolicyReport(enforceReportCRD)
result := preport.Results[result3ID]
result := preport.GetResult(result3ID)
if result == nil {
if result.ID == "" {
t.Errorf("Expected ResultID was mapped from property Key %s", kubernetes.ResultIDKey)
}
}
@ -209,7 +214,7 @@ func Test_PriorityMap(t *testing.T) {
preport := mapper.MapPolicyReport(policyReportCRD)
result := preport.Results[result1ID]
result := preport.GetResult(result1ID)
if result.Priority != report.DebugPriority {
t.Errorf("Expected Policy '%d' (acutal %d)", report.DebugPriority, result.Priority)
@ -221,8 +226,7 @@ func Test_PriorityMap(t *testing.T) {
preport := mapper.MapPolicyReport(policyReportCRD)
result := preport.Results[result1ID]
result := preport.GetResult(result1ID)
if result.Priority != report.DebugPriority {
t.Errorf("Expected Priority '%d' (acutal %d)", report.DebugPriority, result.Priority)
}
@ -233,7 +237,7 @@ func Test_PriorityMap(t *testing.T) {
preport := mapper.MapPolicyReport(policyReportCRD)
result := preport.Results[result2ID]
result := preport.GetResult(result2ID)
if result.Priority != report.WarningPriority {
t.Errorf("Expected Policy '%d' (acutal %d)", report.WarningPriority, result.Priority)
@ -246,7 +250,30 @@ func Test_MapCustomResultID(t *testing.T) {
r := mapper.MapPolicyReport(enforceReportCRD)
if _, ok := r.Results["123456"]; !ok {
result := r.GetResult("123456")
if result.ID == "" {
t.Errorf("Expected resultID used as result.ID")
}
}
func Test_MapMultipleResourcesPolicyReport(t *testing.T) {
mapper := kubernetes.NewMapper(make(map[string]string))
r := mapper.MapPolicyReport(multiResourcePolicyReportCRD)
results := r.ResultList()
if len(results) != 2 {
t.Errorf("Expected one result per resource")
}
}
func Test_MapMultipleResourcesClusterPolicyReport(t *testing.T) {
mapper := kubernetes.NewMapper(make(map[string]string))
r := mapper.MapClusterPolicyReport(multiResourceClusterPolicyReportCRD)
results := r.ResultList()
if len(results) != 2 {
t.Errorf("Expected one result per resource")
}
}

View file

@ -1,8 +1,7 @@
package kubernetes
import (
"context"
"log"
"fmt"
"sync"
"time"
@ -16,64 +15,51 @@ import (
)
type k8sPolicyReportClient struct {
debouncer Debouncer
client versioned.Interface
found map[string]string
mapper Mapper
mx *sync.Mutex
restartWatchOnFailure time.Duration
reportFilter report.Filter
debouncer Debouncer
fatcory externalversions.SharedInformerFactory
v1alpha2 v1alpha2.Interface
synced bool
mapper Mapper
mx *sync.Mutex
reportFilter report.Filter
}
func (k *k8sPolicyReportClient) GetFoundResources() map[string]string {
return k.found
func (k *k8sPolicyReportClient) HasSynced() bool {
return k.synced
}
func (k *k8sPolicyReportClient) WatchPolicyReports(ctx context.Context) *report.Group {
factory := externalversions.NewSharedInformerFactory(k.client, 0).Wgpolicyk8s().V1alpha2()
func (k *k8sPolicyReportClient) Run(stopper chan struct{}) error {
var cpolrInformer cache.SharedIndexInformer
go func(f v1alpha2.Interface) {
informer := factory.PolicyReports().Informer()
for {
k.watchPolicyReport(ctx, informer, "policyreport.wgpolicyk8s.io")
time.Sleep(k.restartWatchOnFailure)
}
}(factory)
polrInformer := k.configurePolicyReport()
if !k.reportFilter.DisableClusterReports() {
informer := factory.ClusterPolicyReports().Informer()
go func(f v1alpha2.Interface) {
for {
k.watchClusterPolicyReport(ctx, informer, "clusterpolicyreport.wgpolicyk8s.io")
time.Sleep(k.restartWatchOnFailure)
}
}(factory)
cpolrInformer = k.configureClusterPolicyReport()
}
for {
if !k.reportFilter.DisableClusterReports() && len(k.found) == 2 {
break
} else if k.reportFilter.DisableClusterReports() && len(k.found) == 1 {
break
}
k.fatcory.Start(stopper)
if !cache.WaitForCacheSync(stopper, polrInformer.HasSynced) {
return fmt.Errorf("failed to sync policy reports")
}
return k.debouncer.ReportGroups()
if cpolrInformer != nil && !cache.WaitForCacheSync(stopper, cpolrInformer.HasSynced) {
return fmt.Errorf("failed to sync cluster policy reports")
}
k.synced = true
return nil
}
func (k *k8sPolicyReportClient) watchPolicyReport(ctx context.Context, informer cache.SharedIndexInformer, crd string) {
ctx = k.addErrorWatchHandler(ctx, informer, crd)
go k.handleCRDRegistration(ctx, informer, crd)
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
func (k *k8sPolicyReportClient) configurePolicyReport() cache.SharedIndexInformer {
polrInformer := k.v1alpha2.PolicyReports().Informer()
polrInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
if item, ok := obj.(*pr.PolicyReport); ok {
preport := k.mapper.MapPolicyReport(item)
if k.reportFilter.AllowReport(preport) {
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: &report.PolicyReport{}, Type: report.Added})
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: report.PolicyReport{}, Type: report.Added})
}
}
},
@ -81,7 +67,7 @@ func (k *k8sPolicyReportClient) watchPolicyReport(ctx context.Context, informer
if item, ok := obj.(*pr.PolicyReport); ok {
preport := k.mapper.MapPolicyReport(item)
if k.reportFilter.AllowReport(preport) {
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: &report.PolicyReport{}, Type: report.Deleted})
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: report.PolicyReport{}, Type: report.Deleted})
}
}
},
@ -89,7 +75,7 @@ func (k *k8sPolicyReportClient) watchPolicyReport(ctx context.Context, informer
if item, ok := newObj.(*pr.PolicyReport); ok {
preport := k.mapper.MapPolicyReport(item)
var oreport *report.PolicyReport
var oreport report.PolicyReport
if oldItem, ok := oldObj.(*pr.PolicyReport); ok {
oreport = k.mapper.MapPolicyReport(oldItem)
}
@ -101,20 +87,21 @@ func (k *k8sPolicyReportClient) watchPolicyReport(ctx context.Context, informer
},
})
informer.Run(ctx.Done())
polrInformer.SetWatchErrorHandler(func(_ *cache.Reflector, _ error) {
k.synced = false
})
return polrInformer
}
func (k *k8sPolicyReportClient) watchClusterPolicyReport(ctx context.Context, informer cache.SharedIndexInformer, crd string) {
ctx = k.addErrorWatchHandler(ctx, informer, crd)
go k.handleCRDRegistration(ctx, informer, crd)
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
func (k *k8sPolicyReportClient) configureClusterPolicyReport() cache.SharedIndexInformer {
cpolrInformer := k.v1alpha2.ClusterPolicyReports().Informer()
cpolrInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
if item, ok := obj.(*pr.ClusterPolicyReport); ok {
preport := k.mapper.MapClusterPolicyReport(item)
if k.reportFilter.AllowReport(preport) {
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: &report.PolicyReport{}, Type: report.Added})
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: report.PolicyReport{}, Type: report.Added})
}
}
},
@ -122,7 +109,7 @@ func (k *k8sPolicyReportClient) watchClusterPolicyReport(ctx context.Context, in
if item, ok := obj.(*pr.ClusterPolicyReport); ok {
preport := k.mapper.MapClusterPolicyReport(item)
if k.reportFilter.AllowReport(preport) {
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: &report.PolicyReport{}, Type: report.Deleted})
k.debouncer.Add(report.LifecycleEvent{NewPolicyReport: preport, OldPolicyReport: report.PolicyReport{}, Type: report.Deleted})
}
}
},
@ -130,7 +117,7 @@ func (k *k8sPolicyReportClient) watchClusterPolicyReport(ctx context.Context, in
if item, ok := newObj.(*pr.ClusterPolicyReport); ok {
preport := k.mapper.MapClusterPolicyReport(item)
var oreport *report.PolicyReport
var oreport report.PolicyReport
if oldItem, ok := oldObj.(*pr.ClusterPolicyReport); ok {
oreport = k.mapper.MapClusterPolicyReport(oldItem)
}
@ -142,53 +129,24 @@ func (k *k8sPolicyReportClient) watchClusterPolicyReport(ctx context.Context, in
},
})
informer.Run(ctx.Done())
}
func (k *k8sPolicyReportClient) handleCRDRegistration(ctx context.Context, informer cache.SharedIndexInformer, crd string) {
ticker := time.NewTicker(k.restartWatchOnFailure)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
if informer.HasSynced() {
k.mx.Lock()
k.found[crd] = crd
k.mx.Unlock()
log.Printf("[INFO] Resource registered: %s\n", crd)
return
}
}
}
}
func (k *k8sPolicyReportClient) addErrorWatchHandler(ctx context.Context, informer cache.SharedIndexInformer, crd string) context.Context {
ctx, cancel := context.WithCancel(ctx)
informer.SetWatchErrorHandler(func(c *cache.Reflector, err error) {
k.mx.Lock()
delete(k.found, crd)
k.mx.Unlock()
cancel()
log.Printf("[WARNING] Resource registration failed: %s\n", crd)
cpolrInformer.SetWatchErrorHandler(func(_ *cache.Reflector, _ error) {
k.synced = false
})
return ctx
return cpolrInformer
}
// NewPolicyReportAdapter new Adapter for Policy Report Kubernetes API
func NewPolicyReportClient(client versioned.Interface, mapper Mapper, restartWatchOnFailure time.Duration, reportFilter report.Filter) report.PolicyReportClient {
func NewPolicyReportClient(client versioned.Interface, mapper Mapper, reportFilter report.Filter, publisher report.EventPublisher) report.PolicyReportClient {
fatcory := externalversions.NewSharedInformerFactory(client, time.Hour)
v1alpha2 := fatcory.Wgpolicyk8s().V1alpha2()
return &k8sPolicyReportClient{
client: client,
mapper: mapper,
mx: &sync.Mutex{},
found: make(map[string]string),
debouncer: NewDebouncer(time.Minute),
restartWatchOnFailure: restartWatchOnFailure,
reportFilter: reportFilter,
fatcory: fatcory,
v1alpha2: v1alpha2,
mapper: mapper,
mx: &sync.Mutex{},
debouncer: NewDebouncer(time.Minute, publisher),
reportFilter: reportFilter,
}
}

View file

@ -2,7 +2,6 @@ package kubernetes_test
import (
"context"
"fmt"
"sync"
"testing"
"time"
@ -17,29 +16,26 @@ var filter = report.NewFilter(false, make([]string, 0), make([]string, 0))
func Test_PolicyReportWatcher(t *testing.T) {
ctx := context.Background()
kclient, rclient, _ := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), 100*time.Millisecond, filter)
group := client.WatchPolicyReports(ctx)
store := newStore(3)
stop := make(chan struct{})
defer close(stop)
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
reportID := <-group.ChannelAdded()
eventChan, err := group.Listen(reportID)
if err != nil {
t.Error(err)
}
store := newStore(3)
publisher := report.NewEventPublisher()
publisher.RegisterListener(func(event report.LifecycleEvent) {
store.Add(event)
wg.Done()
})
for event := range eventChan {
fmt.Printf("%v\n", event.Type)
store.Add(event)
wg.Done()
}
}()
kclient, rclient, _ := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), filter, publisher)
err := client.Run(stop)
if err != nil {
t.Fatal(err)
}
rclient.Create(ctx, policyReportCRD, metav1.CreateOptions{})
time.Sleep(10 * time.Millisecond)
@ -55,28 +51,25 @@ func Test_PolicyReportWatcher(t *testing.T) {
}
func Test_ClusterPolicyReportWatcher(t *testing.T) {
ctx := context.Background()
kclient, _, rclient := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), 100*time.Millisecond, filter)
group := client.WatchPolicyReports(ctx)
store := newStore(3)
stop := make(chan struct{})
defer close(stop)
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
reportID := <-group.ChannelAdded()
eventChan, err := group.Listen(reportID)
if err != nil {
t.Error(err)
}
store := newStore(3)
publisher := report.NewEventPublisher()
publisher.RegisterListener(func(event report.LifecycleEvent) {
store.Add(event)
wg.Done()
})
for event := range eventChan {
store.Add(event)
wg.Done()
}
}()
kclient, _, rclient := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), filter, publisher)
err := client.Run(stop)
if err != nil {
t.Fatal(err)
}
rclient.Create(ctx, clusterPolicyReportCRD, metav1.CreateOptions{})
time.Sleep(10 * time.Millisecond)
@ -91,32 +84,19 @@ func Test_ClusterPolicyReportWatcher(t *testing.T) {
}
}
func Test_GetFoundResources(t *testing.T) {
ctx := context.Background()
func Test_HasSynced(t *testing.T) {
stop := make(chan struct{})
defer close(stop)
kclient, _, _ := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), 100*time.Millisecond, filter)
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), filter, report.NewEventPublisher())
client.WatchPolicyReports(ctx)
err := client.Run(stop)
if err != nil {
t.Fatal(err)
}
time.Sleep(1 * time.Second)
if len(client.GetFoundResources()) != 2 {
t.Errorf("Should find PolicyReport and ClusterPolicyReport Resource")
}
}
func Test_GetFoundResourcesWihDisabledClusterReports(t *testing.T) {
ctx := context.Background()
kclient, _, _ := NewFakeCilent()
client := kubernetes.NewPolicyReportClient(kclient, NewMapper(), 100*time.Millisecond, report.NewFilter(true, make([]string, 0), make([]string, 0)))
client.WatchPolicyReports(ctx)
time.Sleep(1 * time.Second)
if len(client.GetFoundResources()) != 1 {
t.Errorf("Should find only PolicyReport Resource")
if client.HasSynced() != true {
t.Errorf("Should synced")
}
}

View file

@ -6,7 +6,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/report"
)
var result1 = &report.Result{
var result1 = report.Result{
ID: "123",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -17,7 +17,7 @@ var result1 = &report.Result{
Severity: report.High,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -26,7 +26,7 @@ var result1 = &report.Result{
},
}
var result2 = &report.Result{
var result2 = report.Result{
ID: "124",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -36,7 +36,7 @@ var result2 = &report.Result{
Category: "Best Practices",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Pod",
Name: "nginx",
@ -45,31 +45,26 @@ var result2 = &report.Result{
},
}
var preport1 = &report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
},
Summary: &report.Summary{Fail: 1},
var preport1 = report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: []report.Result{result1},
Summary: report.Summary{Fail: 1},
CreationTimestamp: time.Now(),
}
var preport2 = &report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result2.GetIdentifier(): result2,
},
Summary: &report.Summary{Fail: 1, Pass: 1},
var preport2 = report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: []report.Result{result1, result2},
Summary: report.Summary{Fail: 1, Pass: 1},
CreationTimestamp: time.Now(),
}
var creport = &report.PolicyReport{
var creport = report.PolicyReport{
Name: "cpolr-test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}

View file

@ -22,8 +22,8 @@ func CreateClusterPolicyReportMetricsListener(filter *Filter) report.PolicyRepor
prometheus.Register(clusterPolicyGauge)
prometheus.Register(clusterRuleGauge)
var newReport *report.PolicyReport
var oldReport *report.PolicyReport
var newReport report.PolicyReport
var oldReport report.PolicyReport
return func(event report.LifecycleEvent) {
newReport = event.NewPolicyReport
@ -70,7 +70,7 @@ func CreateClusterPolicyReportMetricsListener(filter *Filter) report.PolicyRepor
}
}
func generateClusterResultLabels(newReport *report.PolicyReport, result *report.Result) prometheus.Labels {
func generateClusterResultLabels(newReport report.PolicyReport, result report.Result) prometheus.Labels {
labels := prometheus.Labels{
"rule": result.Rule,
"policy": result.Policy,
@ -91,7 +91,7 @@ func generateClusterResultLabels(newReport *report.PolicyReport, result *report.
return labels
}
func resetClusterPolicyGauge(newReport *report.PolicyReport) {
func resetClusterPolicyGauge(newReport report.PolicyReport) {
clusterPolicyGauge.
WithLabelValues(newReport.Name, "Pass").
Set(0)

View file

@ -13,37 +13,30 @@ import (
var creport = &report.PolicyReport{
Name: "cpolr-test",
Results: make(map[string]*report.Result),
Summary: &report.Summary{},
Results: make([]report.Result, 0),
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}
func Test_ClusterPolicyReportMetricGeneration(t *testing.T) {
report1 := &report.PolicyReport{
report1 := report.PolicyReport{
Name: "cpolr-test",
Summary: &report.Summary{Pass: 1, Fail: 1},
Summary: report.Summary{Pass: 1, Fail: 1},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result2.GetIdentifier(): result2,
result3.GetIdentifier(): result3,
},
Results: []report.Result{result1, result2, result3},
}
report2 := &report.PolicyReport{
report2 := report.PolicyReport{
Name: "cpolr-test",
Summary: &report.Summary{Pass: 0, Fail: 1},
Summary: report.Summary{Pass: 0, Fail: 1},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result3.GetIdentifier(): result3,
},
Results: []report.Result{result1, result3},
}
handler := metrics.CreateClusterPolicyReportMetricsListener(&metrics.Filter{Policy: metrics.Rules{Exclude: []string{"disallow-policy"}}})
t.Run("Added Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {
@ -88,7 +81,7 @@ func Test_ClusterPolicyReportMetricGeneration(t *testing.T) {
})
t.Run("Modified Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report2, OldPolicyReport: report1})
metricFam, err := prometheus.DefaultGatherer.Gather()
@ -134,9 +127,9 @@ func Test_ClusterPolicyReportMetricGeneration(t *testing.T) {
})
t.Run("Deleted Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report2, OldPolicyReport: report1})
handler(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: report2, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: report2, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {
@ -183,7 +176,7 @@ func testClusterSummaryMetricLabels(
return nil
}
func testClusterResultMetricLabels(metric *ioprometheusclient.Metric, result *report.Result) error {
func testClusterResultMetricLabels(metric *ioprometheusclient.Metric, result report.Result) error {
if name := *metric.Label[0].Name; name != "category" {
return fmt.Errorf("unexpected Category Label: %s", name)
}

View file

@ -18,8 +18,8 @@ type Filter struct {
Severity Rules
}
func (f *Filter) Validate(result *report.Result) bool {
if result.Resource != nil &&
func (f *Filter) Validate(result report.Result) bool {
if result.HasResource() &&
result.Resource.Namespace != "" &&
!validateRules(result.Resource.Namespace, f.Namespace) {
return false

View file

@ -22,8 +22,8 @@ func CreatePolicyReportMetricsListener(filter *Filter) report.PolicyReportListen
prometheus.Register(policyGauge)
prometheus.Register(ruleGauge)
var newReport *report.PolicyReport
var oldReport *report.PolicyReport
var newReport report.PolicyReport
var oldReport report.PolicyReport
return func(event report.LifecycleEvent) {
newReport = event.NewPolicyReport
@ -70,7 +70,7 @@ func CreatePolicyReportMetricsListener(filter *Filter) report.PolicyReportListen
}
}
func generateResultLabels(report *report.PolicyReport, result *report.Result) prometheus.Labels {
func generateResultLabels(report report.PolicyReport, result report.Result) prometheus.Labels {
labels := prometheus.Labels{
"namespace": report.Namespace,
"rule": result.Rule,
@ -92,7 +92,7 @@ func generateResultLabels(report *report.PolicyReport, result *report.Result) pr
return labels
}
func resetPolicyGauge(newReport *report.PolicyReport) {
func resetPolicyGauge(newReport report.PolicyReport) {
policyGauge.WithLabelValues(newReport.Namespace, newReport.Name, "Pass").Set(0)
policyGauge.WithLabelValues(newReport.Namespace, newReport.Name, "Fail").Set(0)
policyGauge.WithLabelValues(newReport.Namespace, newReport.Name, "Warn").Set(0)

View file

@ -11,7 +11,7 @@ import (
ioprometheusclient "github.com/prometheus/client_model/go"
)
var result1 = &report.Result{
var result1 = report.Result{
ID: "1",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -21,7 +21,7 @@ var result1 = &report.Result{
Severity: report.High,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -31,7 +31,7 @@ var result1 = &report.Result{
Source: "Kyverno",
}
var result2 = &report.Result{
var result2 = report.Result{
ID: "2",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "check-requests-and-limits-required",
@ -40,7 +40,7 @@ var result2 = &report.Result{
Status: report.Pass,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -50,7 +50,7 @@ var result2 = &report.Result{
Source: "Kyverno",
}
var result3 = &report.Result{
var result3 = report.Result{
ID: "3",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "disallow-policy",
@ -59,7 +59,7 @@ var result3 = &report.Result{
Status: report.Pass,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -69,45 +69,38 @@ var result3 = &report.Result{
Source: "Kyverno",
}
var preport = &report.PolicyReport{
var preport = report.PolicyReport{
ID: "1",
Name: "polr-test",
Namespace: "test",
Results: make(map[string]*report.Result),
Summary: &report.Summary{},
Results: make([]report.Result, 0),
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}
func Test_PolicyReportMetricGeneration(t *testing.T) {
report1 := &report.PolicyReport{
report1 := report.PolicyReport{
ID: "1",
Name: "polr-test",
Namespace: "test",
Summary: &report.Summary{Pass: 2, Fail: 1},
Summary: report.Summary{Pass: 2, Fail: 1},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result2.GetIdentifier(): result2,
result3.GetIdentifier(): result3,
},
Results: []report.Result{result1, result2, result3},
}
report2 := &report.PolicyReport{
report2 := report.PolicyReport{
ID: "1",
Name: "polr-test",
Namespace: "test",
Summary: &report.Summary{Pass: 0, Fail: 1},
Summary: report.Summary{Pass: 0, Fail: 1},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result3.GetIdentifier(): result3,
},
Results: []report.Result{result1, result3},
}
handler := metrics.CreatePolicyReportMetricsListener(&metrics.Filter{Policy: metrics.Rules{Exclude: []string{"disallow-policy"}}})
t.Run("Added Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {
@ -152,7 +145,7 @@ func Test_PolicyReportMetricGeneration(t *testing.T) {
})
t.Run("Modified Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report2, OldPolicyReport: report1})
metricFam, err := prometheus.DefaultGatherer.Gather()
@ -198,9 +191,9 @@ func Test_PolicyReportMetricGeneration(t *testing.T) {
})
t.Run("Deleted Metric", func(t *testing.T) {
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Added, NewPolicyReport: report1, OldPolicyReport: report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report2, OldPolicyReport: report1})
handler(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: report2, OldPolicyReport: &report.PolicyReport{}})
handler(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: report2, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {
@ -221,7 +214,7 @@ func Test_PolicyReportMetricGeneration(t *testing.T) {
func testSummaryMetricLabels(
metric *ioprometheusclient.Metric,
preport *report.PolicyReport,
preport report.PolicyReport,
status string,
gauge float64,
) error {
@ -253,7 +246,7 @@ func testSummaryMetricLabels(
return nil
}
func testResultMetricLabels(metric *ioprometheusclient.Metric, result *report.Result) error {
func testResultMetricLabels(metric *ioprometheusclient.Metric, result report.Result) error {
if name := *metric.Label[0].Name; name != "category" {
return fmt.Errorf("unexpected Name Label: %s", name)
}

View file

@ -15,7 +15,7 @@ func Test_MetricsListener(t *testing.T) {
slistener := listener.NewMetricsListener(&metrics.Filter{})
t.Run("Add ClusterPolicyReport Metric", func(t *testing.T) {
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: creport, OldPolicyReport: &report.PolicyReport{}})
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: creport, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {
@ -28,7 +28,7 @@ func Test_MetricsListener(t *testing.T) {
}
})
t.Run("Add PolicyReport Metric", func(t *testing.T) {
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: preport1, OldPolicyReport: &report.PolicyReport{}})
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: preport1, OldPolicyReport: report.PolicyReport{}})
metricFam, err := prometheus.DefaultGatherer.Gather()
if err != nil {

View file

@ -21,8 +21,8 @@ func (l *ResultListener) RegisterListener(listener report.PolicyReportResultList
func (l *ResultListener) Listen(event report.LifecycleEvent) {
if len(event.OldPolicyReport.Results) > 0 {
for id := range event.OldPolicyReport.Results {
l.cache.Add(id)
for _, result := range event.OldPolicyReport.Results {
l.cache.Add(result.ID)
}
}
@ -56,7 +56,7 @@ func (l *ResultListener) Listen(event report.LifecycleEvent) {
wg.Add(len(l.listener))
for _, cb := range l.listener {
go func(callback report.PolicyReportResultListener, result *report.Result) {
go func(callback report.PolicyReportResultListener, result report.Result) {
callback(result, preExisted)
wg.Done()
}(cb, r)

View file

@ -11,10 +11,10 @@ import (
func Test_ResultListener(t *testing.T) {
t.Run("Publish Result", func(t *testing.T) {
var called *report.Result
var called report.Result
slistener := listener.NewResultListener(true, cache.New(0, 5*time.Minute), time.Now())
slistener.RegisterListener(func(r *report.Result, b bool) {
slistener.RegisterListener(func(r report.Result, b bool) {
called = r
})
@ -29,7 +29,7 @@ func Test_ResultListener(t *testing.T) {
var called bool
slistener := listener.NewResultListener(true, cache.New(0, 5*time.Minute), time.Now())
slistener.RegisterListener(func(r *report.Result, b bool) {
slistener.RegisterListener(func(r report.Result, b bool) {
called = true
})
@ -44,7 +44,7 @@ func Test_ResultListener(t *testing.T) {
var called bool
slistener := listener.NewResultListener(true, cache.New(0, 5*time.Minute), time.Now())
slistener.RegisterListener(func(r *report.Result, b bool) {
slistener.RegisterListener(func(r report.Result, b bool) {
called = true
})
@ -62,7 +62,7 @@ func Test_ResultListener(t *testing.T) {
rcache.Add(result2.ID)
slistener := listener.NewResultListener(true, rcache, time.Now())
slistener.RegisterListener(func(r *report.Result, b bool) {
slistener.RegisterListener(func(r report.Result, b bool) {
called = true
})
@ -80,7 +80,7 @@ func Test_ResultListener(t *testing.T) {
rcache.Add(result2.ID)
slistener := listener.NewResultListener(true, rcache, time.Now())
slistener.RegisterListener(func(r *report.Result, b bool) {
slistener.RegisterListener(func(r report.Result, b bool) {
called = true
})

View file

@ -8,12 +8,12 @@ import (
)
func NewSendResultListener(clients []target.Client) report.PolicyReportResultListener {
return func(r *report.Result, e bool) {
return func(r report.Result, e bool) {
wg := &sync.WaitGroup{}
wg.Add(len(clients))
for _, t := range clients {
go func(target target.Client, result *report.Result, preExisted bool) {
go func(target target.Client, result report.Result, preExisted bool) {
defer wg.Done()
if (preExisted && target.SkipExistingOnStartup()) || !target.Validate(result) {

View file

@ -14,7 +14,7 @@ type client struct {
validated bool
}
func (c *client) Send(result *report.Result) {
func (c *client) Send(result report.Result) {
c.Called = true
}
@ -34,7 +34,7 @@ func (c *client) SkipExistingOnStartup() bool {
return c.skipExistingOnStartup
}
func (c client) Validate(result *report.Result) bool {
func (c client) Validate(result report.Result) bool {
return c.validated
}

View file

@ -12,7 +12,7 @@ func Test_StoreListener(t *testing.T) {
t.Run("Save New Report", func(t *testing.T) {
slistener := listener.NewStoreListener(store)
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: preport1, OldPolicyReport: &report.PolicyReport{}})
slistener(report.LifecycleEvent{Type: report.Added, NewPolicyReport: preport1, OldPolicyReport: report.PolicyReport{}})
if _, ok := store.Get(preport1.ID); !ok {
t.Error("Expected Report to be stored")
@ -28,7 +28,7 @@ func Test_StoreListener(t *testing.T) {
})
t.Run("Remove Deleted Report", func(t *testing.T) {
slistener := listener.NewStoreListener(store)
slistener(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: preport2, OldPolicyReport: &report.PolicyReport{}})
slistener(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: preport2, OldPolicyReport: report.PolicyReport{}})
if _, ok := store.Get(preport2.ID); ok {
t.Error("Expected Report to be removed")

View file

@ -1,19 +1,15 @@
package report
import (
"context"
)
// PolicyReportListener is called whenever a new PolicyReport comes in
type PolicyReportListener = func(LifecycleEvent)
// PolicyReportResultListener is called whenever a new PolicyResult comes in
type PolicyReportResultListener = func(*Result, bool)
type PolicyReportResultListener = func(Result, bool)
// PolicyReportClient watches for PolicyReport Events and executes registered callback
type PolicyReportClient interface {
// WatchPolicyReports starts to watch for PolicyReport LifecycleEvent events
WatchPolicyReports(ctx context.Context) *Group
// GetFoundResources as Map of Names
GetFoundResources() map[string]string
Run(stopper chan struct{}) error
// HasSynced the configured PolicyReport
HasSynced() bool
}

View file

@ -4,7 +4,7 @@ import "github.com/minio/pkg/wildcard"
type Filter interface {
DisableClusterReports() bool
AllowReport(report *PolicyReport) bool
AllowReport(report PolicyReport) bool
}
type filter struct {
@ -17,7 +17,7 @@ func (f *filter) DisableClusterReports() bool {
return f.disbaleClusterReports
}
func (f *filter) AllowReport(report *PolicyReport) bool {
func (f *filter) AllowReport(report PolicyReport) bool {
if report.Namespace == "" {
return true
} else if len(f.includeNamespaces) > 0 {

View file

@ -2,9 +2,10 @@ package report
import (
"bytes"
"crypto/sha1"
"fmt"
"strconv"
"time"
"github.com/segmentio/fasthash/fnv1a"
)
// Event Enum
@ -33,8 +34,8 @@ const (
// LifecycleEvent of PolicyReports
type LifecycleEvent struct {
Type Event
NewPolicyReport *PolicyReport
OldPolicyReport *PolicyReport
NewPolicyReport PolicyReport
OldPolicyReport PolicyReport
}
// Status Enum defined for PolicyReport
@ -173,15 +174,15 @@ type Result struct {
Message string
Policy string
Rule string
Priority Priority
Status Status
Severity Severity `json:",omitempty"`
Category string `json:",omitempty"`
Source string `json:",omitempty"`
Scored bool
Timestamp time.Time
Resource *Resource
Properties map[string]string
Resource Resource
Priority Priority
Scored bool
}
// GetIdentifier returns a global unique Result identifier
@ -191,10 +192,6 @@ func (r Result) GetIdentifier() string {
// HasResource checks if the result has an valid Resource
func (r Result) HasResource() bool {
if r.Resource == nil {
return false
}
return r.Resource.UID != "" || r.Resource.Name != ""
}
@ -212,8 +209,8 @@ type PolicyReport struct {
ID string
Name string
Namespace string
Results map[string]*Result
Summary *Summary
Results []Result
Summary Summary
CreationTimestamp time.Time
}
@ -224,19 +221,29 @@ func (pr PolicyReport) GetIdentifier() string {
// HasResult returns if the Report has an Rusult with the given ID
func (pr PolicyReport) HasResult(id string) bool {
_, ok := pr.Results[id]
for _, r := range pr.Results {
if r.ID == id {
return true
}
}
return ok
return false
}
// GetResult returns if the Report has an Rusult with the given ID
func (pr PolicyReport) GetResult(id string) Result {
for _, r := range pr.Results {
if r.ID == id {
return r
}
}
return Result{}
}
// ResultList returns all results as slice
func (pr PolicyReport) ResultList() []*Result {
list := make([]*Result, 0, len(pr.Results))
for _, v := range pr.Results {
list = append(list, v)
}
return list
func (pr PolicyReport) ResultList() []Result {
return pr.Results
}
// GetType returns the Type of the Report
@ -249,8 +256,8 @@ func (pr PolicyReport) GetType() ResourceType {
}
// GetNewResults filters already existing Results from the old PolicyReport and returns only the diff with new Results
func (pr PolicyReport) GetNewResults(or *PolicyReport) []*Result {
diff := make([]*Result, 0)
func (pr PolicyReport) GetNewResults(or PolicyReport) []Result {
diff := make([]Result, 0)
for _, r := range pr.Results {
if or.HasResult(r.GetIdentifier()) {
@ -264,28 +271,26 @@ func (pr PolicyReport) GetNewResults(or *PolicyReport) []*Result {
}
func GeneratePolicyReportID(name, namespace string) string {
id := name
h1 := fnv1a.Init64
h1 = fnv1a.AddString64(h1, name)
if namespace != "" {
id = fmt.Sprintf("%s__%s", namespace, name)
h1 = fnv1a.AddString64(h1, namespace)
}
h := sha1.New()
h.Write([]byte(id))
return fmt.Sprintf("%x", h.Sum(nil))
return strconv.FormatUint(h1, 10)
}
func GeneratePolicyReportResultID(uid, name, policy, rule, status, suffix string) string {
h1 := fnv1a.Init64
h1 = fnv1a.AddString64(h1, name)
h1 = fnv1a.AddString64(h1, policy)
h1 = fnv1a.AddString64(h1, rule)
h1 = fnv1a.AddString64(h1, status)
h1 = fnv1a.AddString64(h1, suffix)
if uid != "" {
suffix = "__" + uid
h1 = fnv1a.AddString64(h1, uid)
}
id := fmt.Sprintf("%s_%s__%s__%s%s", name, policy, rule, status, suffix)
h := sha1.New()
h.Write([]byte(id))
return fmt.Sprintf("%x", h.Sum(nil))
return strconv.FormatUint(h1, 10)
}

View file

@ -7,8 +7,8 @@ import (
"github.com/kyverno/policy-reporter/pkg/report"
)
var result1 = &report.Result{
ID: "c6215d837642824766ec511357140bf02636b5d8",
var result1 = report.Result{
ID: "8804968580595351199",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -17,7 +17,7 @@ var result1 = &report.Result{
Category: "resources",
Severity: report.High,
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -26,7 +26,7 @@ var result1 = &report.Result{
},
}
var result2 = &report.Result{
var result2 = report.Result{
ID: "2",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -35,7 +35,7 @@ var result2 = &report.Result{
Status: report.Fail,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -44,20 +44,20 @@ var result2 = &report.Result{
},
}
var preport = &report.PolicyReport{
ID: "24cfa233af033d104cd6ce0ff9a5a875c71a5844",
var preport = report.PolicyReport{
ID: "7605991845421273693",
Name: "polr-test",
Namespace: "test",
Results: make(map[string]*report.Result),
Summary: &report.Summary{},
Results: make([]report.Result, 0),
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}
var creport = &report.PolicyReport{
ID: "57e1551475e17740bacc3640d2412b1a6aad6a93",
var creport = report.PolicyReport{
ID: "1241710096395975500",
Name: "cpolr-test",
Results: make(map[string]*report.Result),
Summary: &report.Summary{},
Results: make([]report.Result, 0),
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}
@ -71,21 +71,21 @@ func Test_PolicyReport(t *testing.T) {
})
t.Run("Check PolicyReport.GetNewResults", func(t *testing.T) {
preport1 := &report.PolicyReport{
preport1 := report.PolicyReport{
ID: "24cfa233af033d104cd6ce0ff9a5a875c71a5844",
Name: "polr-test",
Namespace: "test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{result1.GetIdentifier(): result1},
Results: []report.Result{result1},
}
preport2 := &report.PolicyReport{
preport2 := report.PolicyReport{
ID: "24cfa233af033d104cd6ce0ff9a5a875c71a5844",
Name: "polr-test",
Namespace: "test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{result1.GetIdentifier(): result1, result2.GetIdentifier(): result2},
Results: []report.Result{result1, result2},
}
diff := preport2.GetNewResults(preport1)
@ -98,9 +98,9 @@ func Test_PolicyReport(t *testing.T) {
creport2 := &report.PolicyReport{
ID: "57e1551475e17740bacc3640d2412b1a6aad6a93",
Name: "cpolr-test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{result1.GetIdentifier(): result1, result2.GetIdentifier(): result2},
Results: []report.Result{result1, result2},
}
list := creport2.ResultList()
@ -109,7 +109,23 @@ func Test_PolicyReport(t *testing.T) {
t.Errorf("Expected len of PolicyReport.ResultList() to be 2 (actual: %d)", len(list))
}
})
t.Run("Check PolicyReport.GetResult", func(t *testing.T) {
preport := report.PolicyReport{
ID: "24cfa233af033d104cd6ce0ff9a5a875c71a5844",
Name: "polr-test",
Namespace: "test",
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: []report.Result{result1},
}
if result := preport.GetResult("8804968580595351199"); result.ID != "8804968580595351199" {
t.Error("Expected PolicyReport.GetResult() returns a given Result by ID")
}
if result := preport.GetResult("123"); result.ID != "" {
t.Error("Expected PolicyReport.GetResult() returns an empty Result for an unknown ID")
}
})
}
func Test_ClusterPolicyReport(t *testing.T) {
@ -127,20 +143,20 @@ func Test_ClusterPolicyReport(t *testing.T) {
})
t.Run("Check ClusterPolicyReport.GetNewResults", func(t *testing.T) {
creport1 := &report.PolicyReport{
creport1 := report.PolicyReport{
ID: "57e1551475e17740bacc3640d2412b1a6aad6a93",
Name: "cpolr-test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{result1.GetIdentifier(): result1},
Results: []report.Result{result1},
}
creport2 := &report.PolicyReport{
ID: "57e1551475e17740bacc3640d2412b1a6aad6a93",
Name: "cpolr-test",
Summary: &report.Summary{},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
Results: map[string]*report.Result{result1.GetIdentifier(): result1, result2.GetIdentifier(): result2},
Results: []report.Result{result1, result2},
}
diff := creport2.GetNewResults(creport1)
@ -170,7 +186,6 @@ func Test_Result(t *testing.T) {
t.Errorf("Expected result.HasResource() to be false without a Resource (actual: %v)", result1.HasResource())
}
})
}
func Test_MarshalPriority(t *testing.T) {
@ -250,3 +265,20 @@ func Test_Priorities(t *testing.T) {
}
})
}
func Test_Events(t *testing.T) {
t.Run("Event.String", func(t *testing.T) {
if report.Added.String() != "add" {
t.Errorf("Unexpected type conversion, expected %s go %s", "add", report.Added.String())
}
if report.Updated.String() != "update" {
t.Errorf("Unexpected type conversion, expected %s go %s", "update", report.Updated.String())
}
if report.Deleted.String() != "delete" {
t.Errorf("Unexpected type conversion, expected %s go %s", "delete", report.Deleted.String())
}
if report.Event(4).String() != "unknown" {
t.Errorf("Unexpected type conversion, expected %s go %s", "unknown", report.Event(4).String())
}
})
}

View file

@ -1,91 +1,16 @@
package report
import (
"fmt"
"sync"
"time"
)
type Group struct {
reportsChan chan string
eventGroups map[string]chan LifecycleEvent
}
func (g *Group) Register(reportID string) {
g.eventGroups[reportID] = make(chan LifecycleEvent)
g.reportsChan <- reportID
}
func (g *Group) ChannelAdded() <-chan string {
return g.reportsChan
}
func (g *Group) AddEvent(event LifecycleEvent) {
if channel, ok := g.eventGroups[event.NewPolicyReport.ID]; ok {
channel <- event
}
}
func (g *Group) Listen(reportID string) (<-chan LifecycleEvent, error) {
if channel, ok := g.eventGroups[reportID]; ok {
return channel, nil
}
return nil, fmt.Errorf("channel for ReportID %s not found", reportID)
}
func (g *Group) ListenWithRetry(reportID string, retry int) (<-chan LifecycleEvent, error) {
var count int
var err error
for count <= retry {
channel, err := g.Listen(reportID)
if err == nil {
return channel, nil
}
count++
time.Sleep(1 * time.Second)
}
return nil, err
}
func (g *Group) Close(reportID string) error {
if channel, ok := g.eventGroups[reportID]; ok {
close(channel)
delete(g.eventGroups, reportID)
return nil
}
return fmt.Errorf("channel for ReportID %s not found", reportID)
}
func (g *Group) CloseRegisterChannel() {
close(g.reportsChan)
}
func (g *Group) CloseAll() {
for reportID, channel := range g.eventGroups {
close(channel)
delete(g.eventGroups, reportID)
}
close(g.reportsChan)
}
func NewGroup() *Group {
return &Group{
reportsChan: make(chan string),
eventGroups: make(map[string]chan LifecycleEvent),
}
}
type EventPublisher interface {
// RegisterListener register Handlers called on each PolicyReport watch.Event
RegisterListener(PolicyReportListener)
// GetListener returns a list of all registered Listeners
GetListener() []PolicyReportListener
// Publish events to the registered listeners
Publish(reportChannels *Group)
// Process LifecycleEvent with all registered listeners
Publish(event LifecycleEvent)
}
type lifecycleEventPublisher struct {
@ -102,33 +27,18 @@ func (p *lifecycleEventPublisher) GetListener() []PolicyReportListener {
return p.listeners
}
func (p *lifecycleEventPublisher) Publish(reportChannels *Group) {
for channelName := range reportChannels.ChannelAdded() {
go func(cName string) {
channel, err := reportChannels.ListenWithRetry(cName, 3)
if err != nil {
fmt.Println(err.Error())
}
func (p *lifecycleEventPublisher) Publish(event LifecycleEvent) {
g := sync.WaitGroup{}
g.Add(len(p.listeners))
for _, listener := range p.listeners {
go func(li PolicyReportListener, ev LifecycleEvent) {
li(ev)
for event := range channel {
wg := sync.WaitGroup{}
wg.Add(p.listenerCount)
for _, listener := range p.listeners {
go func(li PolicyReportListener, ev LifecycleEvent) {
li(ev)
wg.Done()
}(listener, event)
}
wg.Wait()
if event.Type == Deleted {
reportChannels.Close(cName)
}
}
}(channelName)
g.Done()
}(listener, event)
}
g.Wait()
}
func NewEventPublisher() EventPublisher {

View file

@ -19,17 +19,7 @@ func Test_PublishLifecycleEvents(t *testing.T) {
wg.Done()
})
groups := report.NewGroup()
go func() {
groups.Register("UID")
groups.AddEvent(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: &report.PolicyReport{ID: "UID"}, OldPolicyReport: &report.PolicyReport{ID: "UID"}})
groups.CloseAll()
}()
publisher.Publish(groups)
publisher.Publish(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report.PolicyReport{ID: "UID"}, OldPolicyReport: report.PolicyReport{ID: "UID"}})
wg.Wait()
@ -50,27 +40,14 @@ func Test_PublishDeleteLifecycleEvents(t *testing.T) {
wg.Done()
})
groups := report.NewGroup()
go func() {
groups.Register("UID")
groups.AddEvent(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: &report.PolicyReport{ID: "UID"}, OldPolicyReport: &report.PolicyReport{ID: "UID"}})
groups.AddEvent(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: &report.PolicyReport{ID: "UID"}})
groups.CloseRegisterChannel()
}()
publisher.Publish(groups)
publisher.Publish(report.LifecycleEvent{Type: report.Updated, NewPolicyReport: report.PolicyReport{ID: "UID"}, OldPolicyReport: report.PolicyReport{ID: "UID"}})
publisher.Publish(report.LifecycleEvent{Type: report.Deleted, NewPolicyReport: report.PolicyReport{ID: "UID"}})
wg.Wait()
if event.Type != report.Deleted {
t.Error("Expected Event to be published to the listener")
}
if _, err := groups.Listen("UID"); err == nil {
t.Error("Expected report to be deleted")
}
}
func Test_GetReisteredListeners(t *testing.T) {
@ -81,12 +58,3 @@ func Test_GetReisteredListeners(t *testing.T) {
t.Error("Expected to get one registered listener back")
}
}
func Test_ListenUknownChannel(t *testing.T) {
reportChannel := report.NewGroup()
_, err := reportChannel.Listen("test")
if err == nil {
t.Error("Expected to get a not found error")
}
}

View file

@ -6,11 +6,11 @@ type PolicyReportStore interface {
// CreateSchemas for PolicyReports and PolicyReportResults
CreateSchemas() error
// Get an PolicyReport by Type and ID
Get(id string) (*PolicyReport, bool)
Get(id string) (PolicyReport, bool)
// Add a PolicyReport to the Store
Add(r *PolicyReport) error
Add(r PolicyReport) error
// Add a PolicyReport to the Store
Update(r *PolicyReport) error
Update(r PolicyReport) error
// Remove a PolicyReport with the given Type and ID from the Store
Remove(id string) error
// CleanUp removes all items in the store
@ -19,7 +19,7 @@ type PolicyReportStore interface {
// PolicyReportStore caches the latest version of an PolicyReport
type policyReportStore struct {
store map[string]map[string]*PolicyReport
store map[string]map[string]PolicyReport
rwm *sync.RWMutex
}
@ -27,7 +27,7 @@ func (s *policyReportStore) CreateSchemas() error {
return nil
}
func (s *policyReportStore) Get(id string) (*PolicyReport, bool) {
func (s *policyReportStore) Get(id string) (PolicyReport, bool) {
s.rwm.RLock()
r, ok := s.store[PolicyReportType][id]
s.rwm.RUnlock()
@ -42,7 +42,7 @@ func (s *policyReportStore) Get(id string) (*PolicyReport, bool) {
return r, ok
}
func (s *policyReportStore) Add(r *PolicyReport) error {
func (s *policyReportStore) Add(r PolicyReport) error {
s.rwm.Lock()
s.store[r.GetType()][r.GetIdentifier()] = r
s.rwm.Unlock()
@ -50,7 +50,7 @@ func (s *policyReportStore) Add(r *PolicyReport) error {
return nil
}
func (s *policyReportStore) Update(r *PolicyReport) error {
func (s *policyReportStore) Update(r PolicyReport) error {
s.rwm.Lock()
s.store[r.GetType()][r.GetIdentifier()] = r
s.rwm.Unlock()
@ -70,7 +70,7 @@ func (s *policyReportStore) Remove(id string) error {
func (s *policyReportStore) CleanUp() error {
s.rwm.Lock()
s.store = map[ResourceType]map[string]*PolicyReport{
s.store = map[ResourceType]map[string]PolicyReport{
PolicyReportType: {},
ClusterPolicyReportType: {},
}
@ -82,7 +82,7 @@ func (s *policyReportStore) CleanUp() error {
// NewPolicyReportStore construct a PolicyReportStore
func NewPolicyReportStore() PolicyReportStore {
return &policyReportStore{
store: map[ResourceType]map[string]*PolicyReport{
store: map[ResourceType]map[string]PolicyReport{
PolicyReportType: {},
ClusterPolicyReportType: {},
},

View file

@ -25,12 +25,12 @@ func Test_PolicyReportStore(t *testing.T) {
})
t.Run("Update/Get", func(t *testing.T) {
ureport := &report.PolicyReport{
ID: "24cfa233af033d104cd6ce0ff9a5a875c71a5844",
ureport := report.PolicyReport{
ID: "7605991845421273693",
Name: "polr-test",
Namespace: "test",
Results: make(map[string]*report.Result),
Summary: &report.Summary{Skip: 1},
Results: make([]report.Result, 0),
Summary: report.Summary{Skip: 1},
CreationTimestamp: time.Now(),
}

View file

@ -81,9 +81,9 @@ func (s *policyReportStore) CreateSchemas() error {
}
// Get an PolicyReport by Type and ID
func (s *policyReportStore) Get(id string) (*report.PolicyReport, bool) {
func (s *policyReportStore) Get(id string) (report.PolicyReport, bool) {
var created int64
r := &report.PolicyReport{Summary: &report.Summary{}}
r := report.PolicyReport{Summary: report.Summary{}}
row := s.db.QueryRow("SELECT namespace, name, pass, skip, warn, fail, error, created FROM policy_report WHERE id=$1", id)
err := row.Scan(&r.Namespace, &r.Name, &r.Summary.Pass, &r.Summary.Skip, &r.Summary.Warn, &r.Summary.Fail, &r.Summary.Error, &created)
@ -108,7 +108,7 @@ func (s *policyReportStore) Get(id string) (*report.PolicyReport, bool) {
}
// Add a PolicyReport to the Store
func (s *policyReportStore) Add(r *report.PolicyReport) error {
func (s *policyReportStore) Add(r report.PolicyReport) error {
stmt, err := s.db.Prepare("INSERT INTO policy_report(id, type, namespace, name, pass, skip, warn, fail, error, created) values(?,?,?,?,?,?,?,?,?,?)")
if err != nil {
return err
@ -123,7 +123,7 @@ func (s *policyReportStore) Add(r *report.PolicyReport) error {
return s.persistResults(r)
}
func (s *policyReportStore) Update(r *report.PolicyReport) error {
func (s *policyReportStore) Update(r report.PolicyReport) error {
stmt, err := s.db.Prepare("UPDATE policy_report SET pass=?, skip=?, warn=?, fail=?, error=?, created=? WHERE id=?")
if err != nil {
return err
@ -755,12 +755,15 @@ func (s *policyReportStore) CountClusterResults(filter api.Filter) (int, error)
return count, nil
}
func (s *policyReportStore) persistResults(report *report.PolicyReport) error {
func (s *policyReportStore) persistResults(report report.PolicyReport) error {
var vals []interface{}
var sqlStr string
bulks := chunkSlice(report.ResultList(), 50)
for _, list := range bulks {
sqlStr := resultInsertBaseSQL
vals := make([]interface{}, 0, len(list)*18)
sqlStr = resultInsertBaseSQL
vals = make([]interface{}, 0, len(list)*18)
for _, result := range list {
sqlStr += "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?),"
@ -810,8 +813,8 @@ func (s *policyReportStore) persistResults(report *report.PolicyReport) error {
return nil
}
func (s *policyReportStore) fetchResults(reportID string) (map[string]*report.Result, error) {
results := make(map[string]*report.Result)
func (s *policyReportStore) fetchResults(reportID string) ([]report.Result, error) {
results := make([]report.Result, 0)
rows, err := s.db.Query(`
SELECT
@ -844,8 +847,8 @@ func (s *policyReportStore) fetchResults(reportID string) (map[string]*report.Re
var timestamp int64
for rows.Next() {
result := &report.Result{
Resource: &report.Resource{},
result := report.Result{
Resource: report.Resource{},
}
err = rows.Scan(
@ -878,7 +881,7 @@ func (s *policyReportStore) fetchResults(reportID string) (map[string]*report.Re
result.Timestamp = time.Unix(timestamp, 0)
results[result.GetIdentifier()] = result
results = append(results, result)
}
return results, nil
@ -1019,8 +1022,8 @@ func NewDatabase(dbFile string) (*sql.DB, error) {
return sql.Open("sqlite3", dbFile)
}
func chunkSlice(slice []*report.Result, chunkSize int) [][]*report.Result {
var chunks [][]*report.Result
func chunkSlice(slice []report.Result, chunkSize int) [][]report.Result {
var chunks [][]report.Result
for i := 0; i < len(slice); i += chunkSize {
end := i + chunkSize

View file

@ -11,7 +11,7 @@ import (
var pagination = v1.Pagination{Page: 1, Offset: 20, Direction: "ASC", SortBy: []string{"resource_name"}}
var result1 = &report.Result{
var result1 = report.Result{
ID: "123",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -22,7 +22,7 @@ var result1 = &report.Result{
Severity: report.High,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -31,7 +31,7 @@ var result1 = &report.Result{
},
}
var result2 = &report.Result{
var result2 = report.Result{
ID: "124",
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
@ -41,7 +41,7 @@ var result2 = &report.Result{
Category: "Best Practices",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Pod",
Name: "nginx",
@ -50,7 +50,7 @@ var result2 = &report.Result{
},
}
var cresult1 = &report.Result{
var cresult1 = report.Result{
ID: "125",
Message: "validation error: The label `test` is required. Rule check-for-labels-on-namespace",
Policy: "require-ns-labels",
@ -61,7 +61,7 @@ var cresult1 = &report.Result{
Severity: report.Medium,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Namespace",
Name: "test",
@ -69,7 +69,7 @@ var cresult1 = &report.Result{
},
}
var cresult2 = &report.Result{
var cresult2 = report.Result{
ID: "126",
Message: "validation error: The label `test` is required. Rule check-for-labels-on-namespace",
Policy: "require-ns-labels",
@ -80,7 +80,7 @@ var cresult2 = &report.Result{
Severity: report.High,
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Namespace",
Name: "dev",
@ -88,37 +88,29 @@ var cresult2 = &report.Result{
},
}
var preport = &report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
},
Summary: &report.Summary{Fail: 1},
var preport = report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: []report.Result{result1},
Summary: report.Summary{Fail: 1},
CreationTimestamp: time.Now(),
}
var ureport = &report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: map[string]*report.Result{
result1.GetIdentifier(): result1,
result2.GetIdentifier(): result2,
},
Summary: &report.Summary{Fail: 1, Pass: 1},
var ureport = report.PolicyReport{
ID: report.GeneratePolicyReportID("polr-test", "test"),
Name: "polr-test",
Namespace: "test",
Results: []report.Result{result1, result2},
Summary: report.Summary{Fail: 1, Pass: 1},
CreationTimestamp: time.Now(),
}
var creport = &report.PolicyReport{
ID: report.GeneratePolicyReportID("cpolr", ""),
Name: "cpolr",
Results: map[string]*report.Result{
cresult1.GetIdentifier(): cresult1,
cresult2.GetIdentifier(): cresult2,
},
Summary: &report.Summary{},
var creport = report.PolicyReport{
ID: report.GeneratePolicyReportID("cpolr", ""),
Name: "cpolr",
Results: []report.Result{cresult1, cresult2},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}

View file

@ -10,13 +10,13 @@ import (
// Client for a provided Target
type Client interface {
// Send the given Result to the configured Target
Send(result *report.Result)
Send(result report.Result)
// SkipExistingOnStartup skips already existing PolicyReportResults on startup
SkipExistingOnStartup() bool
// Name is a unique identifier for each Target
Name() string
// Validate is a result should send
Validate(result *report.Result) bool
Validate(result report.Result) bool
// MinimumPriority for a triggered Result to send to this target
MinimumPriority() string
// Sources of the Results which should send to this target, empty means all sources
@ -36,7 +36,7 @@ type Filter struct {
Sources []string
}
func (f *Filter) Validate(result *report.Result) bool {
func (f *Filter) Validate(result report.Result) bool {
if len(f.Sources) > 0 && !contains(result.Source, f.Sources) {
return false
}
@ -60,8 +60,8 @@ func (f *Filter) Validate(result *report.Result) bool {
return true
}
func (f *Filter) validateNamespaceRules(result *report.Result) bool {
if result.Resource != nil && len(f.Namespace.Include) > 0 {
func (f *Filter) validateNamespaceRules(result report.Result) bool {
if result.HasResource() && len(f.Namespace.Include) > 0 {
for _, ns := range f.Namespace.Include {
if wildcard.Match(ns, result.Resource.Namespace) {
return true
@ -69,7 +69,7 @@ func (f *Filter) validateNamespaceRules(result *report.Result) bool {
}
return false
} else if result.Resource != nil && len(f.Namespace.Exclude) > 0 {
} else if result.HasResource() && len(f.Namespace.Exclude) > 0 {
for _, ns := range f.Namespace.Exclude {
if wildcard.Match(ns, result.Resource.Namespace) {
return false
@ -80,7 +80,7 @@ func (f *Filter) validateNamespaceRules(result *report.Result) bool {
return true
}
func (f *Filter) validatePolicyRules(result *report.Result) bool {
func (f *Filter) validatePolicyRules(result report.Result) bool {
if len(f.Policy.Include) > 0 {
for _, ns := range f.Policy.Include {
if wildcard.Match(ns, result.Policy) {
@ -100,7 +100,7 @@ func (f *Filter) validatePolicyRules(result *report.Result) bool {
return true
}
func (f *Filter) validatePriorityRules(result *report.Result) bool {
func (f *Filter) validatePriorityRules(result report.Result) bool {
if len(f.Priority.Include) > 0 {
return contains(result.Priority.String(), f.Priority.Include)
} else if len(f.Priority.Exclude) > 0 && contains(result.Priority.String(), f.Priority.Exclude) {
@ -128,7 +128,7 @@ func (c *BaseClient) Sources() []string {
return c.filter.Sources
}
func (c *BaseClient) Validate(result *report.Result) bool {
func (c *BaseClient) Validate(result report.Result) bool {
return c.filter.Validate(result)
}

View file

@ -7,7 +7,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target"
)
var result = &report.Result{
var result = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -17,7 +17,7 @@ var result = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",

View file

@ -34,7 +34,7 @@ var colors = map[report.Priority]string{
report.ErrorPriority: "15158332",
}
func newPayload(result *report.Result) payload {
func newPayload(result report.Result) payload {
color := colors[result.Priority]
embedFields := make([]embedField, 0)
@ -89,7 +89,7 @@ type client struct {
client http.Client
}
func (d *client) Send(result *report.Result) {
func (d *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(d.Name(), "POST", d.webhook, newPayload(result))
if err != nil {
return

View file

@ -10,7 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/discord"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -21,7 +21,7 @@ var completeResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -31,7 +31,7 @@ var completeResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var minimalResult = &report.Result{
var minimalResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.CriticalPriority,

View file

@ -27,7 +27,7 @@ type client struct {
client http.Client
}
func (e *client) Send(result *report.Result) {
func (e *client) Send(result report.Result) {
var host string
switch e.rotation {
case None:

View file

@ -10,7 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/elasticsearch"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -21,7 +21,7 @@ var completeResult = &report.Result{
Category: "resources",
Source: "Kyverno",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",

View file

@ -49,7 +49,7 @@ func ProcessHTTPResponse(target string, resp *http.Response, err error) {
}
}
func NewJSONResult(r *report.Result) Result {
func NewJSONResult(r report.Result) Result {
return Result{
Message: r.Message,
Policy: r.Policy,

View file

@ -17,7 +17,7 @@ type client struct {
kinesis helper.AWSClient
}
func (c *client) Send(result *report.Result) {
func (c *client) Send(result report.Result) {
body := new(bytes.Buffer)
if err := json.NewEncoder(body).Encode(result); err != nil {

View file

@ -10,7 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/kinesis"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -19,7 +19,7 @@ var completeResult = &report.Result{
Severity: report.High,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",

View file

@ -23,7 +23,7 @@ type entry struct {
Line string `json:"line"`
}
func newLokiPayload(result *report.Result, customLabels map[string]string) payload {
func newLokiPayload(result report.Result, customLabels map[string]string) payload {
timestamp := time.Now()
if !result.Timestamp.IsZero() {
timestamp = result.Timestamp
@ -85,7 +85,7 @@ type client struct {
customLabels map[string]string
}
func (l *client) Send(result *report.Result) {
func (l *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(l.Name(), "POST", l.host, newLokiPayload(result, l.customLabels))
if err != nil {
return

View file

@ -13,7 +13,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/loki"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -24,7 +24,7 @@ var completeResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -34,7 +34,7 @@ var completeResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var minimalResult = &report.Result{
var minimalResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.WarningPriority,

View file

@ -18,7 +18,7 @@ type client struct {
prefix string
}
func (c *client) Send(result *report.Result) {
func (c *client) Send(result report.Result) {
body := new(bytes.Buffer)
if err := json.NewEncoder(body).Encode(result); err != nil {

View file

@ -10,7 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/s3"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -19,7 +19,7 @@ var completeResult = &report.Result{
Severity: report.High,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",

View file

@ -48,7 +48,7 @@ var colors = map[report.Priority]string{
report.ErrorPriority: "#e20b0b",
}
func (s *client) newPayload(result *report.Result) payload {
func (s *client) newPayload(result report.Result) payload {
p := payload{
Attachments: make([]attachment, 0, 1),
}
@ -174,7 +174,7 @@ func (s *client) newPayload(result *report.Result) payload {
return p
}
func (s *client) Send(result *report.Result) {
func (s *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(s.Name(), "POST", s.webhook, s.newPayload(result))
if err != nil {
return

View file

@ -10,7 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/slack"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -21,7 +21,7 @@ var completeResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -31,7 +31,7 @@ var completeResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var enforceResult = &report.Result{
var enforceResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "check-for-requests-and-limits",
@ -42,7 +42,7 @@ var enforceResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "",
Kind: "Pod",
Name: "nginx",
@ -52,7 +52,7 @@ var enforceResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var incompleteResult = &report.Result{
var incompleteResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "check-for-requests-and-limits",
@ -63,7 +63,7 @@ var incompleteResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Pod",
Name: "nginx",
@ -73,7 +73,7 @@ var incompleteResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var incompleteResult2 = &report.Result{
var incompleteResult2 = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "check-for-requests-and-limits",
@ -84,7 +84,7 @@ var incompleteResult2 = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "",
Kind: "Pod",
Name: "nginx",
@ -94,7 +94,7 @@ var incompleteResult2 = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var minimalResult = &report.Result{
var minimalResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.WarningPriority,

View file

@ -37,7 +37,7 @@ var colors = map[report.Priority]string{
report.ErrorPriority: "e20b0b",
}
func newPayload(result *report.Result) payload {
func newPayload(result report.Result) payload {
facts := make([]fact, 0)
facts = append(facts, fact{"Policy", result.Policy})
@ -103,7 +103,7 @@ type client struct {
client http.Client
}
func (s *client) Send(result *report.Result) {
func (s *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(s.Name(), "POST", s.webhook, newPayload(result))
if err != nil {
return

View file

@ -11,7 +11,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/teams"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -22,7 +22,7 @@ var completeResult = &report.Result{
Category: "resources",
Scored: true,
Source: "Kyverno",
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
@ -32,7 +32,7 @@ var completeResult = &report.Result{
Properties: map[string]string{"version": "1.2.0"},
}
var minimalErrorResult = &report.Result{
var minimalErrorResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.ErrorPriority,
@ -40,7 +40,7 @@ var minimalErrorResult = &report.Result{
Scored: true,
}
var minimalResult = &report.Result{
var minimalResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.CriticalPriority,
@ -48,7 +48,7 @@ var minimalResult = &report.Result{
Scored: true,
}
var minimalInfoResult = &report.Result{
var minimalInfoResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.InfoPriority,
@ -56,7 +56,7 @@ var minimalInfoResult = &report.Result{
Scored: true,
}
var minimalDebugResult = &report.Result{
var minimalDebugResult = report.Result{
Message: "validation error: label required. Rule app-label-required failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "app-label-requirement",
Priority: report.DebugPriority,

View file

@ -12,7 +12,7 @@ type client struct {
client http.Client
}
func (e *client) Send(result *report.Result) {
func (e *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(e.Name(), "POST", e.host, http.NewJSONResult(result))
if err != nil {
return

View file

@ -9,7 +9,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/ui"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -18,7 +18,7 @@ var completeResult = &report.Result{
Severity: report.High,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",

View file

@ -13,7 +13,7 @@ type client struct {
client http.Client
}
func (e *client) Send(result *report.Result) {
func (e *client) Send(result report.Result) {
req, err := http.CreateJSONRequest(e.Name(), "POST", e.host, http.NewJSONResult(result))
if err != nil {
return

View file

@ -11,7 +11,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/target/webhook"
)
var completeResult = &report.Result{
var completeResult = report.Result{
Message: "validation error: requests and limits required. Rule autogen-check-for-requests-and-limits failed at path /spec/template/spec/containers/0/resources/requests/",
Policy: "require-requests-and-limits-required",
Rule: "autogen-check-for-requests-and-limits",
@ -20,7 +20,7 @@ var completeResult = &report.Result{
Severity: report.High,
Category: "resources",
Scored: true,
Resource: &report.Resource{
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",