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:
commit
462231c09d
8 changed files with 103 additions and 77 deletions
27
README.md
27
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue