1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

refactor generate to use variable substition at rule level

This commit is contained in:
shivkumar dudhani 2020-02-13 13:57:48 -08:00
parent f4c1973c36
commit d855247a98
7 changed files with 443 additions and 279 deletions
pkg
api/kyverno/v1
engine
generate

View file

@ -216,8 +216,8 @@ type Validation struct {
// Generation describes which resources will be created when other resource is created
type Generation struct {
ResourceSpec
Data interface{} `json:"data"`
Clone CloneFrom `json:"clone"`
Data interface{} `json:"data,omitempty"`
Clone CloneFrom `json:"clone,omitempty"`
}
// CloneFrom - location of the resource

View file

@ -41,6 +41,17 @@ func ValidateResourceWithPattern(ctx context.EvalInterface, resource, pattern in
return "", ValidationError{}
}
// ValidateResourceWithPattern1 is a start of element-by-element validation process
// It assumes that validation is started from root, so "/" is passed
func ValidateResourceWithPattern1(resource, pattern interface{}) (string, error) {
path, err := validateResourceElement(resource, pattern, pattern, "/")
if err != nil {
return path, err
}
return "", nil
}
func copyInterface(original interface{}) (interface{}, error) {
tempData, err := json.Marshal(original)
if err != nil {

View file

@ -0,0 +1,167 @@
package variables
import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/operator"
)
//SubstituteVars replaces the variables with the values defined in the context
// - if any variable is invaid or has nil value, it is considered as a failed varable substitution
func SubstituteVars(ctx context.EvalInterface, pattern interface{}) error {
errs := []error{}
subVars(ctx, pattern, "", &errs)
if len(errs) == 0 {
// no error while parsing the pattern
return nil
}
return fmt.Errorf("variable(s) not found or has nil values: %v", errs)
}
func subVars(ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
switch typedPattern := pattern.(type) {
case map[string]interface{}:
return subMap(ctx, typedPattern, path, errs)
case []interface{}:
return subArray(ctx, typedPattern, path, errs)
case string:
return subVal(ctx, typedPattern, path, errs)
default:
return pattern
}
}
func subMap(ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
for key, patternElement := range patternMap {
curPath := path + "/" + key
value := subVars(ctx, patternElement, curPath, errs)
patternMap[key] = value
}
return patternMap
}
func subArray(ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
for idx, patternElement := range patternList {
curPath := path + "/" + strconv.Itoa(idx)
value := subVars(ctx, patternElement, curPath, errs)
patternList[idx] = value
}
return patternList
}
func subVal(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
operatorVariable := getOp(valuePattern)
variable := valuePattern[len(operatorVariable):]
// substitute variable with value
value, failedVars := getValQuery(ctx, variable)
// if there are failedVars at this level
// capture as error and the path to the variables
for _, failedVar := range failedVars {
failedPath := path + "/" + failedVar
*errs = append(*errs, NewInvalidPath(failedPath))
}
if operatorVariable == "" {
// default or operator.Equal
// equal + string value
// object variable
return value
}
// operator + string variable
switch value.(type) {
case string:
return string(operatorVariable) + value.(string)
default:
glog.Infof("cannot use operator with object variables. operator used %s in pattern %v", string(operatorVariable), valuePattern)
var emptyInterface interface{}
return emptyInterface
}
}
func getOp(pattern string) string {
operatorVariable := operator.GetOperatorFromStringPattern(pattern)
if operatorVariable == operator.Equal {
return ""
}
return string(operatorVariable)
}
func getValQuery(ctx context.EvalInterface, valuePattern string) (interface{}, []string) {
var emptyInterface interface{}
validRegex := regexp.MustCompile(variableRegex)
groups := validRegex.FindAllStringSubmatch(valuePattern, -1)
// there can be multiple varialbes in a single value pattern
varMap, failedVars := getVal(ctx, groups)
if len(varMap) == 0 && len(failedVars) == 0 {
// no variables
// return original value
return valuePattern, nil
}
if isAllStrings(varMap) {
newVal := valuePattern
for key, value := range varMap {
if val, ok := value.(string); ok {
newVal = strings.Replace(newVal, key, val, -1)
}
}
return newVal, failedVars
}
// multiple substitution per statement for non-string types are not supported
for _, value := range varMap {
return value, failedVars
}
return emptyInterface, failedVars
}
func getVal(ctx context.EvalInterface, groups [][]string) (map[string]interface{}, []string) {
substiutions := map[string]interface{}{}
var failedVars []string
for _, group := range groups {
// 0th is the string
varName := group[0]
varValue := group[1]
variable, err := ctx.Query(varValue)
// err !=nil -> invalid expression
// err == nil && variable == nil -> variable is empty or path is not present
// a variable with empty value is considered as a failed variable
if err != nil || (err == nil && variable == nil) {
// could not find the variable at the given path
failedVars = append(failedVars, varName)
continue
}
substiutions[varName] = variable
}
return substiutions, failedVars
}
func isAllStrings(subVar map[string]interface{}) bool {
if len(subVar) == 0 {
return false
}
for _, value := range subVar {
if _, ok := value.(string); !ok {
return false
}
}
return true
}
//InvalidPath stores the path to failed variable
type InvalidPath struct {
path string
}
func (e *InvalidPath) Error() string {
return e.path
}
//NewInvalidPath returns a new Invalid Path error
func NewInvalidPath(path string) *InvalidPath {
return &InvalidPath{path: path}
}

View file

@ -0,0 +1,130 @@
package variables
import (
"encoding/json"
"testing"
"github.com/nirmata/kyverno/pkg/engine/context"
)
func Test_subVars_success(t *testing.T) {
patternMap := []byte(`
{
"kind": "{{request.object.metadata.name}}",
"name": "ns-owner-{{request.object.metadata.name}}",
"data": {
"rules": [
{
"apiGroups": [
"{{request.object.metadata.name}}"
],
"resources": [
"namespaces"
],
"verbs": [
"*"
],
"resourceNames": [
"{{request.object.metadata.name}}"
]
}
]
}
}
`)
resourceRaw := []byte(`
{
"metadata": {
"name": "temp",
"namespace": "n1"
},
"spec": {
"namespace": "n1",
"name": "temp1"
}
}
`)
var pattern, resource interface{}
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
if err := SubstituteVars(ctx, pattern); err != nil {
t.Error(err)
}
}
func Test_subVars_failed(t *testing.T) {
patternMap := []byte(`
{
"kind": "{{request.object.metadata.name1}}",
"name": "ns-owner-{{request.object.metadata.name}}",
"data": {
"rules": [
{
"apiGroups": [
"{{request.object.metadata.name}}"
],
"resources": [
"namespaces"
],
"verbs": [
"*"
],
"resourceNames": [
"{{request.object.metadata.name1}}"
]
}
]
}
}
`)
resourceRaw := []byte(`
{
"metadata": {
"name": "temp",
"namespace": "n1"
},
"spec": {
"namespace": "n1",
"name": "temp1"
}
}
`)
var pattern, resource interface{}
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
if err := SubstituteVars(ctx, pattern); err == nil {
t.Error("error is expected")
}
}

View file

@ -16,8 +16,8 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
if err := deleteGeneratedResources(c.client, gr); err != nil {
return err
}
// - trigger-resource is delted
// - generated-resources are delted
// - trigger-resource is deleted
// - generated-resources are deleted
// - > Now delete the GenerateRequest CR
return c.control.Delete(gr.Name)
}

View file

@ -2,9 +2,7 @@ package generate
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -13,10 +11,8 @@ import (
"github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/validate"
"github.com/nirmata/kyverno/pkg/engine/variables"
"github.com/nirmata/kyverno/pkg/policyviolation"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
@ -30,24 +26,10 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
glog.V(4).Infof("resource does not exist or is yet to be created, requeuing: %v", err)
return err
}
// 2 - Apply the generate policy on the resource
genResources, err = c.applyGenerate(*resource, *gr)
switch e := err.(type) {
case *Violation:
// Generate event
// - resource -> rule failed and created PV
// - policy -> failed to apply of resource and created PV
c.pvGenerator.Add(generatePV(*gr, *resource, e))
default:
// Generate event
// - resource -> rule failed
// - policy -> failed tp apply on resource
glog.V(4).Info(e)
}
// 3 - Report Events
reportEvents(err, c.eventGen, *gr, *resource)
// 4 - Update Status
return updateStatus(c.statusControl, *gr, err, genResources)
}
@ -97,13 +79,6 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
}
if pv := buildPathNotPresentPV(engineResponse); pv != nil {
c.pvGenerator.Add(pv...)
// variable substitiution fails in ruleInfo (match,exclude,condition)
// the overall policy should not apply to resource
return nil, fmt.Errorf("referenced path not present in generate policy %s", policy.Name)
}
// Apply the generate rule on resource
return applyGeneratePolicy(c.client, policyContext)
}
@ -152,61 +127,57 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
var mode ResourceMode
var noGenResource kyverno.ResourceSpec
if invalidPaths := variables.ValidateVariables(ctx, rule.Generation.ResourceSpec); len(invalidPaths) != 0 {
return noGenResource, NewViolation(rule.Name, fmt.Errorf("path not present in generate resource spec: %s", invalidPaths))
// convert to unstructured Resource
genUnst, err := getUnstrRule(rule.Generation.DeepCopy())
if err != nil {
return noGenResource, err
}
glog.V(4).Info("applyRule1 %v", genUnst)
// Variable substitutions
// format : {{<variable_name}}
// - if there is variables that are not defined the context -> results in error and rule is not applied
// - valid variables are replaced with the values
if err := variables.SubstituteVars(ctx, genUnst.Object); err != nil {
return noGenResource, err
}
glog.V(4).Info("applyRule2 %v", genUnst.Object)
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
if err != nil {
return noGenResource, err
}
genName, _, err := unstructured.NestedString(genUnst.Object, "name")
if err != nil {
return noGenResource, err
}
genNamespace, _, err := unstructured.NestedString(genUnst.Object, "namespace")
if err != nil {
return noGenResource, err
}
// variable substitution
// - name
// - namespace
// - clone.name
// - clone.namespace
gen := variableSubsitutionForAttributes(rule.Generation, ctx)
// Resource to be generated
newGenResource := kyverno.ResourceSpec{
Kind: gen.Kind,
Namespace: gen.Namespace,
Name: gen.Name,
Kind: genKind,
Namespace: genNamespace,
Name: genName,
}
genData, _, err := unstructured.NestedMap(genUnst.Object, "data")
if err != nil {
return noGenResource, err
}
genCopy, _, err := unstructured.NestedMap(genUnst.Object, "clone")
if err != nil {
return noGenResource, err
}
// DATA
if gen.Data != nil {
if rdata, mode, err = handleData(rule.Name, gen, client, resource, ctx); err != nil {
glog.V(4).Info(err)
switch e := err.(type) {
case *ParseFailed, *NotFound, *ConfigNotFound:
// handled errors
return noGenResource, e
case *Violation:
// create policy violation
return noGenResource, e
default:
// errors that cant be handled
return noGenResource, e
}
}
if rdata == nil {
// existing resource contains the configuration
return newGenResource, nil
}
if genData != nil {
rdata, mode, err = manageData(genKind, genNamespace, genName, genData, client, resource)
} else {
rdata, mode, err = manageClone(genKind, genNamespace, genName, genCopy, client, resource)
}
// CLONE
if gen.Clone != (kyverno.CloneFrom{}) {
if rdata, mode, err = handleClone(rule.Name, gen, client, resource, ctx); err != nil {
glog.V(4).Info(err)
switch e := err.(type) {
case *NotFound:
// handled errors
return noGenResource, e
default:
// errors that cant be handled
return noGenResource, e
}
}
if rdata == nil {
// resource already exists
return newGenResource, nil
}
if rdata == nil {
// existing resource contains the configuration
return newGenResource, nil
}
if processExisting {
// handle existing resources
@ -218,8 +189,8 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
// build the resource template
newResource := &unstructured.Unstructured{}
newResource.SetUnstructuredContent(rdata)
newResource.SetName(gen.Name)
newResource.SetNamespace(gen.Namespace)
newResource.SetName(genName)
newResource.SetNamespace(genNamespace)
// manage labels
// - app.kubernetes.io/managed-by: kyverno
@ -230,58 +201,88 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
// Reset resource version
newResource.SetResourceVersion("")
// Create the resource
glog.V(4).Infof("Creating new resource %s/%s/%s", gen.Kind, gen.Namespace, gen.Name)
_, err = client.CreateResource(gen.Kind, gen.Namespace, newResource, false)
glog.V(4).Infof("Creating new resource %s/%s/%s", genKind, genNamespace, genName)
_, err = client.CreateResource(genKind, genNamespace, newResource, false)
if err != nil {
// Failed to create resource
return noGenResource, err
}
glog.V(4).Infof("Created new resource %s/%s/%s", gen.Kind, gen.Namespace, gen.Name)
glog.V(4).Infof("Created new resource %s/%s/%s", genKind, genNamespace, genName)
} else if mode == Update {
glog.V(4).Infof("Updating existing resource %s/%s/%s", gen.Kind, gen.Namespace, gen.Name)
glog.V(4).Infof("Updating existing resource %s/%s/%s", genKind, genNamespace, genName)
// Update the resource
_, err := client.UpdateResource(gen.Kind, gen.Namespace, newResource, false)
_, err := client.UpdateResource(genKind, genNamespace, newResource, false)
if err != nil {
// Failed to update resource
return noGenResource, err
}
glog.V(4).Infof("Updated existing resource %s/%s/%s", gen.Kind, gen.Namespace, gen.Name)
glog.V(4).Infof("Updated existing resource %s/%s/%s", genKind, genNamespace, genName)
}
return newGenResource, nil
}
func variableSubsitutionForAttributes(gen kyverno.Generation, ctx context.EvalInterface) kyverno.Generation {
// Name
name := gen.Name
namespace := gen.Namespace
newNameVar := variables.SubstituteVariables(ctx, name)
if newName, ok := newNameVar.(string); ok {
gen.Name = newName
func manageData(kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
// check if resource to be generated exists
obj, err := client.GetResource(kind, namespace, name)
if apierrors.IsNotFound(err) {
glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", kind, namespace, name)
return data, Create, nil
}
if err != nil {
//something wrong while fetching resource
// client-errors
return nil, Skip, err
}
// Resource exists; verfiy the content of the resource
err = checkResource(data, obj)
if err == nil {
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
return nil, Skip, nil
}
newNamespaceVar := variables.SubstituteVariables(ctx, namespace)
if newNamespace, ok := newNamespaceVar.(string); ok {
gen.Namespace = newNamespace
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", kind, namespace, name)
return data, Update, nil
}
func manageClone(kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
// check if resource to be generated exists
_, err := client.GetResource(kind, namespace, name)
if err == nil {
// resource does exists, not need to process further as it is already in expected state
return nil, Skip, nil
}
//TODO: check this
if !apierrors.IsNotFound(err) {
//something wrong while fetching resource
return nil, Skip, err
}
if gen.Clone != (kyverno.CloneFrom{}) {
// Clone
cloneName := gen.Clone.Name
cloneNamespace := gen.Clone.Namespace
newcloneNameVar := variables.SubstituteVariables(ctx, cloneName)
if newcloneName, ok := newcloneNameVar.(string); ok {
gen.Clone.Name = newcloneName
}
newcloneNamespaceVar := variables.SubstituteVariables(ctx, cloneNamespace)
if newcloneNamespace, ok := newcloneNamespaceVar.(string); ok {
gen.Clone.Namespace = newcloneNamespace
}
newRNs, _, err := unstructured.NestedString(clone, "namespace")
if err != nil {
return nil, Skip, err
}
return gen
newRName, _, err := unstructured.NestedString(clone, "name")
if err != nil {
return nil, Skip, err
}
// Short-circuit if the resource to be generated and the clone is the same
if newRNs == namespace && newRName == name {
// attempting to clone it self, this will fail -> short-ciruit it
return nil, Skip, nil
}
// check if the resource as reference in clone exists?
obj, err := client.GetResource(kind, newRNs, newRName)
if err != nil {
return nil, Skip, err
}
// create the resource based on the reference clone
return obj.UnstructuredContent(), Create, nil
}
// ResourceMode defines the mode for generated resource
@ -292,130 +293,33 @@ const (
Skip ResourceMode = "SKIP"
//Create : create a new resource
Create = "CREATE"
//Update : update/override the new resource
//Update : update/overwrite the new resource
Update = "UPDATE"
)
func copyInterface(original interface{}) (interface{}, error) {
tempData, err := json.Marshal(original)
if err != nil {
return nil, err
}
fmt.Println(string(tempData))
var temp interface{}
err = json.Unmarshal(tempData, &temp)
if err != nil {
return nil, err
}
return temp, nil
}
// manage the creation/update of resource to be generated using the spec defined in the policy
func handleData(ruleName string, generateRule kyverno.Generation, client *dclient.Client, resource unstructured.Unstructured, ctx context.EvalInterface) (map[string]interface{}, ResourceMode, error) {
//work on copy of the data
// as the type of data stored in interface is not know,
// we marshall the data and unmarshal it into a new resource to create a copy
dataCopy, err := copyInterface(generateRule.Data)
if err != nil {
glog.V(4).Infof("failed to create a copy of the interface %v", generateRule.Data)
return nil, Skip, err
}
// replace variables with the corresponding values
newData := variables.SubstituteVariables(ctx, dataCopy)
// if any variable defined in the data is not avaialbe in the context
if invalidPaths := variables.ValidateVariables(ctx, newData); len(invalidPaths) != 0 {
return nil, Skip, NewViolation(ruleName, fmt.Errorf("path not present in generate data: %s", invalidPaths))
}
// check if resource exists
obj, err := client.GetResource(generateRule.Kind, generateRule.Namespace, generateRule.Name)
if apierrors.IsNotFound(err) {
// Resource does not exist
// Processing the request first time
rdata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&newData)
if err != nil {
return nil, Skip, NewParseFailed(newData, err)
}
glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", generateRule.Kind, generateRule.Namespace, generateRule.Name)
return rdata, Create, nil
}
if err != nil {
//something wrong while fetching resource
return nil, Skip, err
}
// Resource exists; verfiy the content of the resource
ok, err := checkResource(ctx, newData, obj)
if err != nil {
// error while evaluating if the existing resource contains the required information
return nil, Skip, err
}
if !ok {
// existing resource does not contain the configuration mentioned in spec, will try to update
rdata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&newData)
if err != nil {
return nil, Skip, NewParseFailed(newData, err)
}
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", generateRule.Kind, generateRule.Namespace, generateRule.Name)
return rdata, Update, nil
}
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
return nil, Skip, nil
}
// manage the creation/update based on the reference clone resource
func handleClone(ruleName string, generateRule kyverno.Generation, client *dclient.Client, resource unstructured.Unstructured, ctx context.EvalInterface) (map[string]interface{}, ResourceMode, error) {
// if any variable defined in the data is not avaialbe in the context
if invalidPaths := variables.ValidateVariables(ctx, generateRule.Clone); len(invalidPaths) != 0 {
return nil, Skip, NewViolation(ruleName, fmt.Errorf("path not present in generate clone: %s", invalidPaths))
}
// check if resource to be generated exists
_, err := client.GetResource(generateRule.Kind, generateRule.Namespace, generateRule.Name)
if err == nil {
// resource does exists, not need to process further as it is already in expected state
return nil, Skip, nil
}
if !apierrors.IsNotFound(err) {
//something wrong while fetching resource
return nil, Skip, err
}
// get clone resource reference in the rule
obj, err := client.GetResource(generateRule.Kind, generateRule.Clone.Namespace, generateRule.Clone.Name)
if apierrors.IsNotFound(err) {
// reference resource does not exist, cant generate the resources
return nil, Skip, NewNotFound(generateRule.Kind, generateRule.Clone.Namespace, generateRule.Clone.Name)
}
if err != nil {
//something wrong while fetching resource
return nil, Skip, err
}
// create the resource based on the reference clone
return obj.UnstructuredContent(), Create, nil
}
func checkResource(ctx context.EvalInterface, newResourceSpec interface{}, resource *unstructured.Unstructured) (bool, error) {
func checkResource(newResourceSpec interface{}, resource *unstructured.Unstructured) error {
// check if the resource spec if a subset of the resource
path, err := validate.ValidateResourceWithPattern(ctx, resource.Object, newResourceSpec)
if !reflect.DeepEqual(err, validate.ValidationError{}) {
glog.V(4).Infof("config not a subset of resource. failed at path %s: %v", path, err)
return false, errors.New(err.ErrorMsg)
if path, err := validate.ValidateResourceWithPattern1(resource.Object, newResourceSpec); err != nil {
glog.V(4).Info("Failed to match the resource at path %s: err", path, err)
return err
}
return true, nil
return nil
}
func generatePV(gr kyverno.GenerateRequest, resource unstructured.Unstructured, err *Violation) policyviolation.Info {
info := policyviolation.Info{
PolicyName: gr.Spec.Policy,
Resource: resource,
Rules: []kyverno.ViolatedRule{{
Name: err.rule,
Type: "Generation",
Message: err.Error(),
}},
func getUnstrRule(rule *kyverno.Generation) (*unstructured.Unstructured, error) {
ruleData, err := json.Marshal(rule)
if err != nil {
return nil, err
}
return info
return ConvertToUnstructured(ruleData)
}
//ConvertToUnstructured converts the resource to unstructured format
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data)
if err != nil {
return nil, err
}
return resource, nil
}

View file

@ -5,9 +5,7 @@ import (
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/event"
"github.com/nirmata/kyverno/pkg/policyviolation"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -20,45 +18,9 @@ func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateReques
eventGen.Add(events...)
return
}
switch e := err.(type) {
case *Violation:
// - resource -> rule failed and created PV
// - policy -> failed to apply of resource and created PV
glog.V(4).Infof("reporing events for %v", e)
events := failedEventsPV(err, gr, resource)
eventGen.Add(events...)
default:
// - resource -> rule failed
// - policy -> failed tp apply on resource
glog.V(4).Infof("reporing events for %v", e)
events := failedEvents(err, gr, resource)
eventGen.Add(events...)
}
}
func failedEventsPV(err error, gr kyverno.GenerateRequest, resource unstructured.Unstructured) []event.Info {
var events []event.Info
// Cluster Policy
pe := event.Info{}
pe.Kind = "ClusterPolicy"
// cluserwide-resource
pe.Name = gr.Spec.Policy
pe.Reason = event.PolicyViolation.String()
pe.Source = event.GeneratePolicyController
pe.Message = fmt.Sprintf("policy failed to apply on resource %s/%s/%s creating violation: %v", resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
events = append(events, pe)
// Resource
re := event.Info{}
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Reason = event.PolicyViolation.String()
re.Source = event.GeneratePolicyController
re.Message = fmt.Sprintf("policy %s failed to apply created violation: %v", gr.Spec.Policy, err)
events = append(events, re)
return events
glog.V(4).Infof("reporing events for %v", err)
events := failedEvents(err, gr, resource)
eventGen.Add(events...)
}
func failedEvents(err error, gr kyverno.GenerateRequest, resource unstructured.Unstructured) []event.Info {
@ -110,13 +72,3 @@ func successEvents(gr kyverno.GenerateRequest, resource unstructured.Unstructure
return events
}
// buildPathNotPresentPV build violation info when referenced path not found
func buildPathNotPresentPV(er response.EngineResponse) []policyviolation.Info {
for _, rr := range er.PolicyResponse.Rules {
if rr.PathNotPresent {
return policyviolation.GeneratePVsFromEngineResponse([]response.EngineResponse{er})
}
}
return nil
}