Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Policy Report API #251

Merged
merged 3 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions pkg/api/gzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package api
import (
"compress/gzip"
"io"
"io/ioutil"
"net/http"
"strings"
"sync"
)

var gzPool = sync.Pool{
New: func() interface{} {
w := gzip.NewWriter(ioutil.Discard)
w := gzip.NewWriter(io.Discard)
return w
},
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ func (s *httpServer) RegisterV1Handler(finder v1.PolicyReportFinder) {
s.mux.HandleFunc("/v1/namespaces", Gzip(v1.NamespaceListHandler(finder)))
s.mux.HandleFunc("/v1/rule-status-count", Gzip(v1.RuleStatusCountHandler(finder)))

s.mux.HandleFunc("/v1/policy-reports", Gzip(v1.PolicyReportListHandler(finder)))
s.mux.HandleFunc("/v1/cluster-policy-reports", Gzip(v1.ClusterPolicyReportListHandler(finder)))

s.mux.HandleFunc("/v1/namespaced-resources/policies", Gzip(v1.NamespacedResourcesPolicyListHandler(finder)))
s.mux.HandleFunc("/v1/namespaced-resources/rules", Gzip(v1.NamespacedResourcesRuleListHandler(finder)))
s.mux.HandleFunc("/v1/namespaced-resources/kinds", Gzip(v1.NamespacedResourcesKindListHandler(finder)))
Expand Down
8 changes: 8 additions & 0 deletions pkg/api/v1/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ type Pagination struct {
}

type PolicyReportFinder interface {
// FetchClusterPolicyReports by filter and pagination
FetchClusterPolicyReports(Filter, Pagination) ([]*PolicyReport, error)
// FetchPolicyReports by filter and pagination
FetchPolicyReports(Filter, Pagination) ([]*PolicyReport, error)
// CountClusterPolicyReports by filter
CountClusterPolicyReports(Filter) (int, error)
// CountPolicyReports by filter
CountPolicyReports(Filter) (int, error)
// FetchClusterPolicies from current PolicyReportResults
FetchClusterPolicies(Filter) ([]string, error)
// FetchClusterRules from current PolicyReportResults
Expand Down
32 changes: 26 additions & 6 deletions pkg/api/v1/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ func TargetsHandler(targets []target.Client) http.HandlerFunc {
}
}

// PolicyReportListHandler REST API
func PolicyReportListHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
filter := buildFilter(req)
count, _ := finder.CountPolicyReports(filter)
list, err := finder.FetchPolicyReports(filter, buildPaginatiomn(req, []string{"namespace", "name"}))
helper.SendJSONResponse(w, PolicyReportList{Items: list, Count: count}, err)
}
}

// PolicyReportListHandler REST API
func ClusterPolicyReportListHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
filter := buildFilter(req)
count, _ := finder.CountClusterPolicyReports(filter)
list, err := finder.FetchClusterPolicyReports(filter, buildPaginatiomn(req, []string{"namespace", "name"}))
helper.SendJSONResponse(w, PolicyReportList{Items: list, Count: count}, err)
}
}

// ClusterResourcesPolicyListHandler REST API
func ClusterResourcesPolicyListHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
Expand All @@ -47,7 +67,7 @@ func NamespacedResourcesPolicyListHandler(finder PolicyReportFinder) http.Handle
}
}

// NamespacedResourcesPolicyListHandler REST API
// NamespacedResourcesRuleListHandler REST API
func NamespacedResourcesRuleListHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
list, err := finder.FetchNamespacedRules(buildFilter(req))
Expand Down Expand Up @@ -158,8 +178,8 @@ func RuleStatusCountHandler(finder PolicyReportFinder) http.HandlerFunc {
func NamespacedResourcesResultHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
filter := buildFilter(req)
count, err := finder.CountNamespacedResults(filter)
list, err := finder.FetchNamespacedResults(filter, buildPaginatiomn(req))
count, _ := finder.CountNamespacedResults(filter)
list, err := finder.FetchNamespacedResults(filter, buildPaginatiomn(req, defaultOrder))
helper.SendJSONResponse(w, ResultList{Items: list, Count: count}, err)
}
}
Expand All @@ -168,8 +188,8 @@ func NamespacedResourcesResultHandler(finder PolicyReportFinder) http.HandlerFun
func ClusterResourcesResultHandler(finder PolicyReportFinder) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
filter := buildFilter(req)
count, err := finder.CountClusterResults(filter)
list, err := finder.FetchClusterResults(filter, buildPaginatiomn(req))
count, _ := finder.CountClusterResults(filter)
list, err := finder.FetchClusterResults(filter, buildPaginatiomn(req, defaultOrder))
helper.SendJSONResponse(w, ResultList{Items: list, Count: count}, err)
}
}
Expand All @@ -187,7 +207,7 @@ func NamespaceListHandler(finder PolicyReportFinder) http.HandlerFunc {
}
}

