1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 10:28:36 +00:00

Merge commit 'a4e484b8d5003019c7f1b57af73422f418f01e81' into 254_dynamic_webhook_configurations

This commit is contained in:
Shuting Zhao 2019-08-08 15:28:59 -07:00
commit 462231c09d
8 changed files with 103 additions and 77 deletions

View file

@ -34,9 +34,10 @@ metadata:
spec:
rules:
- name: check-pod-resources
resource:
kinds:
- Pod
match:
resources:
kinds:
- Pod
validate:
message: "CPU and memory resource requests and limits are required"
pattern:
@ -67,9 +68,10 @@ metadata:
spec:
rules:
- name: set-image-pull-policy
resource:
kinds:
- Deployment
match:
resources:
kinds:
- Deployment
mutate:
overlay:
spec:
@ -94,12 +96,13 @@ metadata:
spec:
rules:
- name: "zk-kafka-address"
resource:
kinds:
- Namespace
selector:
matchExpressions:
- {key: kafka, operator: Exists}
match:
resources:
kinds:
- Namespace
selector:
matchExpressions:
- {key: kafka, operator: Exists}
generate:
kind: ConfigMap
name: zk-kafka-address

View file

@ -1,7 +1,7 @@
apiVersion: kyverno.io/v1alpha1
kind: Policy
metadata:
name: "default-networkpolicy"
name: defaultgeneratenetworkpolicy
spec:
rules:
- name: "default-networkpolicy"
@ -12,7 +12,7 @@ spec:
name: "devtest"
generate:
kind: NetworkPolicy
name: default-networkpolicy
name: defaultnetworkpolicy
data:
spec:
# select all pods in the namespace

View file

