mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-05 07:26:55 +00:00
NK-23: Implemented logging to the policy object/status.
Refactored MutationWebhook, modified controller logs.
This commit is contained in:
parent
9d5f77a941
commit
0a939e44dc
4 changed files with 74 additions and 20 deletions
|
@ -6,12 +6,14 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
clientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
|
||||
policies "github.com/nirmata/kube-policy/pkg/client/clientset/versioned/typed/policy/v1alpha1"
|
||||
informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
|
||||
lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
|
||||
)
|
||||
|
@ -20,6 +22,7 @@ import (
|
|||
type PolicyController struct {
|
||||
policyInformerFactory informers.SharedInformerFactory
|
||||
policyLister lister.PolicyLister
|
||||
policiesInterface policies.PolicyInterface
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
|
@ -44,6 +47,7 @@ func NewPolicyController(config *rest.Config, logger *log.Logger) (*PolicyContro
|
|||
controller := &PolicyController{
|
||||
policyInformerFactory: policyInformerFactory,
|
||||
policyLister: policyInformer.Lister(),
|
||||
policiesInterface: policyClientset.NirmataV1alpha1().Policies("default"),
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
|
@ -81,26 +85,65 @@ func (c *PolicyController) GetPolicies() []types.Policy {
|
|||
return policies
|
||||
}
|
||||
|
||||
func (c *PolicyController) LogPolicyError(name, text string) {
|
||||
c.addPolicyLog(name, "[ERROR] "+text)
|
||||
}
|
||||
|
||||
func (c *PolicyController) LogPolicyInfo(name, text string) {
|
||||
c.addPolicyLog(name, "[ INFO] "+text)
|
||||
}
|
||||
|
||||
const policyLogMaxRecords int = 10
|
||||
|
||||
// Appends given log text to the status/logs array.
|
||||
func (c *PolicyController) addPolicyLog(name, text string) {
|
||||
getOptions := metav1.GetOptions{
|
||||
ResourceVersion: "1",
|
||||
IncludeUninitialized: true,
|
||||
}
|
||||
policy, err := c.policiesInterface.Get(name, getOptions)
|
||||
if err != nil {
|
||||
c.logger.Printf("Unable to get policy %s: %s", name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Add new log record
|
||||
text = time.Now().Format("2006 Jan 02 15:04:05.999 ") + text
|
||||
policy.Status.Logs = append(policy.Status.Logs, text)
|
||||
// Pop front extra log records
|
||||
logsCount := len(policy.Status.Logs)
|
||||
if logsCount > policyLogMaxRecords {
|
||||
policy.Status.Logs = policy.Status.Logs[logsCount-policyLogMaxRecords:]
|
||||
}
|
||||
// Save logs to policy object
|
||||
_, err = c.policiesInterface.UpdateStatus(policy)
|
||||
if err != nil {
|
||||
c.logger.Printf("Unable to update logs for policy %s: %s", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PolicyController) createPolicyHandler(resource interface{}) {
|
||||
key := c.getResourceKey(resource)
|
||||
c.logger.Printf("Created policy: %s\n", key)
|
||||
c.logger.Printf("Policy created: %s", key)
|
||||
c.addPolicyLog(key, "Added")
|
||||
}
|
||||
|
||||
func (c *PolicyController) updatePolicyHandler(oldResource, newResource interface{}) {
|
||||
oldKey := c.getResourceKey(oldResource)
|
||||
newKey := c.getResourceKey(newResource)
|
||||
|
||||
c.logger.Printf("Updated policy from %s to %s\n", oldKey, newKey)
|
||||
c.logger.Printf("Policy %s updated to %s", oldKey, newKey)
|
||||
c.addPolicyLog(newKey, "Updated")
|
||||
}
|
||||
|
||||
func (c *PolicyController) deletePolicyHandler(resource interface{}) {
|
||||
key := c.getResourceKey(resource)
|
||||
c.logger.Printf("Deleted policy: %s\n", key)
|
||||
c.logger.Printf("Policy deleted: %s", key)
|
||||
}
|
||||
|
||||
func (c *PolicyController) getResourceKey(resource interface{}) string {
|
||||
if key, err := cache.MetaNamespaceKeyFunc(resource); err != nil {
|
||||
c.logger.Fatalf("Error retrieving policy key: %v\n", err)
|
||||
c.logger.Fatalf("Error retrieving policy key: %v", err)
|
||||
} else {
|
||||
return key
|
||||
}
|
||||
|
|
|
@ -54,15 +54,14 @@ func NewWebhookServer(config WebhookServerConfig, logger *log.Logger) (*WebhookS
|
|||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{pair}
|
||||
|
||||
mw, err := webhooks.NewMutationWebhook(logger, config.Kubeclient)
|
||||
mw, err := webhooks.NewMutationWebhook(config.Kubeclient, config.Controller, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ws := &WebhookServer{
|
||||
logger: logger,
|
||||
policyController: config.Controller,
|
||||
mutationWebhook: mw,
|
||||
logger: logger,
|
||||
mutationWebhook: mw,
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
@ -89,7 +88,7 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var admissionResponse *v1beta1.AdmissionResponse
|
||||
if webhooks.AdmissionIsRequired(admissionReview.Request) {
|
||||
admissionResponse = ws.mutationWebhook.Mutate(admissionReview.Request, ws.policyController.GetPolicies())
|
||||
admissionResponse = ws.mutationWebhook.Mutate(admissionReview.Request)
|
||||
}
|
||||
|
||||
if admissionResponse == nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
controller "github.com/nirmata/kube-policy/controller"
|
||||
kubeclient "github.com/nirmata/kube-policy/kubeclient"
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
|
@ -15,24 +16,26 @@ import (
|
|||
// MutationWebhook is a data type that represents
|
||||
// buisness logic for resource mutation
|
||||
type MutationWebhook struct {
|
||||
logger *log.Logger
|
||||
kubeclient *kubeclient.KubeClient
|
||||
controller *controller.PolicyController
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewMutationWebhook is a method that returns new instance
|
||||
// of MutationWebhook struct
|
||||
func NewMutationWebhook(logger *log.Logger, kubeclient *kubeclient.KubeClient) (*MutationWebhook, error) {
|
||||
if logger == nil {
|
||||
return nil, errors.New("Logger and/or KubeClient is not set")
|
||||
func NewMutationWebhook(kubeclient *kubeclient.KubeClient, controller *controller.PolicyController, logger *log.Logger) (*MutationWebhook, error) {
|
||||
if kubeclient == nil || controller == nil || logger == nil {
|
||||
return nil, errors.New("Some parameters are not set")
|
||||
}
|
||||
return &MutationWebhook{logger: logger, kubeclient: kubeclient}, nil
|
||||
return &MutationWebhook{kubeclient: kubeclient, controller: controller, logger: logger}, nil
|
||||
}
|
||||
|
||||
// Mutate applies admission to request
|
||||
func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest, policies []types.Policy) *v1beta1.AdmissionResponse {
|
||||
func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
mw.logger.Printf("AdmissionReview for Kind=%v, Namespace=%v Name=%v UID=%v patchOperation=%v UserInfo=%v",
|
||||
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation, request.UserInfo)
|
||||
|
||||
policies := mw.controller.GetPolicies()
|
||||
if len(policies) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -52,13 +55,18 @@ func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest, policies []
|
|||
}
|
||||
|
||||
if IsRuleApplicableToRequest(rule.Resource, request) {
|
||||
mw.logger.Printf("Applying policy %s, rule index = %d", policy.ObjectMeta.Name, ruleIdx)
|
||||
mw.logger.Printf("Applying policy %s, rule #%d", policy.ObjectMeta.Name, ruleIdx)
|
||||
rulePatches, err := mw.applyRule(request, rule, stopOnError)
|
||||
// If at least one error is detected in the rule, the entire rule will not be applied:
|
||||
// it can be changed in the future by varying the policy.Spec.FailurePolicy values.
|
||||
if err != nil && stopOnError {
|
||||
mw.logger.Printf("/!\\ Denying the request according to FailurePolicy spec /!\\")
|
||||
return errorToResponse(err, false)
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Unable to apply rule #%d: %s", ruleIdx, err)
|
||||
mw.logger.Print(errStr)
|
||||
mw.controller.LogPolicyError(policy.Name, errStr)
|
||||
if stopOnError {
|
||||
mw.logger.Printf("/!\\ Denying the request according to FailurePolicy spec /!\\")
|
||||
}
|
||||
return errorToResponse(err, !stopOnError)
|
||||
}
|
||||
if rulePatches != nil {
|
||||
allPatches = append(allPatches, rulePatches...)
|
||||
|
@ -151,6 +159,10 @@ func (mw *MutationWebhook) applyConfigGenerator(generator *types.PolicyConfigGen
|
|||
// SerializePatches converts JSON patches to byte array
|
||||
func SerializePatches(patches []types.PolicyPatch) ([]byte, error) {
|
||||
var result []byte
|
||||
if len(patches) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result = append(result, []byte("[\n")...)
|
||||
for index, patch := range patches {
|
||||
if patch.Operation == "" || patch.Path == "" {
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestSerializePatches_Empty(t *testing.T) {
|
|||
var patches []types.PolicyPatch
|
||||
bytes, err := webhooks.SerializePatches(patches)
|
||||
assertEq(t, nil, err)
|
||||
assertEqStringAndData(t, "[\n\n]", bytes)
|
||||
assertEq(t, 0, len(bytes))
|
||||
}
|
||||
|
||||
func TestSerializePatches_SingleValid(t *testing.T) {
|
||||
|
|
Loading…
Add table
Reference in a new issue