func buildPaginatiomn(req *http.Request) Pagination {
func buildPaginatiomn(req *http.Request, defaultOrder []string) Pagination {
page, err := strconv.Atoi(req.URL.Query().Get("page"))
if err != nil || page < 1 {
page = 0
Expand Down
40 changes: 40 additions & 0 deletions pkg/api/v1/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,46 @@ func Test_V1_API(t *testing.T) {
t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
}
})

t.Run("PolicyReportListHandler", func(t *testing.T) {
req, err := http.NewRequest("GET", "/v1/policy-reports?namespaces=test&labels=app:policy-reporter", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
handler := v1.PolicyReportListHandler(store)
handler.ServeHTTP(rr, req)

if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}

expected := `{"items":[{"id":"7605991845421273693","name":"polr-test","namespace":"test","labels":{"app":"policy-reporter","scope":"namespace"},"pass":0,"skip":0,"warn":0,"error":0,"fail":1}],"count":1}`
if !strings.Contains(rr.Body.String(), expected) {
t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
}
})

t.Run("ClusterPolicyReportListHandler", func(t *testing.T) {
req, err := http.NewRequest("GET", "/v1/policy-reports?labels=app:policy-reporter", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
handler := v1.ClusterPolicyReportListHandler(store)
handler.ServeHTTP(rr, req)

if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}

expected := `{"items":[{"id":"7174304213499286261","name":"cpolr","labels":{"app":"policy-reporter","scope":"cluster"},"pass":0,"skip":0,"warn":0,"error":0,"fail":0}],"count":1}`
if !strings.Contains(rr.Body.String(), expected) {
t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
}
})
}

func Test_TargetsAPI(t *testing.T) {
Expand Down
17 changes: 17 additions & 0 deletions pkg/api/v1/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ import (
"github.com/kyverno/policy-reporter/pkg/target"
)

type PolicyReport struct {
ID string `json:"id"`
Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
Labels map[string]string `json:"labels"`
Pass int `json:"pass"`
Skip int `json:"skip"`
Warn int `json:"warn"`
Error int `json:"error"`
Fail int `json:"fail"`
}

type PolicyReportList struct {
Items []*PolicyReport `json:"items"`
Count int `json:"count"`
}

type ResultList struct {
Items []*ListResult `json:"items"`
Count int `json:"count"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/crd/client/informers/externalversions/generic.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/kubernetes/policy_report_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (k *k8sPolicyReportClient) configureClusterPolicyReport() cache.SharedIndex
return cpolrInformer
}

// NewPolicyReportAdapter new Adapter for Policy Report Kubernetes API
// NewPolicyReportClient new Client for Policy Report Kubernetes API
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()
Expand Down
4 changes: 2 additions & 2 deletions pkg/kubernetes/secrets/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ type k8sClient struct {

func (c *k8sClient) Get(ctx context.Context, name string) (Values, error) {
secret, err := c.client.Get(ctx, name, metav1.GetOptions{})
values := Values{}
if err != nil {
return Values{}, err
return values, err
}

values := Values{}
if host, ok := secret.Data["host"]; ok {
values.Host = string(host)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/report/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type PolicyReportResultListener = func(PolicyReport, Result, bool)

// PolicyReportClient watches for PolicyReport Events and executes registered callback
type PolicyReportClient interface {
// WatchPolicyReports starts to watch for PolicyReport LifecycleEvent events
// Run WatchPolicyReports starts to watch for PolicyReport LifecycleEvent events
Run(stopper chan struct{}) error
// HasSynced the configured PolicyReport
HasSynced() bool
Expand Down
2 changes: 1 addition & 1 deletion pkg/report/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type EventPublisher interface {
UnregisterListener(string)
// GetListener returns a list of all registered Listeners
GetListener() map[string]PolicyReportListener
// Process LifecycleEvent with all registered listeners
// Publish Process LifecycleEvent with all registered listeners
Publish(event LifecycleEvent)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/report/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type PolicyReportStore interface {
Get(id string) (PolicyReport, bool)
// Add a PolicyReport to the Store
Add(r PolicyReport) error
// Add a PolicyReport to the Store
// Update a PolicyReport to the Store
Update(r PolicyReport) error
// Remove a PolicyReport with the given Type and ID from the Store
Remove(id string) error
Expand Down
Loading