1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-07 00:17:13 +00:00
kyverno/pkg/violation/builder.go
2019-05-06 12:08:31 -07:00

138 lines
3.8 KiB
Go

package violation
import (
"encoding/json"
"fmt"
"log"
jsonpatch "github.com/evanphx/json-patch"
controllerinternalinterfaces "github.com/nirmata/kube-policy/controller/internalinterfaces"
kubeClient "github.com/nirmata/kube-policy/kubeclient"
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
"github.com/nirmata/kube-policy/pkg/event/internalinterfaces"
eventinternalinterfaces "github.com/nirmata/kube-policy/pkg/event/internalinterfaces"
eventutils "github.com/nirmata/kube-policy/pkg/event/utils"
violationinternalinterfaces "github.com/nirmata/kube-policy/pkg/violation/internalinterfaces"
utils "github.com/nirmata/kube-policy/pkg/violation/utils"
mergetypes "k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
type builder struct {
kubeClient *kubeClient.KubeClient
controller controllerinternalinterfaces.PolicyGetter
eventBuilder eventinternalinterfaces.BuilderInternal
logger *log.Logger
}
type Builder interface {
violationinternalinterfaces.ViolationGenerator
ProcessViolation(info utils.ViolationInfo) error
Patch(policy *types.Policy, updatedPolicy *types.Policy) error
IsActive(kind string, resource string) (bool, error)
}
func NewViolationBuilder(
kubeClient *kubeClient.KubeClient,
eventBuilder internalinterfaces.BuilderInternal,
logger *log.Logger) (Builder, error) {
builder := &builder{
kubeClient: kubeClient,
eventBuilder: eventBuilder,
logger: logger,
}
return builder, nil
}
func (b *builder) Create(info utils.ViolationInfo) error {
err := b.ProcessViolation(info)
if err != nil {
return err
}
return nil
}
func (b *builder) SetController(controller controllerinternalinterfaces.PolicyGetter) {
b.controller = controller
}
func (b *builder) ProcessViolation(info utils.ViolationInfo) error {
// Get the policy
policy, err := b.controller.GetPolicy(info.Policy)
if err != nil {
utilruntime.HandleError(err)
return err
}
modifiedPolicy := policy.DeepCopy()
modifiedViolations := []types.Violation{}
// Create new violation
newViolation := types.Violation{
Kind: info.Kind,
Resource: info.Resource,
Rule: info.Rule,
Reason: info.Reason,
Message: info.Message,
}
for _, violation := range modifiedPolicy.PolicyViolation.Violations {
ok, err := b.IsActive(info.Kind, violation.Resource)
if err != nil {
utilruntime.HandleError(err)
continue
}
if !ok {
// Remove the violation
// Create a removal event
b.eventBuilder.AddEvent(eventutils.EventInfo{
Kind: "Policy",
Resource: info.Policy,
Rule: info.Rule,
Reason: info.Reason,
Message: info.Message,
})
continue
}
// If violation already exists for this rule, we update the violation
//TODO: update violation, instead of re-creating one every time
}
modifiedViolations = append(modifiedViolations, newViolation)
modifiedPolicy.PolicyViolation.Violations = modifiedViolations
return b.Patch(policy, modifiedPolicy)
}
func (b *builder) IsActive(kind string, resource string) (bool, error) {
// Generate Merge Patch
_, err := b.kubeClient.GetResource(kind, resource)
if err != nil {
utilruntime.HandleError(fmt.Errorf("unable to get resource %s ", resource))
return false, err
}
return true, nil
}
// ProcessViolation(info utils.ViolationInfo) error
func (b *builder) Patch(policy *types.Policy, updatedPolicy *types.Policy) error {
originalData, err := json.Marshal(policy)
if err != nil {
return err
}
modifiedData, err := json.Marshal(updatedPolicy)
if err != nil {
return err
}
// generate merge patch
patchBytes, err := jsonpatch.CreateMergePatch(originalData, modifiedData)
if err != nil {
return err
}
_, err = b.controller.PatchPolicy(policy.Name, mergetypes.MergePatchType, patchBytes)
if err != nil {
// Unable to patch
return err
}
return nil
}