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

Update liveness probe (#53)

* Update liveness probe
This commit is contained in:
Frank Jogeleit 2021-08-09 20:53:04 +02:00 committed by GitHub
parent 33ccfbb3db
commit c1b5dd549f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 124 additions and 100 deletions

View file

@ -1,5 +1,13 @@
# Changelog
# 1.8.6
* Update Policy Reporter UI to 0.13.1
* Hide Rule Chips if rule name is empty
* Update Policy Reporter Kyvern Plugin to 0.3.2
* Improved LivenessProbe, checks now if Kyverno CRDs are available
* Update Policy Reporter to 1.8.4
* Improved LivenessProbe, checks now if any PolicyReport CRD is available
# 1.8.5
* Added trusted root CA's [#52](https://github.com/kyverno/policy-reporter/pull/52) by [frezbo](https://github.com/frezbo)

View file

@ -1,7 +1,7 @@
GO ?= go
BUILD ?= build
REPO ?= fjogeleit/policy-reporter
IMAGE_TAG ?= 1.8.3
IMAGE_TAG ?= 1.8.4
LD_FLAGS="-s -w"
all: build

View file

@ -4,9 +4,9 @@ dependencies:
version: 1.4.0
- name: ui
repository: ""
version: 1.8.3
version: 1.8.4
- name: kyvernoPlugin
repository: ""
version: 0.5.1
digest: sha256:0ef6012a60a7bd73488830f8b466172c27de8f4628e3ff2e3ff3615411c71e7a
generated: "2021-07-06T18:15:23.735281+02:00"
version: 0.5.2
digest: sha256:685d62ebe8f290e74785bf444a072aa839087822aabeb8e91caa4816915bafe5
generated: "2021-08-09T20:16:57.768228+02:00"

View file

@ -5,8 +5,8 @@ description: |
It creates Prometheus Metrics and can send rule validation events to different targets like Loki, Elasticsearch, Slack or Discord
type: application
version: 1.8.5
appVersion: 1.8.3
version: 1.8.6
appVersion: 1.8.4
dependencies:
- name: monitoring
@ -16,8 +16,8 @@ dependencies:
- name: ui
condition: ui.enabled
repository: ""
version: "1.8.3"
version: "1.8.4"
- name: kyvernoPlugin
condition: kyvernoPlugin.enabled
repository: ""
version: "0.5.1"
version: "0.5.2"

View file

@ -3,5 +3,5 @@ name: kyvernoPlugin
description: Policy Reporter Kyverno Plugin
type: application
version: 0.5.1
appVersion: 0.3.1
version: 0.5.2
appVersion: 0.3.2

View file

@ -1,7 +1,7 @@
image:
repository: fjogeleit/policy-reporter-kyverno-plugin
pullPolicy: IfNotPresent
tag: 0.3.1
tag: 0.3.2
imagePullSecrets: []

View file

@ -3,5 +3,5 @@ name: ui
description: Policy Reporter UI
type: application
version: 1.8.3
appVersion: 0.13.0
version: 1.8.4
appVersion: 0.13.1

View file

@ -10,7 +10,7 @@ plugins:
image:
repository: fjogeleit/policy-reporter-ui
pullPolicy: IfNotPresent
tag: 0.13.0
tag: 0.13.1
imagePullSecrets: []

View file

@ -1,7 +1,7 @@
image:
repository: fjogeleit/policy-reporter
pullPolicy: IfNotPresent
tag: 1.8.3
tag: 1.8.4
imagePullSecrets: []

View file

@ -66,10 +66,10 @@ func newRunCMD() *cobra.Command {
errorChan := make(chan error)
go func() { errorChan <- resolver.APIServer().Start() }()
go func() { errorChan <- client.StartWatching() }()
go func() { errorChan <- resolver.APIServer().Start() }()
go func() {
http.Handle("/metrics", promhttp.Handler())

View file

@ -97,7 +97,7 @@ spec:
automountServiceAccountToken: false
containers:
- name: ui
image: "fjogeleit/policy-reporter-ui:0.12.0"
image: "fjogeleit/policy-reporter-ui:0.13.1"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
@ -148,7 +148,7 @@ spec:
automountServiceAccountToken: true
containers:
- name: policy-reporter
image: "fjogeleit/policy-reporter:1.8.3"
image: "fjogeleit/policy-reporter:1.8.4"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -165,7 +165,7 @@ spec:
automountServiceAccountToken: true
containers:
- name: "kyverno-plugin"
image: "fjogeleit/policy-reporter-kyverno-plugin:0.3.1"
image: "fjogeleit/policy-reporter-kyverno-plugin:0.3.2"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
@ -215,7 +215,7 @@ spec:
spec:
containers:
- name: ui
image: "fjogeleit/policy-reporter-ui:0.12.0"
image: "fjogeleit/policy-reporter-ui:0.13.1"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
@ -266,7 +266,7 @@ spec:
automountServiceAccountToken: true
containers:
- name: policy-reporter
image: "fjogeleit/policy-reporter:1.8.3"
image: "fjogeleit/policy-reporter:1.8.4"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -84,7 +84,7 @@ spec:
automountServiceAccountToken: true
containers:
- name: policy-reporter
image: "fjogeleit/policy-reporter:1.8.3"
image: "fjogeleit/policy-reporter:1.8.4"
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false

View file

@ -3,28 +3,22 @@ package api
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/kyverno/policy-reporter/pkg/report"
)
// HealthzHandler for the Halthz REST API
func HealthzHandler() http.HandlerFunc {
func HealthzHandler(found map[string]string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")
}
}
// ReadyHandler for the Halthz REST API
func ReadyHandler(s *report.PolicyReportStore) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if len(s.List(report.PolicyReportType))+len(s.List(report.ClusterPolicyReportType)) == 0 {
if len(found) == 0 {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, "{}")
log.Println("[ERROR] No PolicyReport CRDs found")
fmt.Fprint(w, `{ "error": "No PolicyReport CRDs found" }`)
return
}
@ -36,6 +30,15 @@ func ReadyHandler(s *report.PolicyReportStore) http.HandlerFunc {
}
}
// ReadyHandler for the Halthz REST API
func ReadyHandler() http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")
}
}
// PolicyReportHandler for the PolicyReport REST API
func PolicyReportHandler(s *report.PolicyReportStore) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {

View file

@ -204,7 +204,7 @@ func Test_HealthzAPI(t *testing.T) {
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(api.HealthzHandler())
handler := http.HandlerFunc(api.HealthzHandler(map[string]string{"wgpolicyk8s.io/v1alpha2": "wgpolicyk8s.io/v1alpha2"}))
handler.ServeHTTP(rr, req)
@ -212,6 +212,22 @@ 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) {
req, err := http.NewRequest("GET", "/healthz", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(api.HealthzHandler(map[string]string{}))
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)
}
})
}
func Test_ReadyAPI(t *testing.T) {
@ -221,36 +237,8 @@ func Test_ReadyAPI(t *testing.T) {
t.Fatal(err)
}
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",
Priority: report.ErrorPriority,
Status: report.Fail,
Category: "resources",
Scored: true,
Resource: report.Resource{
APIVersion: "v1",
Kind: "Deployment",
Name: "nginx",
Namespace: "test",
UID: "536ab69f-1b3c-4bd9-9ba4-274a56188409",
},
}
preport := report.PolicyReport{
Name: "polr-test",
Namespace: "test",
Results: map[string]report.Result{"": result},
Summary: report.Summary{},
CreationTimestamp: time.Now(),
}
store := report.NewPolicyReportStore()
store.Add(preport)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(api.ReadyHandler(store))
handler := http.HandlerFunc(api.ReadyHandler())
handler.ServeHTTP(rr, req)
@ -258,22 +246,4 @@ func Test_ReadyAPI(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) {
req, err := http.NewRequest("GET", "/ready", nil)
if err != nil {
t.Fatal(err)
}
store := report.NewPolicyReportStore()
rr := httptest.NewRecorder()
handler := http.HandlerFunc(api.ReadyHandler(store))
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

@ -19,14 +19,15 @@ type httpServer struct {
mux *http.ServeMux
store *report.PolicyReportStore
targets []Target
foundResources map[string]string
}
func (s *httpServer) registerHandler() {
s.mux.HandleFunc("/policy-reports", Gzip(PolicyReportHandler(s.store)))
s.mux.HandleFunc("/cluster-policy-reports", Gzip(ClusterPolicyReportHandler(s.store)))
s.mux.HandleFunc("/targets", Gzip(TargetsHandler(s.targets)))
s.mux.HandleFunc("/healthz", HealthzHandler())
s.mux.HandleFunc("/ready", ReadyHandler(s.store))
s.mux.HandleFunc("/healthz", HealthzHandler(s.foundResources))
s.mux.HandleFunc("/ready", ReadyHandler())
}
func (s *httpServer) Start() error {
@ -39,7 +40,7 @@ func (s *httpServer) Start() error {
}
// NewServer constructor for a new API Server
func NewServer(store *report.PolicyReportStore, targets []target.Client, port int) Server {
func NewServer(store *report.PolicyReportStore, targets []target.Client, port int, foundResources map[string]string) Server {
apiTargets := make([]Target, 0, len(targets))
for _, t := range targets {
apiTargets = append(apiTargets, mapTarget(t))
@ -50,6 +51,7 @@ func NewServer(store *report.PolicyReportStore, targets []target.Client, port in
targets: apiTargets,
store: store,
mux: http.NewServeMux(),
foundResources: foundResources,
}
s.registerHandler()

View file

@ -19,6 +19,7 @@ func Test_NewServer(t *testing.T) {
discord.NewClient("http://webhook:2000", "", false, &http.Client{}),
},
8080,
make(map[string]string),
)
go server.Start()

View file

@ -27,6 +27,7 @@ type Resolver struct {
config *Config
k8sConfig *rest.Config
mapper kubernetes.Mapper
policyAdapter kubernetes.PolicyReportAdapter
policyStore *report.PolicyReportStore
policyClient report.PolicyResultClient
lokiClient target.Client
@ -40,10 +41,18 @@ type Resolver struct {
// APIServer resolver method
func (r *Resolver) APIServer() api.Server {
foundResources := make(map[string]string, 0)
client := r.policyClient
if client != nil {
foundResources = client.GetFoundResources()
}
return api.NewServer(
r.PolicyReportStore(),
r.TargetClients(),
r.config.API.Port,
foundResources,
)
}
@ -305,6 +314,10 @@ func (r *Resolver) configMapAPI() (kubernetes.ConfigMapAdapter, error) {
}
func (r *Resolver) policyReportAPI(ctx context.Context) (kubernetes.PolicyReportAdapter, error) {
if r.policyAdapter != nil {
return r.policyAdapter, nil
}
client, err := dynamic.NewForConfig(r.k8sConfig)
if err != nil {
return nil, err
@ -314,7 +327,9 @@ func (r *Resolver) policyReportAPI(ctx context.Context) (kubernetes.PolicyReport
return nil, err
}
return kubernetes.NewPolicyReportAdapter(client, mapper), nil
r.policyAdapter = kubernetes.NewPolicyReportAdapter(client, mapper)
return r.policyAdapter, nil
}
// ResultCache resolver method

View file

@ -30,6 +30,10 @@ func (c *policyReportClient) RegisterPolicyResultCallback(cb report.PolicyResult
c.resultCallbacks = append(c.resultCallbacks, cb)
}
func (c *policyReportClient) GetFoundResources() map[string]string {
return c.policyAPI.GetFoundResources()
}
func (c *policyReportClient) StartWatching() error {
if c.started {
return errors.New("StartWatching was already started")

View file

@ -3,6 +3,7 @@ package kubernetes
import (
"context"
"log"
"sync"
"github.com/kyverno/policy-reporter/pkg/report"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -45,13 +46,18 @@ type WatchEvent struct {
// PolicyReportAdapter translates API responses to an internal struct
type PolicyReportAdapter interface {
WatchPolicyReports() (chan WatchEvent, error)
GetFoundResources() map[string]string
}
type k8sPolicyReportAdapter struct {
client dynamic.Interface
policyReports schema.GroupVersionResource
clusterPolicyReports schema.GroupVersionResource
found map[string]string
mapper Mapper
mx *sync.Mutex
}
func (k *k8sPolicyReportAdapter) GetFoundResources() map[string]string {
return k.found
}
func (k *k8sPolicyReportAdapter) WatchPolicyReports() (chan WatchEvent, error) {
@ -70,9 +76,16 @@ func (k *k8sPolicyReportAdapter) WatchPolicyReports() (chan WatchEvent, error) {
w, err := k.client.Resource(r).Watch(context.Background(), metav1.ListOptions{})
if err != nil {
log.Printf("[INFO] Resource not Found: %s\n", r.String())
k.mx.Lock()
delete(k.found, r.String())
k.mx.Unlock()
return
}
k.mx.Lock()
k.found[r.String()] = r.String()
k.mx.Unlock()
for result := range w.ResultChan() {
if item, ok := result.Object.(*unstructured.Unstructured); ok {
report := k.mapper.MapPolicyReport(item.Object)
@ -91,5 +104,7 @@ func NewPolicyReportAdapter(dynamic dynamic.Interface, mapper Mapper) PolicyRepo
return &k8sPolicyReportAdapter{
client: dynamic,
mapper: mapper,
mx: &sync.Mutex{},
found: make(map[string]string),
}
}

View file

@ -22,6 +22,10 @@ type fakeClient struct {
mapper kubernetes.Mapper
}
func (f *fakeClient) GetFoundResources() map[string]string {
return make(map[string]string)
}
func (f *fakeClient) ListPolicyReports() ([]report.PolicyReport, error) {
return f.List, f.Error
}

View file

@ -20,4 +20,6 @@ type PolicyResultClient interface {
RegisterPolicyResultWatcher(skipExisting bool)
// StartWatching calls the WatchAPI, waiting for incoming PolicyReport watch.Events and call the registered Handlers
StartWatching() error
// GetFoundResources as Map of Names
GetFoundResources() map[string]string
}