mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
Merge pull request #1405 from NoSkillGirl/bug/1374_generate_rule_with_synchronization
enqueing gr on getting deleted
This commit is contained in:
commit
5edb8b3ee6
11 changed files with 373 additions and 106 deletions
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
backwardcompatibility "github.com/kyverno/kyverno/pkg/backward_compatibility"
|
||||
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
|
@ -328,6 +329,7 @@ func main() {
|
|||
log.Log.WithName("WebhookServer"),
|
||||
openAPIController,
|
||||
rCache,
|
||||
grc,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
@ -355,6 +357,9 @@ func main() {
|
|||
|
||||
// verifies if the admission control is enabled and active
|
||||
server.RunAsync(stopCh)
|
||||
|
||||
go backwardcompatibility.AddLabels(pclient, pInformer.Kyverno().V1().GenerateRequests())
|
||||
go backwardcompatibility.AddCloneLabel(client, pInformer.Kyverno().V1().ClusterPolicies())
|
||||
<-stopCh
|
||||
|
||||
// by default http.Server waits indefinitely for connections to return to idle and then shuts down
|
||||
|
|
1
go.mod
1
go.mod
|
@ -27,6 +27,7 @@ require (
|
|||
github.com/onsi/gomega v1.8.1
|
||||
github.com/ory/go-acc v0.2.6 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/common v0.4.1
|
||||
github.com/sirupsen/logrus v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
|
|
4
go.sum
4
go.sum
|
@ -40,7 +40,9 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrU
|
|||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/ahmetb/gen-crd-api-reference-docs v0.1.5/go.mod h1:P/XzJ+c2+khJKNKABcm2biRwk2QAuwbLf8DlXuaL7WM=
|
||||
github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
|
@ -583,6 +585,7 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
|||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
|
@ -896,6 +899,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
|||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
146
pkg/backward_compatibility/add_labels.go
Normal file
146
pkg/backward_compatibility/add_labels.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package backwardcompatibility
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
dclient "github.com/kyverno/kyverno/pkg/dclient"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// AddLabels - adds labels to all the existing generate requests
|
||||
func AddLabels(client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer) {
|
||||
// Get all the GR's that are existing
|
||||
// Extract and Update all of them with the with the labels
|
||||
grList, err := grInformer.Lister().List(labels.NewSelector())
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to get generate request list")
|
||||
return
|
||||
}
|
||||
|
||||
for _, gr := range grList {
|
||||
|
||||
grLabels := gr.Labels
|
||||
if grLabels == nil || len(grLabels) == 0 {
|
||||
grLabels = make(map[string]string)
|
||||
}
|
||||
grLabels["generate.kyverno.io/policy-name"] = gr.Spec.Policy
|
||||
grLabels["generate.kyverno.io/resource-name"] = gr.Spec.Resource.Name
|
||||
grLabels["generate.kyverno.io/resource-kind"] = gr.Spec.Resource.Kind
|
||||
grLabels["generate.kyverno.io/resource-namespace"] = gr.Spec.Resource.Namespace
|
||||
|
||||
gr.SetLabels(grLabels)
|
||||
|
||||
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
log.Log.V(4).Info(fmt.Sprintf("failed to update the GR %v. error: %v", gr.Name, err))
|
||||
for n := 0; n <= 3; n++ {
|
||||
log.Log.V(4).Info(fmt.Sprintf("retrying to get GR %v", gr.Name))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
errInGettingGR := addLabelForGR(gr.Name, gr.Namespace, client, grInformer)
|
||||
if errInGettingGR != nil {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func addLabelForGR(name string, namespace string, client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer) error {
|
||||
gr, err := grInformer.Lister().GenerateRequests(namespace).Get(name)
|
||||
if err != nil {
|
||||
log.Log.Error(err, fmt.Sprintf("failed to update the GR %v", name))
|
||||
return err
|
||||
}
|
||||
|
||||
grLabels := gr.Labels
|
||||
if grLabels == nil || len(grLabels) == 0 {
|
||||
grLabels = make(map[string]string)
|
||||
}
|
||||
grLabels["generate.kyverno.io/policy-name"] = gr.Spec.Policy
|
||||
grLabels["generate.kyverno.io/resource-name"] = gr.Spec.Resource.Name
|
||||
grLabels["generate.kyverno.io/resource-kind"] = gr.Spec.Resource.Kind
|
||||
grLabels["generate.kyverno.io/resource-namespace"] = gr.Spec.Resource.Namespace
|
||||
|
||||
gr.SetLabels(grLabels)
|
||||
|
||||
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
log.Log.Error(err, fmt.Sprintf("failed to update the GR %v", gr.Name))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddCloneLabel - add label to the source resource about the new clone
|
||||
func AddCloneLabel(client *dclient.Client, pInformer kyvernoinformer.ClusterPolicyInformer) {
|
||||
// Get all the Generate Policies which has clone
|
||||
// Get the resource with Kind, NameSpace, Name
|
||||
// Add Policy name if label not found
|
||||
policies, err := pInformer.Lister().List(labels.NewSelector())
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to get policies")
|
||||
return
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.HasGenerate() {
|
||||
clone := rule.Generation.Clone
|
||||
if clone.Name != "" {
|
||||
namespace := clone.Namespace
|
||||
name := clone.Name
|
||||
kind := rule.Generation.Kind
|
||||
|
||||
obj, err := client.GetResource("", kind, namespace, name)
|
||||
if err != nil {
|
||||
log.Log.Error(err, fmt.Sprintf("source not found name:%v namespace:%v kind:%v", name, namespace, kind))
|
||||
continue
|
||||
}
|
||||
updateSource := true
|
||||
|
||||
// add label
|
||||
label := obj.GetLabels()
|
||||
if len(label) == 0 {
|
||||
label = make(map[string]string)
|
||||
label["generate.kyverno.io/clone-policy-name"] = policy.GetName()
|
||||
} else {
|
||||
if label["generate.kyverno.io/clone-policy-name"] != "" {
|
||||
policyNames := label["generate.kyverno.io/clone-policy-name"]
|
||||
if !strings.Contains(policyNames, policy.GetName()) {
|
||||
policyNames = policyNames + "," + policy.GetName()
|
||||
label["generate.kyverno.io/clone-policy-name"] = policyNames
|
||||
} else {
|
||||
updateSource = false
|
||||
}
|
||||
} else {
|
||||
label["generate.kyverno.io/clone-policy-name"] = policy.GetName()
|
||||
}
|
||||
}
|
||||
|
||||
if updateSource {
|
||||
log.Log.V(4).Info("updating existing clone source")
|
||||
obj.SetLabels(label)
|
||||
_, err = client.UpdateResource(obj.GetAPIVersion(), kind, namespace, obj, false)
|
||||
if err != nil {
|
||||
log.Log.Error(err, fmt.Sprintf("failed to update source name:%v namespace:%v kind:%v\n", obj.GetName(), obj.GetNamespace(), obj.GetKind()))
|
||||
return
|
||||
}
|
||||
log.Log.V(4).Info(fmt.Sprintf("updated source name:%v namespace:%v kind:%v\n", obj.GetName(), obj.GetNamespace(), obj.GetKind()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -144,10 +144,10 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
|
|||
if !r.Success {
|
||||
logger.V(4).Info("querying all generate requests")
|
||||
selector := labels.SelectorFromSet(labels.Set(map[string]string{
|
||||
"policyName": engineResponse.PolicyResponse.Policy,
|
||||
"resourceName": engineResponse.PolicyResponse.Resource.Name,
|
||||
"resourceKind": engineResponse.PolicyResponse.Resource.Kind,
|
||||
"ResourceNamespace": engineResponse.PolicyResponse.Resource.Namespace,
|
||||
"generate.kyverno.io/policy-name": engineResponse.PolicyResponse.Policy,
|
||||
"generate.kyverno.io/resource-name": engineResponse.PolicyResponse.Resource.Name,
|
||||
"generate.kyverno.io/resource-kind": engineResponse.PolicyResponse.Resource.Kind,
|
||||
"generate.kyverno.io/resource-namespace": engineResponse.PolicyResponse.Resource.Namespace,
|
||||
}))
|
||||
grList, err := c.grLister.List(selector)
|
||||
if err != nil {
|
||||
|
@ -179,9 +179,7 @@ func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateReque
|
|||
return statusControl.Success(gr, genResources)
|
||||
}
|
||||
|
||||
func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.PolicyContext, gr kyverno.GenerateRequest, applicableRules []string) ([]kyverno.ResourceSpec, error) {
|
||||
// List of generatedResources
|
||||
var genResources []kyverno.ResourceSpec
|
||||
func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.PolicyContext, gr kyverno.GenerateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, err error) {
|
||||
// Get the response as the actions to be performed on the resource
|
||||
// - - substitute values
|
||||
policy := policyContext.Policy
|
||||
|
@ -203,14 +201,13 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
|
|||
|
||||
startTime := time.Now()
|
||||
processExisting := false
|
||||
var genResource kyverno.ResourceSpec
|
||||
|
||||
if len(rule.MatchResources.Kinds) > 0 {
|
||||
if len(rule.MatchResources.Annotations) == 0 && rule.MatchResources.Selector == nil {
|
||||
processExisting = func() bool {
|
||||
rcreationTime := resource.GetCreationTimestamp()
|
||||
pcreationTime := policy.GetCreationTimestamp()
|
||||
return rcreationTime.Before(&pcreationTime)
|
||||
}()
|
||||
rcreationTime := resource.GetCreationTimestamp()
|
||||
pcreationTime := policy.GetCreationTimestamp()
|
||||
processExisting = rcreationTime.Before(&pcreationTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,15 +217,16 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
|
|||
return nil, err
|
||||
}
|
||||
|
||||
genResource, err := applyRule(log, c.client, rule, resource, jsonContext, policy.Name, gr, processExisting)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to apply generate rule", "policy", policy.Name,
|
||||
"rule", rule.Name, "resource", resource.GetName())
|
||||
return nil, err
|
||||
if !processExisting {
|
||||
genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy.Name, gr)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to apply generate rule", "policy", policy.Name,
|
||||
"rule", rule.Name, "resource", resource.GetName())
|
||||
return nil, err
|
||||
}
|
||||
ruleNameToProcessingTime[rule.Name] = time.Since(startTime)
|
||||
genResources = append(genResources, genResource)
|
||||
}
|
||||
|
||||
ruleNameToProcessingTime[rule.Name] = time.Since(startTime)
|
||||
genResources = append(genResources, genResource)
|
||||
}
|
||||
|
||||
if gr.Status.State == "" && len(genResources) > 0 {
|
||||
|
@ -300,12 +298,11 @@ func getResourceInfo(object map[string]interface{}) (kind, name, namespace, apiv
|
|||
return
|
||||
}
|
||||
|
||||
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest, processExisting bool) (kyverno.ResourceSpec, error) {
|
||||
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest) (kyverno.ResourceSpec, error) {
|
||||
var rdata map[string]interface{}
|
||||
var err error
|
||||
var mode ResourceMode
|
||||
var noGenResource kyverno.ResourceSpec
|
||||
|
||||
genUnst, err := getUnstrRule(rule.Generation.DeepCopy())
|
||||
if err != nil {
|
||||
return noGenResource, err
|
||||
|
@ -347,7 +344,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
}
|
||||
|
||||
if genClone != nil && len(genClone) != 0 {
|
||||
rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, genClone, client)
|
||||
rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy, genClone, client)
|
||||
} else {
|
||||
rdata, mode, err = manageData(logger, genAPIVersion, genKind, genNamespace, genName, genData, client)
|
||||
}
|
||||
|
@ -364,10 +361,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
return newGenResource, nil
|
||||
}
|
||||
|
||||
if processExisting {
|
||||
return noGenResource, nil
|
||||
}
|
||||
|
||||
// build the resource template
|
||||
newResource := &unstructured.Unstructured{}
|
||||
newResource.SetUnstructuredContent(rdata)
|
||||
|
@ -386,7 +379,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
label := newResource.GetLabels()
|
||||
label["policy.kyverno.io/policy-name"] = policy
|
||||
label["policy.kyverno.io/gr-name"] = gr.Name
|
||||
newResource.SetLabels(label)
|
||||
delete(label, "generate.kyverno.io/clone-policy-name")
|
||||
if mode == Create {
|
||||
if rule.Generation.Synchronize {
|
||||
label["policy.kyverno.io/synchronize"] = "enable"
|
||||
|
@ -396,6 +389,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
|
||||
// Reset resource version
|
||||
newResource.SetResourceVersion("")
|
||||
newResource.SetLabels(label)
|
||||
// Create the resource
|
||||
_, err = client.CreateResource(genAPIVersion, genKind, genNamespace, newResource, false)
|
||||
if err != nil {
|
||||
|
@ -405,7 +399,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
logger.V(2).Info("generated target resource")
|
||||
|
||||
} else if mode == Update {
|
||||
label := newResource.GetLabels()
|
||||
if rule.Generation.Synchronize {
|
||||
label["policy.kyverno.io/synchronize"] = "enable"
|
||||
} else {
|
||||
|
@ -417,7 +410,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
|||
newResource.SetLabels(label)
|
||||
_, err := client.UpdateResource(genAPIVersion, genKind, genNamespace, newResource, false)
|
||||
if err != nil {
|
||||
logger.Error(err, "updating existing resource")
|
||||
logger.Error(err, "failed to update resource")
|
||||
return noGenResource, err
|
||||
}
|
||||
logger.V(2).Info("updated target resource")
|
||||
|
@ -450,7 +443,7 @@ func manageData(log logr.Logger, apiVersion, kind, namespace, name string, data
|
|||
return updateObj.UnstructuredContent(), Update, nil
|
||||
}
|
||||
|
||||
func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, clone map[string]interface{}, client *dclient.Client) (map[string]interface{}, ResourceMode, error) {
|
||||
func manageClone(log logr.Logger, apiVersion, kind, namespace, name, policy string, clone map[string]interface{}, client *dclient.Client) (map[string]interface{}, ResourceMode, error) {
|
||||
rNamespace, _, err := unstructured.NestedString(clone, "namespace")
|
||||
if err != nil {
|
||||
return nil, Skip, fmt.Errorf("failed to find source namespace: %v", err)
|
||||
|
|
|
@ -343,3 +343,8 @@ func (c *Controller) syncGenerateRequest(key string) error {
|
|||
|
||||
return c.processGR(gr)
|
||||
}
|
||||
|
||||
// EnqueueGenerateRequestFromWebhook - enqueing generate requests from webhook
|
||||
func (c *Controller) EnqueueGenerateRequestFromWebhook(gr *kyverno.GenerateRequest) {
|
||||
c.enqueueGenerateRequest(gr)
|
||||
}
|
||||
|
|
|
@ -120,6 +120,46 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool, openAPIContro
|
|||
if !isLabelAndAnnotationsString(rule) {
|
||||
return fmt.Errorf("labels and annotations supports only string values, \"use double quotes around the non string values\"")
|
||||
}
|
||||
|
||||
// add label to source mentioned in policy
|
||||
if !mock && rule.Generation.Clone.Name != "" {
|
||||
obj, err := client.GetResource("", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name)
|
||||
if err != nil {
|
||||
log.Log.Error(err, fmt.Sprintf("source resource %s/%s/%s not found.", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
updateSource := true
|
||||
label := obj.GetLabels()
|
||||
|
||||
if len(label) == 0 {
|
||||
label = make(map[string]string)
|
||||
label["generate.kyverno.io/clone-policy-name"] = p.GetName()
|
||||
} else {
|
||||
if label["generate.kyverno.io/clone-policy-name"] != "" {
|
||||
policyNames := label["generate.kyverno.io/clone-policy-name"]
|
||||
if !strings.Contains(policyNames, p.GetName()) {
|
||||
policyNames = policyNames + "," + p.GetName()
|
||||
label["generate.kyverno.io/clone-policy-name"] = policyNames
|
||||
} else {
|
||||
updateSource = false
|
||||
}
|
||||
} else {
|
||||
label["generate.kyverno.io/clone-policy-name"] = p.GetName()
|
||||
}
|
||||
}
|
||||
|
||||
if updateSource {
|
||||
log.Log.V(4).Info("updating existing clone source")
|
||||
obj.SetLabels(label)
|
||||
_, err = client.UpdateResource(obj.GetAPIVersion(), rule.Generation.Kind, rule.Generation.Clone.Namespace, obj, false)
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to update source name:%v namespace:%v kind:%v", obj.GetName(), obj.GetNamespace(), obj.GetKind())
|
||||
continue
|
||||
}
|
||||
log.Log.V(4).Info("updated source name:%v namespace:%v kind:%v", obj.GetName(), obj.GetNamespace(), obj.GetKind())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !mock {
|
||||
|
|
|
@ -437,14 +437,20 @@ func deleteGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList [
|
|||
}
|
||||
|
||||
func updateGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*kyverno.GenerateRequest, logger logr.Logger) {
|
||||
for _, v := range grList {
|
||||
if policyKey == v.Spec.Policy {
|
||||
v.SetLabels(map[string]string{
|
||||
"policy-update": fmt.Sprintf("revision-count-%d", rand.Intn(100000)),
|
||||
})
|
||||
_, err := kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
|
||||
for _, gr := range grList {
|
||||
if policyKey == gr.Spec.Policy {
|
||||
grLabels := gr.Labels
|
||||
if grLabels == nil || len(grLabels) == 0 {
|
||||
grLabels = make(map[string]string)
|
||||
}
|
||||
grLabels["policy-update"] = fmt.Sprintf("revision-count-%d", rand.Intn(100000))
|
||||
// gr.SetLabels(map[string]string{
|
||||
// "policy-update": fmt.Sprintf("revision-count-%d", rand.Intn(100000)),
|
||||
// })
|
||||
gr.SetLabels(grLabels)
|
||||
_, err := kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to update gr", "name", v.GetName())
|
||||
logger.Error(err, "failed to update gr", "name", gr.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,10 +141,10 @@ func retryApplyResource(client *kyvernoclient.Clientset, grSpec kyverno.Generate
|
|||
if action == v1beta1.Create || action == v1beta1.Update {
|
||||
log.V(4).Info("querying all generate requests")
|
||||
selector := labels.SelectorFromSet(labels.Set(map[string]string{
|
||||
"policyName": grSpec.Policy,
|
||||
"resourceName": grSpec.Resource.Name,
|
||||
"resourceKind": grSpec.Resource.Kind,
|
||||
"ResourceNamespace": grSpec.Resource.Namespace,
|
||||
"generate.kyverno.io/policy-name": grSpec.Policy,
|
||||
"generate.kyverno.io/resource-name": grSpec.Resource.Name,
|
||||
"generate.kyverno.io/resource-kind": grSpec.Resource.Kind,
|
||||
"generate.kyverno.io/resource-namespace": grSpec.Resource.Namespace,
|
||||
}))
|
||||
grList, err := grLister.List(selector)
|
||||
if err != nil {
|
||||
|
@ -153,28 +153,31 @@ func retryApplyResource(client *kyvernoclient.Clientset, grSpec kyverno.Generate
|
|||
}
|
||||
|
||||
for _, v := range grList {
|
||||
if grSpec.Policy == v.Spec.Policy && grSpec.Resource.Name == v.Spec.Resource.Name && grSpec.Resource.Kind == v.Spec.Resource.Kind && grSpec.Resource.Namespace == v.Spec.Resource.Namespace {
|
||||
gr.SetLabels(map[string]string{
|
||||
"resources-update": "true",
|
||||
})
|
||||
|
||||
v.Spec.Context = gr.Spec.Context
|
||||
v.Spec.Policy = gr.Spec.Policy
|
||||
v.Spec.Resource = gr.Spec.Resource
|
||||
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isExist = true
|
||||
grLabels := gr.Labels
|
||||
if grLabels == nil || len(grLabels) == 0 {
|
||||
grLabels = make(map[string]string)
|
||||
}
|
||||
grLabels["resources-update"] = "true"
|
||||
gr.SetLabels(grLabels)
|
||||
v.Spec.Context = gr.Spec.Context
|
||||
v.Spec.Policy = gr.Spec.Policy
|
||||
v.Spec.Resource = gr.Spec.Resource
|
||||
|
||||
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isExist = true
|
||||
}
|
||||
|
||||
if !isExist {
|
||||
gr.SetGenerateName("gr-")
|
||||
gr.SetLabels(map[string]string{
|
||||
"policyName": grSpec.Policy,
|
||||
"resourceName": grSpec.Resource.Name,
|
||||
"resourceKind": grSpec.Resource.Kind,
|
||||
"ResourceNamespace": grSpec.Resource.Namespace,
|
||||
"generate.kyverno.io/policy-name": grSpec.Policy,
|
||||
"generate.kyverno.io/resource-name": grSpec.Resource.Name,
|
||||
"generate.kyverno.io/resource-kind": grSpec.Resource.Kind,
|
||||
"generate.kyverno.io/resource-namespace": grSpec.Resource.Namespace,
|
||||
})
|
||||
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Create(context.TODO(), &gr, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package webhooks
|
|||
|
||||
import (
|
||||
contextdefault "context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
kyvernoutils "github.com/kyverno/kyverno/pkg/utils"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/generate"
|
||||
|
@ -30,68 +32,122 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
|
|||
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
|
||||
logger.V(4).Info("incoming request")
|
||||
var engineResponses []*response.EngineResponse
|
||||
if request.Operation == v1beta1.Create || request.Operation == v1beta1.Update {
|
||||
if len(policies) == 0 {
|
||||
return
|
||||
}
|
||||
// convert RAW to unstructured
|
||||
new, old, err := kyvernoutils.ExtractResources(nil, request)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to extract resource")
|
||||
}
|
||||
|
||||
if len(policies) == 0 {
|
||||
return
|
||||
}
|
||||
// convert RAW to unstructured
|
||||
new, old, err := kyvernoutils.ExtractResources(nil, request)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to extract resource")
|
||||
}
|
||||
policyContext := engine.PolicyContext{
|
||||
NewResource: new,
|
||||
OldResource: old,
|
||||
AdmissionInfo: userRequestInfo,
|
||||
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
|
||||
ExcludeResourceFunc: ws.configHandler.ToFilter,
|
||||
ResourceCache: ws.resCache,
|
||||
JSONContext: ctx,
|
||||
}
|
||||
|
||||
policyContext := engine.PolicyContext{
|
||||
NewResource: new,
|
||||
OldResource: old,
|
||||
AdmissionInfo: userRequestInfo,
|
||||
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
|
||||
ExcludeResourceFunc: ws.configHandler.ToFilter,
|
||||
ResourceCache: ws.resCache,
|
||||
JSONContext: ctx,
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
var rules []response.RuleResponse
|
||||
policyContext.Policy = *policy
|
||||
engineResponse := engine.Generate(policyContext)
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if !rule.Success {
|
||||
ws.deleteGR(logger, engineResponse)
|
||||
continue
|
||||
for _, policy := range policies {
|
||||
var rules []response.RuleResponse
|
||||
policyContext.Policy = *policy
|
||||
engineResponse := engine.Generate(policyContext)
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if !rule.Success {
|
||||
ws.deleteGR(logger, engineResponse)
|
||||
continue
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
|
||||
rules = append(rules, rule)
|
||||
if len(rules) > 0 {
|
||||
engineResponse.PolicyResponse.Rules = rules
|
||||
// some generate rules do apply to the resource
|
||||
engineResponses = append(engineResponses, engineResponse)
|
||||
ws.statusListener.Update(generateStats{
|
||||
resp: engineResponse,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(rules) > 0 {
|
||||
engineResponse.PolicyResponse.Rules = rules
|
||||
// some generate rules do apply to the resource
|
||||
engineResponses = append(engineResponses, engineResponse)
|
||||
ws.statusListener.Update(generateStats{
|
||||
resp: engineResponse,
|
||||
})
|
||||
// Adds Generate Request to a channel(queue size 1000) to generators
|
||||
if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil {
|
||||
// report failure event
|
||||
for _, failedGR := range failedResponse {
|
||||
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, new)
|
||||
ws.eventGen.Add(events...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds Generate Request to a channel(queue size 1000) to generators
|
||||
if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil {
|
||||
// report failure event
|
||||
for _, failedGR := range failedResponse {
|
||||
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, new)
|
||||
ws.eventGen.Add(events...)
|
||||
}
|
||||
if request.Operation == v1beta1.Update {
|
||||
ws.handleUpdate(request)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//HandleUpdate handles admission-requests for update
|
||||
func (ws *WebhookServer) handleUpdate(request *v1beta1.AdmissionRequest) {
|
||||
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
|
||||
resource, err := enginutils.ConvertToUnstructured(request.OldObject.Raw)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to convert object resource to unstructured format")
|
||||
}
|
||||
|
||||
resLabels := resource.GetLabels()
|
||||
if resLabels["generate.kyverno.io/clone-policy-name"] != "" {
|
||||
policyNames := strings.Split(resLabels["generate.kyverno.io/clone-policy-name"], ",")
|
||||
for _, policyName := range policyNames {
|
||||
selector := labels.SelectorFromSet(labels.Set(map[string]string{
|
||||
"generate.kyverno.io/policy-name": policyName,
|
||||
}))
|
||||
|
||||
grList, err := ws.grLister.List(selector)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get generate request for the resource", "label", "generate.kyverno.io/policy-name")
|
||||
|
||||
}
|
||||
for _, gr := range grList {
|
||||
ws.grController.EnqueueGenerateRequestFromWebhook(gr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//HandleDelete handles admission-requests for delete
|
||||
func (ws *WebhookServer) handleDelete(request *v1beta1.AdmissionRequest) {
|
||||
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
|
||||
resource, err := enginutils.ConvertToUnstructured(request.OldObject.Raw)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to convert object resource to unstructured format")
|
||||
}
|
||||
|
||||
r, _ := json.Marshal(resource)
|
||||
fmt.Println(string(r))
|
||||
|
||||
resLabels := resource.GetLabels()
|
||||
if resLabels["app.kubernetes.io/managed-by"] == "kyverno" && resLabels["policy.kyverno.io/synchronize"] == "enable" && request.Operation == v1beta1.Delete {
|
||||
grName := resLabels["policy.kyverno.io/gr-name"]
|
||||
gr, err := ws.grLister.Get(grName)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get generate request", "name", grName)
|
||||
}
|
||||
ws.grController.EnqueueGenerateRequestFromWebhook(gr)
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.EngineResponse) {
|
||||
logger.V(4).Info("querying all generate requests")
|
||||
selector := labels.SelectorFromSet(labels.Set(map[string]string{
|
||||
"policyName": engineResponse.PolicyResponse.Policy,
|
||||
"resourceName": engineResponse.PolicyResponse.Resource.Name,
|
||||
"resourceKind": engineResponse.PolicyResponse.Resource.Kind,
|
||||
"ResourceNamespace": engineResponse.PolicyResponse.Resource.Namespace,
|
||||
"generate.kyverno.io/policy-name": engineResponse.PolicyResponse.Policy,
|
||||
"generate.kyverno.io/resource-name": engineResponse.PolicyResponse.Resource.Name,
|
||||
"generate.kyverno.io/resource-kind": engineResponse.PolicyResponse.Resource.Kind,
|
||||
"generate.kyverno.io/resource-namespace": engineResponse.PolicyResponse.Resource.Namespace,
|
||||
}))
|
||||
|
||||
grList, err := ws.grLister.List(selector)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
context2 "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/generate"
|
||||
"github.com/kyverno/kyverno/pkg/openapi"
|
||||
"github.com/kyverno/kyverno/pkg/policycache"
|
||||
"github.com/kyverno/kyverno/pkg/policyreport"
|
||||
|
@ -29,7 +30,7 @@ import (
|
|||
userinfo "github.com/kyverno/kyverno/pkg/userinfo"
|
||||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
"github.com/kyverno/kyverno/pkg/webhookconfig"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/generate"
|
||||
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/generate"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
rbacinformer "k8s.io/client-go/informers/rbac/v1"
|
||||
|
@ -104,7 +105,7 @@ type WebhookServer struct {
|
|||
prGenerator policyreport.GeneratorInterface
|
||||
|
||||
// generate request generator
|
||||
grGenerator *generate.Generator
|
||||
grGenerator *webhookgenerate.Generator
|
||||
|
||||
auditHandler AuditHandler
|
||||
|
||||
|
@ -116,6 +117,8 @@ type WebhookServer struct {
|
|||
|
||||
// resCache - controls creation and fetching of resource informer cache
|
||||
resCache resourcecache.ResourceCacheIface
|
||||
|
||||
grController *generate.Controller
|
||||
}
|
||||
|
||||
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
|
||||
|
@ -137,13 +140,14 @@ func NewWebhookServer(
|
|||
statusSync policystatus.Listener,
|
||||
configHandler config.Interface,
|
||||
prGenerator policyreport.GeneratorInterface,
|
||||
grGenerator *generate.Generator,
|
||||
grGenerator *webhookgenerate.Generator,
|
||||
auditHandler AuditHandler,
|
||||
supportMutateValidate bool,
|
||||
cleanUp chan<- struct{},
|
||||
log logr.Logger,
|
||||
openAPIController *openapi.Controller,
|
||||
resCache resourcecache.ResourceCacheIface,
|
||||
grc *generate.Controller,
|
||||
) (*WebhookServer, error) {
|
||||
|
||||
if tlsPair == nil {
|
||||
|
@ -182,6 +186,7 @@ func NewWebhookServer(
|
|||
webhookMonitor: webhookMonitor,
|
||||
prGenerator: prGenerator,
|
||||
grGenerator: grGenerator,
|
||||
grController: grc,
|
||||
auditHandler: auditHandler,
|
||||
log: log,
|
||||
openAPIController: openAPIController,
|
||||
|
@ -372,6 +377,9 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1
|
|||
|
||||
func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
logger := ws.log.WithName("Validate").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
|
||||
if request.Operation == v1beta1.Delete {
|
||||
ws.handleDelete(request)
|
||||
}
|
||||
|
||||
if !ws.supportMutateValidate {
|
||||
logger.Info("mutate and validate rules are not supported prior to Kubernetes 1.14.0")
|
||||
|
|
Loading…
Add table
Reference in a new issue