2019-05-13 18:17:28 -07:00
|
|
|
package violation
|
2019-04-26 18:16:22 -07:00
|
|
|
|
2019-04-29 14:34:54 -07:00
|
|
|
import (
|
2019-06-28 17:22:00 -07:00
|
|
|
"errors"
|
|
|
|
"reflect"
|
|
|
|
|
2019-05-30 12:28:56 -07:00
|
|
|
"github.com/golang/glog"
|
2019-05-21 11:00:09 -07:00
|
|
|
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
|
|
|
v1alpha1 "github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1"
|
2019-05-29 14:12:09 -07:00
|
|
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
2019-05-21 11:00:09 -07:00
|
|
|
event "github.com/nirmata/kyverno/pkg/event"
|
|
|
|
"github.com/nirmata/kyverno/pkg/sharedinformer"
|
2019-04-29 14:34:54 -07:00
|
|
|
)
|
|
|
|
|
2019-05-10 10:38:38 -07:00
|
|
|
//Generator to generate policy violation
|
|
|
|
type Generator interface {
|
2019-06-27 11:43:07 -07:00
|
|
|
Add(infos ...*Info) error
|
2019-04-26 18:16:22 -07:00
|
|
|
}
|
2019-04-29 14:34:54 -07:00
|
|
|
|
2019-05-10 10:38:38 -07:00
|
|
|
type builder struct {
|
2019-05-15 12:29:09 -07:00
|
|
|
client *client.Client
|
|
|
|
policyLister v1alpha1.PolicyLister
|
|
|
|
eventBuilder event.Generator
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
|
|
|
|
2019-05-10 10:38:38 -07:00
|
|
|
//Builder is to build policy violations
|
|
|
|
type Builder interface {
|
|
|
|
Generator
|
2019-06-27 11:43:07 -07:00
|
|
|
processViolation(info *Info) error
|
2019-06-28 17:22:00 -07:00
|
|
|
isActive(kind string, rname string, rnamespace string) (bool, error)
|
2019-05-10 00:05:21 -07:00
|
|
|
}
|
|
|
|
|
2019-05-10 10:38:38 -07:00
|
|
|
//NewPolicyViolationBuilder returns new violation builder
|
2019-05-15 07:30:22 -07:00
|
|
|
func NewPolicyViolationBuilder(client *client.Client,
|
2019-05-15 12:29:09 -07:00
|
|
|
sharedInfomer sharedinformer.PolicyInformer,
|
2019-05-30 12:28:56 -07:00
|
|
|
eventController event.Generator) Builder {
|
2019-05-15 07:30:22 -07:00
|
|
|
|
2019-05-10 10:38:38 -07:00
|
|
|
builder := &builder{
|
2019-05-15 12:29:09 -07:00
|
|
|
client: client,
|
|
|
|
policyLister: sharedInfomer.GetLister(),
|
|
|
|
eventBuilder: eventController,
|
2019-05-06 12:08:31 -07:00
|
|
|
}
|
2019-05-10 00:05:21 -07:00
|
|
|
return builder
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
|
|
|
|
2019-06-27 11:43:07 -07:00
|
|
|
func (b *builder) Add(infos ...*Info) error {
|
|
|
|
for _, info := range infos {
|
|
|
|
return b.processViolation(info)
|
|
|
|
}
|
|
|
|
return nil
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
|
|
|
|
2019-06-27 11:43:07 -07:00
|
|
|
func (b *builder) processViolation(info *Info) error {
|
2019-06-28 17:22:00 -07:00
|
|
|
currentViolations := []interface{}{}
|
|
|
|
statusMap := map[string]interface{}{}
|
|
|
|
var ok bool
|
|
|
|
//TODO: hack get from client
|
|
|
|
p1, err := b.client.GetResource("policies", "", info.Policy, "status")
|
2019-04-29 14:34:54 -07:00
|
|
|
if err != nil {
|
2019-04-30 17:13:44 -07:00
|
|
|
return err
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
2019-06-28 17:22:00 -07:00
|
|
|
unstr := p1.UnstructuredContent()
|
|
|
|
// check if "status" field exists
|
|
|
|
status, ok := unstr["status"]
|
|
|
|
if ok {
|
|
|
|
// status is already present then we append violations
|
|
|
|
if statusMap, ok = status.(map[string]interface{}); !ok {
|
|
|
|
return errors.New("Unable to parse status subresource")
|
2019-05-06 09:12:37 -07:00
|
|
|
}
|
2019-06-28 17:22:00 -07:00
|
|
|
violations, ok := statusMap["violations"]
|
2019-05-06 09:12:37 -07:00
|
|
|
if !ok {
|
2019-06-28 17:22:00 -07:00
|
|
|
glog.Info("violation not present")
|
|
|
|
}
|
|
|
|
glog.Info(reflect.TypeOf(violations))
|
|
|
|
if currentViolations, ok = violations.([]interface{}); !ok {
|
|
|
|
return errors.New("Unable to parse violations")
|
2019-04-30 17:13:44 -07:00
|
|
|
}
|
|
|
|
}
|
2019-06-28 17:22:00 -07:00
|
|
|
newViolation := info.Violation
|
|
|
|
for _, violation := range currentViolations {
|
|
|
|
glog.Info(reflect.TypeOf(violation))
|
|
|
|
if v, ok := violation.(map[string]interface{}); ok {
|
|
|
|
if name, ok := v["name"].(string); ok {
|
|
|
|
if namespace, ok := v["namespace"].(string); ok {
|
|
|
|
ok, err := b.isActive(info.Kind, name, namespace)
|
|
|
|
if err != nil {
|
|
|
|
glog.Error(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
//TODO remove the violation as it corresponds to resource that does not exist
|
|
|
|
glog.Info("removed violation")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentViolations = append(currentViolations, newViolation)
|
|
|
|
// update violations
|
|
|
|
// set the updated status
|
|
|
|
statusMap["violations"] = currentViolations
|
|
|
|
unstr["status"] = statusMap
|
|
|
|
p1.SetUnstructuredContent(unstr)
|
|
|
|
_, err = b.client.UpdateStatusResource("policies", "", p1, false)
|
2019-05-10 00:05:21 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2019-06-28 17:22:00 -07:00
|
|
|
// modifiedViolations := []types.Violation{}
|
|
|
|
// modifiedViolations = append(modifiedViolations, types.Violation{Name: "name", Kind: "Deploymeny"})
|
|
|
|
// unstr["status"] = modifiedViolations
|
|
|
|
// p1.SetUnstructuredContent(unstr)
|
|
|
|
// rdata, err := p1.MarshalJSON()
|
|
|
|
// if err != nil {
|
|
|
|
// glog.Info(err)
|
|
|
|
// }
|
|
|
|
// glog.Info(string(rdata))
|
|
|
|
// _, err = b.client.UpdateStatusResource("policies", "", p1, false)
|
|
|
|
// if err != nil {
|
|
|
|
// glog.Info(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// p, err := b.policyLister.Get(info.Policy)
|
|
|
|
// if err != nil {
|
|
|
|
// glog.Error(err)
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// glog.Info(p.TypeMeta.Kind)
|
|
|
|
// glog.Info(p.Kind)
|
|
|
|
// modifiedPolicy := p.DeepCopy()
|
|
|
|
// glog.Info(modifiedPolicy.Kind)
|
|
|
|
// // Create new violation
|
|
|
|
// newViolation := info.Violation
|
|
|
|
|
|
|
|
// for _, violation := range modifiedPolicy.Status.Violations {
|
|
|
|
// ok, err := b.isActive(info.Kind, violation.Name)
|
|
|
|
// if err != nil {
|
|
|
|
// glog.Error(err)
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
// if !ok {
|
|
|
|
// glog.Info("removed violation")
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// // 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.Status.Violations = modifiedViolations
|
|
|
|
// // Violations are part of the status sub resource, so we can use the Update Status api instead of updating the policy object
|
|
|
|
// _, err = b.client.UpdateStatusResource("policies", "", *modifiedPolicy, false)
|
|
|
|
// if err != nil {
|
|
|
|
// glog.Info(err)
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// return nil
|
2019-04-30 17:13:44 -07:00
|
|
|
}
|
|
|
|
|
2019-06-28 17:22:00 -07:00
|
|
|
func (b *builder) isActive(kind string, rname string, rnamespace string) (bool, error) {
|
2019-05-06 09:12:37 -07:00
|
|
|
// Generate Merge Patch
|
2019-06-28 17:22:00 -07:00
|
|
|
_, err := b.client.GetResource(b.client.DiscoveryClient.GetGVRFromKind(kind).Resource, rnamespace, rname)
|
2019-04-29 14:34:54 -07:00
|
|
|
if err != nil {
|
2019-06-28 17:22:00 -07:00
|
|
|
glog.Errorf("unable to get resource %s/%s ", rnamespace, rname)
|
2019-04-30 17:13:44 -07:00
|
|
|
return false, err
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
2019-04-30 17:13:44 -07:00
|
|
|
return true, nil
|
2019-04-29 14:34:54 -07:00
|
|
|
}
|
2019-05-10 12:36:55 -07:00
|
|
|
|
|
|
|
//NewViolation return new policy violation
|
2019-06-27 11:43:07 -07:00
|
|
|
func NewViolation(policyName string, kind string, rname string, rnamespace string, reason string, msg string) Info {
|
2019-05-10 12:36:55 -07:00
|
|
|
return Info{Policy: policyName,
|
|
|
|
Violation: types.Violation{
|
2019-06-26 18:02:01 -07:00
|
|
|
Kind: kind,
|
|
|
|
Name: rname,
|
|
|
|
Namespace: rnamespace,
|
|
|
|
Reason: reason,
|
|
|
|
},
|
2019-05-10 12:36:55 -07:00
|
|
|
}
|
|
|
|
}
|
2019-06-27 11:43:07 -07:00
|
|
|
|
|
|
|
//NewViolationFromEvent returns violation info from event
|
|
|
|
func NewViolationFromEvent(e *event.Info, pName string, rKind string, rName string, rnamespace string) *Info {
|
|
|
|
return &Info{
|
|
|
|
Policy: pName,
|
|
|
|
Violation: types.Violation{
|
|
|
|
Kind: rKind,
|
|
|
|
Name: rName,
|
|
|
|
Namespace: rnamespace,
|
2019-06-28 17:22:00 -07:00
|
|
|
Reason: e.Reason,
|
|
|
|
Message: e.Message,
|
2019-06-27 11:43:07 -07:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|