@ -78,6 +78,16 @@ func (p *Policy) updatePolicy(obj *Policy, ruleType pinfo.RuleType) bool {
updates := false
// Check Mutation rules
switch ruleType {
case pinfo.All:
if p.compareMutationRules(obj.MutationRules) {
updates = true
}
if p.compareValidationRules(obj.ValidationRules) {
updates = true
}
if p.compareGenerationRules(obj.GenerationRules) {
updates = true
}
case pinfo.Mutation:
if p.compareMutationRules(obj.MutationRules) {
updates = true
@ -214,6 +224,59 @@ func ParseAnnotationsFromObject(bytes []byte) map[string]string {
return ann
}
func PatchAnnotations(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pinfo.RuleType) ([]byte, error) {
if ruleType != pinfo.All && !pi.ContainsRuleType(ruleType) {
// the rule was not proceesed in the current policy application
return nil, nil
}
// transform the PolicyInfo to anotation struct
policyObj := newAnnotationForPolicy(pi)
if ann == nil {
ann = make(map[string]string, 0)
policyByte, err := json.Marshal(policyObj)
if err != nil {
return nil, err
}
// create a json patch to add annotation object
ann[BuildKeyString(pi.Name)] = string(policyByte)
// patch adds the annotation map with the policy information
jsonPatch, err := createAddJSONPatchMap(ann)
return jsonPatch, err
}
// if the annotations map already exists then we need to update it by adding a patch to the field inside the annotation
cPolicy, ok := ann[BuildKey(pi.Name)]
if !ok {
// annotations does not contain the policy
policyByte, err := json.Marshal(policyObj)
if err != nil {
return nil, err
}
jsonPatch, err := createAddJSONPatch(BuildKey(pi.Name), string(policyByte))
return jsonPatch, err
}
// an annotaion exists for the policy, we need to update the information if anything has changed
cPolicyObj := Policy{}
err := json.Unmarshal([]byte(cPolicy), &cPolicyObj)
if err != nil {
// error while unmarshallign the content
return nil, err
}
// update policy information inside the annotation
// 1> policy status
// 2> rule (name, status,changes,type)
update := cPolicyObj.updatePolicy(policyObj, ruleType)
if !update {
// there is not update, so we dont
return nil, nil
}
policyByte, err := json.Marshal(cPolicyObj)
if err != nil {
return nil, err
}
jsonPatch, err := createAddJSONPatch(BuildKey(pi.Name), string(policyByte))
return jsonPatch, err
}
//AddPolicyJSONPatch generate JSON Patch to add policy informatino JSON patch
func AddPolicyJSONPatch(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pinfo.RuleType) (map[string]string, []byte, error) {
if !pi.ContainsRuleType(ruleType) {

View file

@ -5,8 +5,6 @@ import (
"reflect"
"time"
jsonpatch "github.com/evanphx/json-patch"
"github.com/nirmata/kyverno/pkg/annotations"
"github.com/nirmata/kyverno/pkg/info"
"github.com/nirmata/kyverno/pkg/utils"
@ -207,7 +205,6 @@ func (pc *PolicyController) syncHandler(obj interface{}) error {
func (pc *PolicyController) createAnnotations(policyInfos []*info.PolicyInfo) {
for _, pi := range policyInfos {
var patch []byte
//get resource
obj, err := pc.client.GetResource(pi.RKind, pi.RNamespace, pi.RName)
if err != nil {
@ -216,61 +213,14 @@ func (pc *PolicyController) createAnnotations(policyInfos []*info.PolicyInfo) {
}
// add annotation for policy application
ann := obj.GetAnnotations()
// Mutation rules
ann, mpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Mutation)
if err != nil {
glog.Error(err)
continue
}
// Validation rules
ann, vpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Validation)
if err != nil {
glog.Error(err)
}
// Generation rules
ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Generation)
if err != nil {
glog.Error(err)
}
if mpatch == nil && vpatch == nil && gpatch == nil {
//nothing to patch
continue
}
// merge the patches
if mpatch != nil && vpatch != nil {
patch, err = jsonpatch.MergePatch(mpatch, vpatch)
if err != nil {
glog.Error(err)
continue
}
}
if mpatch == nil {
patch = vpatch
} else {
patch = mpatch
}
if gpatch != nil {
// generation
if patch != nil {
patch, err = jsonpatch.MergePatch(patch, gpatch)
if err != nil {
glog.Error(err)
continue
}
} else {
patch = gpatch
}
}
// if annotations are nil then create a map and patch
// else
// add the exact patch
patch, err := annotations.PatchAnnotations(ann, pi, info.All)
if patch == nil {
/// nothing to patch
return
}
// add the anotation to the resource
_, err = pc.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, patch)
if err != nil {
glog.Error(err)

View file

@ -2,13 +2,14 @@ package engine
import (
"encoding/json"
"errors"
"fmt"
"github.com/golang/glog"
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/info"
"github.com/nirmata/kyverno/pkg/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)
@ -21,7 +22,7 @@ func Generate(client *client.Client, policy *v1alpha1.Policy, ns unstructured.Un
continue
}
ri := info.NewRuleInfo(rule.Name, info.Generation)
err := applyRuleGenerator(client, ns, rule.Generation)
err := applyRuleGenerator(client, ns, rule.Generation, policy.GetCreationTimestamp())
if err != nil {
ri.Fail()
ri.Addf("Rule %s: Failed to apply rule generator, err %v.", rule.Name, err)
@ -34,11 +35,15 @@ func Generate(client *client.Client, policy *v1alpha1.Policy, ns unstructured.Un
return ris
}
func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen *v1alpha1.Generation) error {
func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen *v1alpha1.Generation, policyCreationTime metav1.Time) error {
var err error
resource := &unstructured.Unstructured{}
var rdata map[string]interface{}
// To manage existing resource , we compare the creation time for the default resource to be generate and policy creation time
processExisting := func() bool {
nsCreationTime := ns.GetCreationTimestamp()
return nsCreationTime.Before(&policyCreationTime)
}()
if gen.Data != nil {
// 1> Check if resource exists
obj, err := client.GetResource(gen.Kind, ns.GetName(), gen.Name)
@ -51,7 +56,7 @@ func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen
return err
}
if !ok {
return errors.New("rule configuration not present in resource")
return fmt.Errorf("rule configuration not present in resource %s/%s", ns.GetName(), gen.Name)
}
return nil
}
@ -74,12 +79,15 @@ func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen
}
rdata = resource.UnstructuredContent()
}
if processExisting {
// for existing resources we generate an error which indirectly generates a policy violation
return fmt.Errorf("resource %s not found in existing namespace %s", gen.Name, ns.GetName())
}
resource.SetUnstructuredContent(rdata)
resource.SetName(gen.Name)
resource.SetNamespace(ns.GetName())
// Reset resource version
resource.SetResourceVersion("")
_, err = client.CreateResource(gen.Kind, ns.GetName(), resource, false)
if err != nil {
return err

View file

@ -140,7 +140,7 @@ func (c *Controller) createAnnotations(pi *info.PolicyInfo) {
// add annotation for policy application
ann := obj.GetAnnotations()
// Generation rules
ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Generation)
gpatch, err := annotations.PatchAnnotations(ann, pi, info.Generation)
if err != nil {
glog.Error(err)
return

View file

@ -99,6 +99,7 @@ const (
Mutation RuleType = iota
Validation
Generation
All
)
func (ri RuleType) String() string {
@ -106,6 +107,7 @@ func (ri RuleType) String() string {
"Mutation",
"Validation",
"Generation",
"All",
}[ri]
}

View file

@ -68,7 +68,7 @@ func addAnnotationsToResource(rawResource []byte, pi *info.PolicyInfo, ruleType
}
// get annotations
ann := annotations.ParseAnnotationsFromObject(rawResource)
ann, patch, err := annotations.AddPolicyJSONPatch(ann, pi, ruleType)
patch, err := annotations.PatchAnnotations(ann, pi, ruleType)
if err != nil {
glog.Error(err)
return nil