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

feat: evaluation_metrics 2 #2678

Closed
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
19 changes: 19 additions & 0 deletions pkg/audit/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ var (
auditMatchKindOnly = flag.Bool("audit-match-kind-only", false, "only use kinds specified in all constraints for auditing cluster resources. if kind is not specified in any of the constraints, it will audit all resources (same as setting this flag to false)")
apiCacheDir = flag.String("api-cache-dir", defaultAPICacheDir, "The directory where audit from api server cache are stored, defaults to /tmp/audit")
emptyAuditResults []updateListEntry
logStatsAudit = flag.Bool("log-stats-audit", false, "(alpha) log stats metrics for the audit run")
)

// Manager allows us to audit resources periodically.
Expand Down Expand Up @@ -491,6 +492,15 @@ func (am *Manager) auditFromCache(ctx context.Context) ([]Result, []error) {
continue
}

if *logStatsAudit {
logging.LogStatsEntries(
am.opa,
log.WithValues(logging.Process, "audit"),
resp.StatsEntries,
"audit from cache review request stats",
)
}

for _, r := range resp.Results() {
results = append(results, Result{
Result: r,
Expand Down Expand Up @@ -600,6 +610,15 @@ func (am *Manager) reviewObjects(ctx context.Context, kind string, folderCount i
}

if len(resp.Results()) > 0 {
if *logStatsAudit {
logging.LogStatsEntries(
am.opa,
log.WithValues(logging.Process, "audit"),
resp.StatsEntries,
"audit review request stats",
)
}

results := ToResults(&augmentedObj.Object, resp)
err = am.addAuditResponsesToUpdateLists(updateLists, results, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions pkg/logging/logging.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package logging

import (
"github.com/go-logr/logr"
"github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
)

// Log keys.
const (
Process = "process"
Expand Down Expand Up @@ -27,3 +33,30 @@ const (
Mutator = "mutator"
DebugLevel = 2 // r.log.Debug(foo) == r.log.V(logging.DebugLevel).Info(foo)
)

func LogStatsEntries(client *client.Client, logger logr.Logger, entries []*instrumentation.StatsEntry, msg string) {
for _, se := range entries {
labelledLogger := logger
for _, label := range se.Labels {
labelledLogger = labelledLogger.WithValues(label.Name, label.Value)
}

for _, stat := range se.Stats {
labelledLogger = labelledLogger.WithValues(
"scope", se.Scope,
"statsFor", se.StatsFor,
"source_type", stat.Source.Type,
"source_value", stat.Source.Value,
"name", stat.Name,
"value", stat.Value,
)

if client != nil {
desc := client.GetDescriptionForStat(stat.Source, stat.Name)
labelledLogger = labelledLogger.WithValues("description", desc)
}

labelledLogger.Info(msg)
}
}
}
52 changes: 52 additions & 0 deletions pkg/logging/logging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package logging

import (
"bytes"
"testing"

constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
"github.com/stretchr/testify/require"
"k8s.io/klog/v2"
)

func Test_LogStatsEntries(t *testing.T) {
testLogger := klog.NewKlogr()
testBuf := bytes.NewBuffer(nil)

klog.SetOutput(testBuf)
klog.LogToStderr(false)

LogStatsEntries(
&constraintclient.Client{},
testLogger,
[]*instrumentation.StatsEntry{
{
Scope: "someScope",
StatsFor: "someConstranint",
Stats: []*instrumentation.Stat{
{
Name: "someStat",
Value: "someValue",
Source: instrumentation.Source{
Type: "someType",
Value: "someValue",
},
},
},
Labels: []*instrumentation.Label{
{
Name: "someLabel",
Value: "someLabelValue",
},
},
},
},
"test message",
)

require.Contains(t, testBuf.String(), "\"test message\" someLabel=\"someLabelValue\" "+
"scope=\"someScope\" statsFor=\"someConstranint\" source_type=\"someType\" "+
"source_value=\"someValue\" name=\"someStat\" value=\"someValue\" description=\"unknown description\"",
)
}
1 change: 1 addition & 0 deletions pkg/webhook/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var (
logDenies = flag.Bool("log-denies", false, "log detailed info on each deny")
emitAdmissionEvents = flag.Bool("emit-admission-events", false, "(alpha) emit Kubernetes events for each admission violation")
admissionEventsInvolvedNamespace = flag.Bool("admission-events-involved-namespace", false, "emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will still follow the default behavior")
logStatsAdmission = flag.Bool("log-stats-admission", false, "(alpha) log stats for admission webhook")
tlsMinVersion = flag.String("tls-min-version", "1.3", "minimum version of TLS supported")
serviceaccount = fmt.Sprintf("system:serviceaccount:%s:%s", util.GetNamespace(), serviceAccountName)
clientCAName = flag.String("client-ca-name", "", "name of the certificate authority bundle to authenticate the Kubernetes API server requests against")
Expand Down
16 changes: 16 additions & 0 deletions pkg/webhook/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ func (h *validationHandler) Handle(ctx context.Context, req admission.Request) a
return admission.Errored(http.StatusInternalServerError, err)
}

if *logStatsAdmission {
logging.LogStatsEntries(
h.opa,
log.WithValues(
logging.Process, "admission",
logging.EventType, "review_response_stats",
logging.ResourceGroup, req.AdmissionRequest.Kind.Group,
logging.ResourceAPIVersion, req.AdmissionRequest.Kind.Version,
logging.ResourceKind, req.AdmissionRequest.Kind.Kind,
logging.ResourceNamespace, req.AdmissionRequest.Namespace,
logging.RequestUsername, req.AdmissionRequest.UserInfo.Username,
),
resp.StatsEntries, "admission review request stats",
)
}

res := resp.Results()
denyMsgs, warnMsgs := h.getValidationMessages(res, &req)

Expand Down