1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

Convert GenerateRequest to UpdateRequest for backward compatibility (#3730)

- Remove GenerateRequest Informer
 - Rename GenerateRequest to UpdateRequest in logs and vars
 - Fix initContainer leader election
 - Convert GenerateRequest to UpdateRequest in initContainer
 - Remove unused methods
 - Add printer column ruleType to UR


Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
shuting 2022-04-29 19:05:49 +08:00 committed by GitHub
parent de84b8071d
commit a4815f77c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 369 additions and 784 deletions

View file

@ -26,7 +26,7 @@ import (
// UpdateRequestStatus defines the observed state of UpdateRequest
type UpdateRequestStatus struct {
// State represents state of the generate request.
// State represents state of the update request.
State UpdateRequestState `json:"state" yaml:"state"`
// Specifies request status message.
@ -43,6 +43,7 @@ type UpdateRequestStatus struct {
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Policy",type="string",JSONPath=".spec.policy"
// +kubebuilder:printcolumn:name="RuleType",type="string",JSONPath=".spec.type"
// +kubebuilder:printcolumn:name="ResourceKind",type="string",JSONPath=".spec.resource.kind"
// +kubebuilder:printcolumn:name="ResourceName",type="string",JSONPath=".spec.resource.name"
// +kubebuilder:printcolumn:name="ResourceNamespace",type="string",JSONPath=".spec.resource.namespace"
@ -126,13 +127,13 @@ const (
// Pending - the Request is yet to be processed or resource has not been created.
Pending UpdateRequestState = "Pending"
// Failed - the Generate Request Controller failed to process the rules.
// Failed - the Update Request Controller failed to process the rules.
Failed UpdateRequestState = "Failed"
// Completed - the Generate Request Controller created resources defined in the policy.
// Completed - the Update Request Controller created resources defined in the policy.
Completed UpdateRequestState = "Completed"
// Skip - the Generate Request Controller skips to generate the resource.
// Skip - the Update Request Controller skips to generate the resource.
Skip UpdateRequestState = "Skip"
)

View file

@ -7388,6 +7388,9 @@ spec:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.type
name: RuleType
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
@ -7528,7 +7531,7 @@ spec:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
description: State represents state of the update request.
type: string
required:
- state

View file

@ -11,8 +11,11 @@ import (
"sync"
"time"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
engineUtils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/kyverno/kyverno/pkg/signal"
@ -22,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
"sigs.k8s.io/controller-runtime/pkg/log"
@ -49,8 +53,8 @@ const (
clusterPolicyReportKind string = "ClusterPolicyReport"
reportChangeRequestKind string = "ReportChangeRequest"
clusterReportChangeRequestKind string = "ClusterReportChangeRequest"
policyViolation string = "PolicyViolation"
clusterPolicyViolation string = "ClusterPolicyViolation"
convertGenerateRequest string = "ConvertGenerateRequest"
)
func main() {
@ -89,6 +93,12 @@ func main() {
os.Exit(1)
}
pclient, err := kyvernoclient.NewForConfig(clientConfig)
if err != nil {
setupLog.Error(err, "Failed to create client")
os.Exit(1)
}
// Exit for unsupported version of kubernetes cluster
if !utils.HigherThanKubernetesVersion(kubeClient.Discovery(), log.Log, 1, 16, 0) {
os.Exit(1)
@ -101,9 +111,7 @@ func main() {
{reportChangeRequestKind, ""},
{clusterReportChangeRequestKind, ""},
// clean up policy violation CRD
{policyViolation, ""},
{clusterPolicyViolation, ""},
{convertGenerateRequest, ""},
}
ctx, cancel := context.WithCancel(context.Background())
@ -138,7 +146,7 @@ func main() {
name := tls.GenerateRootCASecretName(certProps)
secret, err := kubeClient.CoreV1().Secrets(config.KyvernoNamespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
log.Log.Info("failed to fetch secret '%v': %v", name, err.Error())
log.Log.Info("failed to fetch root CA secret", "name", name, "error", err.Error())
if !errors.IsNotFound(err) {
os.Exit(1)
@ -155,7 +163,7 @@ func main() {
name = tls.GenerateTLSPairSecretName(certProps)
secret, err = kubeClient.CoreV1().Secrets(config.KyvernoNamespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
log.Log.Info("failed to fetch secret '%v': %v", name, err.Error())
log.Log.Info("failed to fetch TLS Pair secret", "name", name, "error", err.Error())
if !errors.IsNotFound(err) {
os.Exit(1)
@ -169,21 +177,17 @@ func main() {
}
}
_, err = kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Get(ctx, "kyvernopre-lock", metav1.GetOptions{})
if err != nil {
log.Log.Info("Lease 'kyvernopre-lock' not found. Starting clean-up...")
} else {
log.Log.Info("Clean-up complete. Leader exiting...")
os.Exit(0)
if err = acquireLeader(ctx, kubeClient); err != nil {
log.Log.Info("Failed to create lease 'kyvernopre-lock'")
os.Exit(1)
}
// use pipline to pass request to cleanup resources
// generate requests
in := gen(done, stopCh, requests...)
// process requests
// processing routine count : 2
p1 := process(client, done, stopCh, in)
p2 := process(client, done, stopCh, in)
p1 := process(client, pclient, done, stopCh, in)
p2 := process(client, pclient, done, stopCh, in)
// merge results from processing routines
for err := range merge(done, stopCh, p1, p2) {
if err != nil {
@ -197,18 +201,6 @@ func main() {
os.Exit(1)
}
lease := coord.Lease{
ObjectMeta: metav1.ObjectMeta{
Name: "kyvernopre-lock",
},
}
_, err = kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Create(ctx, &lease, metav1.CreateOptions{})
if err != nil {
log.Log.Info("Failed to create lease 'kyvernopre-lock'")
}
log.Log.Info("Clean-up complete. Leader exiting...")
os.Exit(0)
}
@ -221,7 +213,26 @@ func main() {
le.Run(ctx)
}
func executeRequest(client *client.Client, req request) error {
func acquireLeader(ctx context.Context, kubeClient kubernetes.Interface) error {
_, err := kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Get(ctx, "kyvernopre-lock", metav1.GetOptions{})
if err != nil {
log.Log.Info("Lease 'kyvernopre-lock' not found. Starting clean-up...")
} else {
log.Log.Info("Leader was elected, quiting")
os.Exit(0)
}
lease := coord.Lease{
ObjectMeta: metav1.ObjectMeta{
Name: "kyvernopre-lock",
},
}
_, err = kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Create(ctx, &lease, metav1.CreateOptions{})
return err
}
func executeRequest(client *client.Client, kyvernoclient *kyvernoclient.Clientset, req request) error {
switch req.kind {
case policyReportKind:
return removePolicyReport(client, req.kind)
@ -231,8 +242,8 @@ func executeRequest(client *client.Client, req request) error {
return removeReportChangeRequest(client, req.kind)
case clusterReportChangeRequestKind:
return removeClusterReportChangeRequest(client, req.kind)
case policyViolation, clusterPolicyViolation:
return removeViolationCRD(client)
case convertGenerateRequest:
return convertGR(kyvernoclient)
}
return nil
@ -272,14 +283,14 @@ func gen(done <-chan struct{}, stopCh <-chan struct{}, requests ...request) <-ch
}
// processes the requests
func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error {
func process(client *client.Client, kyvernoclient *kyvernoclient.Clientset, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error {
logger := log.Log.WithName("process")
out := make(chan error)
go func() {
defer close(out)
for req := range requests {
select {
case out <- executeRequest(client, req):
case out <- executeRequest(client, kyvernoclient, req):
case <-done:
logger.Info("done")
return
@ -419,21 +430,6 @@ func removeClusterReportChangeRequest(client *client.Client, kind string) error
return nil
}
func removeViolationCRD(client *client.Client) error {
if err := client.DeleteResource("", "CustomResourceDefinition", "", "policyviolations.kyverno.io", false); err != nil {
if !errors.IsNotFound(err) {
log.Log.Error(err, "failed to delete CRD policyViolation")
}
}
if err := client.DeleteResource("", "CustomResourceDefinition", "", "clusterpolicyviolations.kyverno.io", false); err != nil {
if !errors.IsNotFound(err) {
log.Log.Error(err, "failed to delete CRD clusterPolicyViolation")
}
}
return nil
}
func deleteResource(client *client.Client, apiversion, kind, ns, name string) {
err := client.DeleteResource(apiversion, kind, ns, name, false)
if err != nil && !errors.IsNotFound(err) {
@ -467,3 +463,65 @@ func addSelectorLabel(client *client.Client, apiversion, kind, ns, name string)
log.Log.Info("successfully updated resource labels", "kind", kind, "name", name)
}
func convertGR(pclient *kyvernoclient.Clientset) error {
logger := log.Log.WithName("convertGenerateRequest")
var errors []error
grs, err := pclient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
logger.Error(err, "failed to list update requests")
return err
}
for _, gr := range grs.Items {
var ur = &urkyverno.UpdateRequest{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "ur-",
Namespace: config.KyvernoNamespace,
Labels: gr.GetLabels(),
},
Spec: urkyverno.UpdateRequestSpec{
Type: urkyverno.Generate,
Policy: gr.Spec.Policy,
Resource: *gr.Spec.Resource.DeepCopy(),
Context: urkyverno.UpdateRequestSpecContext{
UserRequestInfo: urkyverno.RequestInfo{
Roles: gr.Spec.Context.UserRequestInfo.DeepCopy().Roles,
ClusterRoles: gr.Spec.Context.UserRequestInfo.DeepCopy().ClusterRoles,
AdmissionUserInfo: *gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.DeepCopy(),
},
AdmissionRequestInfo: urkyverno.AdmissionRequestInfoObject{
AdmissionRequest: gr.Spec.Context.AdmissionRequestInfo.DeepCopy().AdmissionRequest,
Operation: gr.Spec.Context.AdmissionRequestInfo.DeepCopy().Operation,
},
},
},
}
new, err := pclient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), ur, metav1.CreateOptions{})
if err != nil {
logger.Info("failed to create UpdateRequest", "GR namespace", gr.GetNamespace(), "GR name", gr.GetName(), "err", err.Error())
errors = append(errors, err)
continue
} else {
logger.Info("successfully created UpdateRequest", "GR namespace", gr.GetNamespace(), "GR name", gr.GetName())
}
new.Status.State = urkyverno.Pending
if _, err := pclient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending")
errors = append(errors, err)
continue
}
if err := pclient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(context.TODO(), gr.GetName(), metav1.DeleteOptions{}); err != nil {
errors = append(errors, err)
logger.Error(err, "failed to delete GR")
}
}
err = engineUtils.CombineErrors(errors)
return err
}

View file

@ -23,7 +23,6 @@ import (
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
"github.com/kyverno/kyverno/pkg/common"
backwardcompatibility "github.com/kyverno/kyverno/pkg/compatibility"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/cosign"
dclient "github.com/kyverno/kyverno/pkg/dclient"
@ -288,7 +287,6 @@ func main() {
client,
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
configData,
eventGenerator,
@ -305,22 +303,17 @@ func main() {
os.Exit(1)
}
// GENERATE REQUEST GENERATOR
grgen := webhookgenerate.NewGenerator(pclient,
pInformer.Kyverno().V1().GenerateRequests(),
urgen := webhookgenerate.NewGenerator(pclient,
pInformer.Kyverno().V1beta1().UpdateRequests(),
stopCh,
log.Log.WithName("UpdateRequestGenerator"))
// GENERATE CONTROLLER
// - applies generate rules on resources based on generate requests created by webhook
grc, err := background.NewController(
urc, err := background.NewController(
kubeClient,
pclient,
client,
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
eventGenerator,
kubeInformer.Core().V1().Namespaces(),
@ -332,15 +325,12 @@ func main() {
os.Exit(1)
}
// GENERATE REQUEST CLEANUP
// -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout
grcc, err := generatecleanup.NewController(
kubeClient,
pclient,
client,
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
kubeInformer.Core().V1().Namespaces(),
log.Log.WithName("GenerateCleanUpController"),
@ -443,7 +433,6 @@ func main() {
pclient,
client,
tlsPair,
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
pInformer.Kyverno().V1().ClusterPolicies(),
kubeInformer.Rbac().V1().RoleBindings(),
@ -457,12 +446,12 @@ func main() {
webhookMonitor,
configData,
reportReqGen,
grgen,
urgen,
auditHandler,
cleanUp,
log.Log.WithName("WebhookServer"),
openAPIController,
grc,
urc,
promConfig,
)
@ -477,7 +466,7 @@ func main() {
go certManager.Run(stopCh)
go policyCtrl.Run(2, prgen.ReconcileCh, stopCh)
go prgen.Run(1, stopCh)
go grc.Run(genWorkers, stopCh)
go urc.Run(genWorkers, stopCh)
go grcc.Run(1, stopCh)
}
@ -514,9 +503,6 @@ func main() {
go webhookMonitor.Run(webhookCfg, certRenewer, eventGenerator, stopCh)
}
go backwardcompatibility.AddLabels(pclient, pInformer.Kyverno().V1().GenerateRequests())
go backwardcompatibility.AddCloneLabel(client, pInformer.Kyverno().V1().ClusterPolicies())
pInformer.Start(stopCh)
kubeInformer.Start(stopCh)
kubeKyvernoInformer.Start(stopCh)

View file

@ -21,6 +21,9 @@ spec:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.type
name: RuleType
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
@ -179,7 +182,7 @@ spec:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
description: State represents state of the update request.
type: string
required:
- state

View file

@ -11479,6 +11479,9 @@ spec:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.type
name: RuleType
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
@ -11637,7 +11640,7 @@ spec:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
description: State represents state of the update request.
type: string
required:
- state

View file

@ -11426,6 +11426,9 @@ spec:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.type
name: RuleType
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
@ -11584,7 +11587,7 @@ spec:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
description: State represents state of the update request.
type: string
required:
- state

View file

@ -417,7 +417,7 @@ UpdateRequestState
</em>
</td>
<td>
<p>State represents state of the generate request.</p>
<p>State represents state of the update request.</p>
</td>
</tr>
<tr>

View file

@ -21,8 +21,8 @@ type StatusControl struct {
Client kyvernoclient.Interface
}
//Failed sets gr status.state to failed with message
func (sc StatusControl) Failed(gr urkyverno.UpdateRequest, message string, genResources []kyverno.ResourceSpec) error {
//Failed sets ur status.state to failed with message
func (sc StatusControl) Failed(ur urkyverno.UpdateRequest, message string, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Failed,
Message: message,
@ -36,17 +36,17 @@ func (sc StatusControl) Failed(gr urkyverno.UpdateRequest, message string, genRe
"replace",
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
_, err := PatchUpdateRequest(&ur, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to patch update request status", "name", gr.Name)
log.Log.Error(err, "failed to patch update request status", "name", ur.Name)
return err
}
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Failed))
log.Log.V(3).Info("updated update request status", "name", ur.Name, "status", string(kyverno.Failed))
return nil
}
// Success sets the gr status.state to completed and clears message
func (sc StatusControl) Success(gr urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
// Success sets the ur status.state to completed and clears message
func (sc StatusControl) Success(ur urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Completed,
Message: "",
@ -61,17 +61,17 @@ func (sc StatusControl) Success(gr urkyverno.UpdateRequest, genResources []kyver
"replace",
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
_, err := PatchUpdateRequest(&ur, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to patch update request status", "name", gr.Name)
log.Log.Error(err, "failed to patch update request status", "name", ur.Name)
return err
}
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Completed))
log.Log.V(3).Info("updated update request status", "name", ur.Name, "status", string(kyverno.Completed))
return nil
}
// Success sets the gr status.state to completed and clears message
func (sc StatusControl) Skip(gr urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
// Success sets the ur status.state to completed and clears message
func (sc StatusControl) Skip(ur urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Skip,
Message: "",
@ -86,11 +86,11 @@ func (sc StatusControl) Skip(gr urkyverno.UpdateRequest, genResources []kyverno.
"replace",
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
_, err := PatchUpdateRequest(&ur, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
log.Log.Error(err, "failed to update UR status", "name", ur.Name)
return err
}
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Skip))
log.Log.V(3).Info("updated UR status", "name", ur.Name, "status", string(kyverno.Skip))
return nil
}

View file

@ -11,15 +11,15 @@ import (
"k8s.io/apimachinery/pkg/types"
)
// PatchGenerateRequest patches a generate request object
func PatchGenerateRequest(gr *urkyverno.UpdateRequest, patch jsonutils.Patch, client kyvernoclient.Interface, subresources ...string) (*urkyverno.UpdateRequest, error) {
// PatchUpdateRequest patches a update request object
func PatchUpdateRequest(ur *urkyverno.UpdateRequest, patch jsonutils.Patch, client kyvernoclient.Interface, subresources ...string) (*urkyverno.UpdateRequest, error) {
data, err := patch.ToPatchBytes()
if nil != err {
return gr, err
return ur, err
}
newGR, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Patch(context.TODO(), gr.Name, types.JSONPatchType, data, metav1.PatchOptions{}, subresources...)
newUR, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Patch(context.TODO(), ur.Name, types.JSONPatchType, data, metav1.PatchOptions{}, subresources...)
if err != nil {
return gr, err
return ur, err
}
return newGR, nil
return newUR, nil
}

View file

@ -9,17 +9,17 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func (c *Controller) processGR(gr urkyverno.UpdateRequest) error {
logger := c.log.WithValues("kind", gr.Kind, "namespace", gr.Namespace, "name", gr.Name)
func (c *Controller) processUR(ur urkyverno.UpdateRequest) error {
logger := c.log.WithValues("kind", ur.Kind, "namespace", ur.Namespace, "name", ur.Name)
// 1- Corresponding policy has been deleted
// then we don't delete the generated resources
// 2- The trigger resource is deleted, then delete the generated resources
if !ownerResourceExists(logger, c.client, gr) {
deleteGR := false
if !ownerResourceExists(logger, c.client, ur) {
deleteUR := false
// check retry count in annotaion
grAnnotations := gr.Annotations
if val, ok := grAnnotations["generate.kyverno.io/retry-count"]; ok {
urAnnotations := ur.Annotations
if val, ok := urAnnotations["generate.kyverno.io/retry-count"]; ok {
retryCount, err := strconv.ParseUint(val, 10, 32)
if err != nil {
logger.Error(err, "unable to convert retry-count")
@ -27,45 +27,45 @@ func (c *Controller) processGR(gr urkyverno.UpdateRequest) error {
}
if retryCount >= 5 {
deleteGR = true
deleteUR = true
}
}
if deleteGR {
if err := deleteGeneratedResources(logger, c.client, gr); err != nil {
if deleteUR {
if err := deleteGeneratedResources(logger, c.client, ur); err != nil {
return err
}
// - trigger-resource is deleted
// - generated-resources are deleted
// - > Now delete the GenerateRequest CR
return c.control.Delete(gr.Name)
// - > Now delete the UpdateRequest CR
return c.control.Delete(ur.Name)
}
}
return nil
}
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr urkyverno.UpdateRequest) bool {
_, err := client.GetResource("", gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
func ownerResourceExists(log logr.Logger, client *dclient.Client, ur urkyverno.UpdateRequest) bool {
_, err := client.GetResource("", ur.Spec.Resource.Kind, ur.Spec.Resource.Namespace, ur.Spec.Resource.Name)
// trigger resources has been deleted
if apierrors.IsNotFound(err) {
return false
}
if err != nil {
log.Error(err, "failed to get resource", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
log.Error(err, "failed to get resource", "genKind", ur.Spec.Resource.Kind, "genNamespace", ur.Spec.Resource.Namespace, "genName", ur.Spec.Resource.Name)
}
// if there was an error while querying the resources we don't delete the generated resources
// but expect the deletion in next reconciliation loop
return true
}
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr urkyverno.UpdateRequest) error {
for _, genResource := range gr.Status.GeneratedResources {
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, ur urkyverno.UpdateRequest) error {
for _, genResource := range ur.Status.GeneratedResources {
err := client.DeleteResource("", genResource.Kind, genResource.Namespace, genResource.Name, false)
if err != nil && !apierrors.IsNotFound(err) {
return err
}
log.V(3).Info("generated resource deleted", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
log.V(3).Info("generated resource deleted", "genKind", ur.Spec.Resource.Kind, "genNamespace", ur.Spec.Resource.Namespace, "genName", ur.Spec.Resource.Name)
}
return nil
}

View file

@ -40,12 +40,12 @@ type Controller struct {
kyvernoClient *kyvernoclient.Clientset
pInformer kyvernoinformer.ClusterPolicyInformer
grInformer kyvernoinformer.GenerateRequestInformer
urInformer urkyvernoinformer.UpdateRequestInformer
// control is used to delete the GR
// control is used to delete the UR
control ControlInterface
// gr that need to be synced
// ur that need to be synced
queue workqueue.RateLimitingInterface
// pLister can list/get cluster policy from the shared informer's store
@ -54,9 +54,6 @@ type Controller struct {
// npLister can list/get namespace policy from the shared informer's store
npLister kyvernolister.PolicyLister
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// urLister can list/get update request from the shared informer's store
urLister urkyvernolister.UpdateRequestNamespaceLister
@ -69,9 +66,6 @@ type Controller struct {
// pSynced returns true if the Namespace policy has been synced at least once
npSynced cache.InformerSynced
// grSynced returns true if the generate request store has been synced at least once
grSynced cache.InformerSynced
// urSynced returns true if the update request store has been synced at least once
urSynced cache.InformerSynced
@ -89,7 +83,6 @@ func NewController(
client *dclient.Client,
pInformer kyvernoinformer.ClusterPolicyInformer,
npInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
namespaceInformer coreinformers.NamespaceInformer,
log logr.Logger,
@ -98,7 +91,7 @@ func NewController(
kyvernoClient: kyvernoclient,
client: client,
pInformer: pInformer,
grInformer: grInformer,
urInformer: urInformer,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request-cleanup"),
log: log,
}
@ -107,13 +100,11 @@ func NewController(
c.pLister = pInformer.Lister()
c.npLister = npInformer.Lister()
c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace)
c.urLister = urInformer.Lister().UpdateRequests(config.KyvernoNamespace)
c.nsLister = namespaceInformer.Lister()
c.pSynced = pInformer.Informer().HasSynced
c.npSynced = npInformer.Informer().HasSynced
c.grSynced = grInformer.Informer().HasSynced
c.urSynced = urInformer.Informer().HasSynced
c.nsListerSynced = namespaceInformer.Informer().HasSynced
@ -131,77 +122,74 @@ func (c *Controller) deletePolicy(obj interface{}) {
}
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
if !ok {
logger.Info("Tombstone contained object that is not a Generate Request", "obj", obj)
logger.Info("Tombstone contained object that is not a Update Request", "obj", obj)
return
}
}
logger.V(4).Info("deleting policy", "name", p.Name)
// clean up the GR
// Get the corresponding GR
// get the list of GR for the current Policy version
rules := autogen.ComputeRules(p)
generatePolicyWithClone := pkgCommon.ProcessDeletePolicyForCloneGenerateRule(rules, c.client, p.GetName(), logger)
// get the generated resource name from generate request for log
// get the generated resource name from update request for log
selector := labels.SelectorFromSet(labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: p.Name,
}))
grList, err := c.urLister.List(selector)
urList, err := c.urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "label", urkyverno.URGeneratePolicyLabel)
logger.Error(err, "failed to get update request for the resource", "label", urkyverno.URGeneratePolicyLabel)
return
}
for _, gr := range grList {
for _, generatedResource := range gr.Status.GeneratedResources {
for _, ur := range urList {
for _, generatedResource := range ur.Status.GeneratedResources {
logger.V(4).Info("retaining resource", "apiVersion", generatedResource.APIVersion, "kind", generatedResource.Kind, "name", generatedResource.Name, "namespace", generatedResource.Namespace)
}
}
if !generatePolicyWithClone {
grs, err := c.urLister.GetUpdateRequestsForClusterPolicy(p.Name)
urs, err := c.urLister.GetUpdateRequestsForClusterPolicy(p.Name)
if err != nil {
logger.Error(err, "failed to generate request for the policy", "name", p.Name)
logger.Error(err, "failed to update request for the policy", "name", p.Name)
return
}
for _, gr := range grs {
logger.V(4).Info("enqueue the gr for cleanup", "gr name", gr.Name)
c.addUR(gr)
for _, ur := range urs {
logger.V(4).Info("enqueue the ur for cleanup", "ur name", ur.Name)
c.addUR(ur)
}
}
}
func (c *Controller) addUR(obj interface{}) {
gr := obj.(*urkyverno.UpdateRequest)
c.enqueue(gr)
ur := obj.(*urkyverno.UpdateRequest)
c.enqueue(ur)
}
func (c *Controller) updateUR(old, cur interface{}) {
gr := cur.(*urkyverno.UpdateRequest)
c.enqueue(gr)
ur := cur.(*urkyverno.UpdateRequest)
c.enqueue(ur)
}
func (c *Controller) deleteUR(obj interface{}) {
logger := c.log
gr, ok := obj.(*urkyverno.UpdateRequest)
ur, ok := obj.(*urkyverno.UpdateRequest)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj)
return
}
gr, ok = tombstone.Obj.(*urkyverno.UpdateRequest)
ur, ok = tombstone.Obj.(*urkyverno.UpdateRequest)
if !ok {
logger.Info("ombstone contained object that is not a Generate Request", "obj", obj)
logger.Info("ombstone contained object that is not a Update Request", "obj", obj)
return
}
}
for _, resource := range gr.Status.GeneratedResources {
for _, resource := range ur.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "failed to fetch generated resource", "resource", resource.Name)
@ -216,29 +204,29 @@ func (c *Controller) deleteUR(obj interface{}) {
}
}
logger.V(4).Info("deleting Generate Request CR", "name", gr.Name)
logger.V(4).Info("deleting Update Request CR", "name", ur.Name)
// sync Handler will remove it from the queue
c.enqueue(gr)
c.enqueue(ur)
}
func (c *Controller) enqueue(gr *urkyverno.UpdateRequest) {
func (c *Controller) enqueue(ur *urkyverno.UpdateRequest) {
// skip enqueueing Pending requests
if gr.Status.State == urkyverno.Pending {
if ur.Status.State == urkyverno.Pending {
return
}
logger := c.log
key, err := cache.MetaNamespaceKeyFunc(gr)
key, err := cache.MetaNamespaceKeyFunc(ur)
if err != nil {
logger.Error(err, "failed to extract key")
return
}
logger.V(5).Info("enqueue generate request", "name", gr.Name)
logger.V(5).Info("enqueue update request", "name", ur.Name)
c.queue.Add(key)
}
//Run starts the generate-request re-conciliation loop
//Run starts the update-request re-conciliation loop
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger := c.log
defer utilruntime.HandleCrash()
@ -246,7 +234,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger.Info("starting")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced, c.urSynced, c.npSynced, c.nsListerSynced) {
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.urSynced, c.npSynced, c.nsListerSynced) {
logger.Info("failed to sync informer cache")
return
}
@ -255,7 +243,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
DeleteFunc: c.deletePolicy, // we only cleanup if the policy is delete
})
c.grInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
c.urInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addUR,
UpdateFunc: c.updateUR,
DeleteFunc: c.deleteUR,
@ -269,7 +257,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
}
// worker runs a worker thread that just de-queues items, processes them, and marks them done.
// It enforces that the syncGenerateRequest is never invoked concurrently with the same key.
// It enforces that the syncUpdateRequest is never invoked concurrently with the same key.
func (c *Controller) worker() {
for c.processNextWorkItem() {
}
@ -281,7 +269,7 @@ func (c *Controller) processNextWorkItem() bool {
return false
}
defer c.queue.Done(key)
err := c.syncGenerateRequest(key.(string))
err := c.syncUpdateRequest(key.(string))
c.handleErr(err, key)
return true
@ -295,43 +283,43 @@ func (c *Controller) handleErr(err error, key interface{}) {
}
if apierrors.IsNotFound(err) {
logger.V(4).Info("dropping generate request", "key", key, "error", err.Error())
logger.V(4).Info("dropping update request", "key", key, "error", err.Error())
c.queue.Forget(key)
return
}
if c.queue.NumRequeues(key) < maxRetries {
logger.V(3).Info("retrying generate request", "key", key, "error", err.Error())
logger.V(3).Info("retrying update request", "key", key, "error", err.Error())
c.queue.AddRateLimited(key)
return
}
logger.Error(err, "failed to cleanup generate request", "key", key)
logger.Error(err, "failed to cleanup update request", "key", key)
c.queue.Forget(key)
}
func (c *Controller) syncGenerateRequest(key string) error {
func (c *Controller) syncUpdateRequest(key string) error {
logger := c.log.WithValues("key", key)
var err error
startTime := time.Now()
logger.V(4).Info("started syncing generate request", "startTime", startTime)
logger.V(4).Info("started syncing update request", "startTime", startTime)
defer func() {
logger.V(4).Info("finished syncing generate request", "processingTIme", time.Since(startTime).String())
logger.V(4).Info("finished syncing update request", "processingTIme", time.Since(startTime).String())
}()
_, grName, err := cache.SplitMetaNamespaceKey(key)
_, urName, err := cache.SplitMetaNamespaceKey(key)
if apierrors.IsNotFound(err) {
logger.Info("generate request has been deleted")
logger.Info("update request has been deleted")
return nil
}
if err != nil {
return err
}
gr, err := c.urLister.Get(grName)
ur, err := c.urLister.Get(urName)
if err != nil {
return err
}
pNamespace, pName, err := cache.SplitMetaNamespaceKey(gr.Spec.Policy)
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
if err != nil {
return err
}
@ -342,8 +330,8 @@ func (c *Controller) syncGenerateRequest(key string) error {
if !apierrors.IsNotFound(err) {
return err
}
logger.Error(err, "failed to get clusterpolicy, deleting the generate request")
err = c.control.Delete(gr.Name)
logger.Error(err, "failed to get clusterpolicy, deleting the update request")
err = c.control.Delete(ur.Name)
if err != nil {
return err
}
@ -355,13 +343,13 @@ func (c *Controller) syncGenerateRequest(key string) error {
if !apierrors.IsNotFound(err) {
return err
}
logger.Error(err, "failed to get policy, deleting the generate request")
err = c.control.Delete(gr.Name)
logger.Error(err, "failed to get policy, deleting the update request")
err = c.control.Delete(ur.Name)
if err != nil {
return err
}
return nil
}
}
return c.processGR(*gr)
return c.processUR(*ur)
}

View file

@ -43,7 +43,7 @@ type GenerateController struct {
// typed client for Kyverno CRDs
kyvernoClient *kyvernoclient.Clientset
// grStatusControl is used to update GR status
// urStatusControl is used to update UR status
statusControl common.StatusControlInterface
// event generator interface
@ -51,9 +51,6 @@ type GenerateController struct {
log logr.Logger
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// urLister can list/get update request from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
@ -75,7 +72,6 @@ func NewGenerateController(
client *dclient.Client,
policyLister kyvernolister.ClusterPolicyLister,
npolicyLister kyvernolister.PolicyLister,
grLister kyvernolister.GenerateRequestNamespaceLister,
urLister urlister.UpdateRequestNamespaceLister,
eventGen event.Interface,
nsLister corelister.NamespaceLister,
@ -91,7 +87,6 @@ func NewGenerateController(
Config: dynamicConfig,
policyLister: policyLister,
npolicyLister: npolicyLister,
grLister: grLister,
urLister: urLister,
}
@ -101,28 +96,28 @@ func NewGenerateController(
return &c, nil
}
func (c *GenerateController) ProcessGR(gr *urkyverno.UpdateRequest) error {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "apiVersion", gr.Spec.Resource.APIVersion, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
logger := c.log.WithValues("name", ur.Name, "policy", ur.Spec.Policy, "kind", ur.Spec.Resource.Kind, "apiVersion", ur.Spec.Resource.APIVersion, "namespace", ur.Spec.Resource.Namespace, "name", ur.Spec.Resource.Name)
var err error
var resource *unstructured.Unstructured
var genResources []kyverno.ResourceSpec
var precreatedResource bool
// 1 - Check if the resource exists
resource, err = common.GetResource(c.client, gr.Spec, c.log)
resource, err = common.GetResource(c.client, ur.Spec, c.log)
if err != nil {
// Don't update status
// re-queueing the GR by updating the annotation
// re-queueing the UR by updating the annotation
// retry - 5 times
logger.V(3).Info("resource does not exist or is pending creation, re-queueing", "details", err.Error(), "retry")
updateAnnotation := true
grAnnotations := gr.Annotations
urAnnotations := ur.Annotations
if len(grAnnotations) == 0 {
grAnnotations = make(map[string]string)
grAnnotations["generate.kyverno.io/retry-count"] = "1"
if len(urAnnotations) == 0 {
urAnnotations = make(map[string]string)
urAnnotations["generate.kyverno.io/retry-count"] = "1"
} else {
if val, ok := grAnnotations["generate.kyverno.io/retry-count"]; ok {
if val, ok := urAnnotations["generate.kyverno.io/retry-count"]; ok {
sleepCountInt64, err := strconv.ParseUint(val, 10, 32)
if err != nil {
logger.Error(err, "unable to convert retry-count")
@ -135,20 +130,20 @@ func (c *GenerateController) ProcessGR(gr *urkyverno.UpdateRequest) error {
} else {
time.Sleep(time.Second * time.Duration(sleepCountInt))
incrementedCountString := strconv.Itoa(sleepCountInt)
grAnnotations["generate.kyverno.io/retry-count"] = incrementedCountString
urAnnotations["generate.kyverno.io/retry-count"] = incrementedCountString
}
} else {
time.Sleep(time.Second * 1)
grAnnotations["generate.kyverno.io/retry-count"] = "1"
urAnnotations["generate.kyverno.io/retry-count"] = "1"
}
}
if updateAnnotation {
gr.SetAnnotations(grAnnotations)
_, err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(contextdefault.TODO(), gr, metav1.UpdateOptions{})
ur.SetAnnotations(urAnnotations)
_, err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(contextdefault.TODO(), ur, metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update annotation in generate request for the resource", "generate request", gr.Name)
logger.Error(err, "failed to update annotation in update request for the resource", "update request", ur.Name)
return err
}
}
@ -163,38 +158,38 @@ func (c *GenerateController) ProcessGR(gr *urkyverno.UpdateRequest) error {
// 2 - Apply the generate policy on the resource
namespaceLabels := pkgcommon.GetNamespaceSelectorsFromNamespaceLister(resource.GetKind(), resource.GetNamespace(), c.nsLister, logger)
genResources, precreatedResource, err = c.applyGenerate(*resource, *gr, namespaceLabels)
genResources, precreatedResource, err = c.applyGenerate(*resource, *ur, namespaceLabels)
if err != nil {
// Need not update the status when policy doesn't apply on resource, because all the generate requests are removed by the cleanup controller
// Need not update the status when policy doesn't apply on resource, because all the update requests are removed by the cleanup controller
if strings.Contains(err.Error(), doesNotApply) {
logger.V(4).Info("skipping updating status of generate request")
logger.V(4).Info("skipping updating status of update request")
return nil
}
// 3 - Report failure Events
events := common.FailedEvents(err, gr.Spec.Policy, "", event.GeneratePolicyController, resource, logger)
events := common.FailedEvents(err, ur.Spec.Policy, "", event.GeneratePolicyController, resource, logger)
c.eventGen.Add(events...)
}
// 4 - Update Status
return updateStatus(c.statusControl, *gr, err, genResources, precreatedResource)
return updateStatus(c.statusControl, *ur, err, genResources, precreatedResource)
}
const doesNotApply = "policy does not apply to resource"
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, gr urkyverno.UpdateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "apiVersion", gr.Spec.Resource.APIVersion, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, ur urkyverno.UpdateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
logger := c.log.WithValues("name", ur.Name, "policy", ur.Spec.Policy, "kind", ur.Spec.Resource.Kind, "apiVersion", ur.Spec.Resource.APIVersion, "namespace", ur.Spec.Resource.Namespace, "name", ur.Spec.Resource.Name)
// Get the list of rules to be applied
// get policy
// build context
logger.V(3).Info("applying generate policy rule")
policy, err := c.getPolicySpec(gr)
policy, err := c.getPolicySpec(ur)
if err != nil {
if apierrors.IsNotFound(err) {
for _, e := range gr.Status.GeneratedResources {
for _, e := range ur.Status.GeneratedResources {
resp, err := c.client.GetResource(e.APIVersion, e.Kind, e.Namespace, e.Name)
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "failed to find generated resource", "name", e.Name)
@ -214,39 +209,39 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, g
return nil, false, err
}
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &gr, &policy, &resource, c.Config, namespaceLabels, logger)
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &ur, &policy, &resource, c.Config, namespaceLabels, logger)
if err != nil {
return nil, precreatedResource, err
}
// check if the policy still applies to the resource
engineResponse := engine.GenerateResponse(policyContext, gr)
engineResponse := engine.GenerateResponse(policyContext, ur)
if len(engineResponse.PolicyResponse.Rules) == 0 {
logger.V(4).Info(doesNotApply)
return nil, false, errors.New(doesNotApply)
}
var applicableRules []string
// Removing GR if rule is failed. Used when the generate condition failed but gr exist
// Removing UR if rule is failed. Used when the generate condition failed but ur exist
for _, r := range engineResponse.PolicyResponse.Rules {
if r.Status != response.RuleStatusPass {
logger.V(4).Info("querying all generate requests")
logger.V(4).Info("querying all update requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: engineResponse.PolicyResponse.Policy.Name,
"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.urLister.List(selector)
urList, err := c.urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
logger.Error(err, "failed to get update request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
continue
}
for _, v := range grList {
for _, v := range urList {
err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{})
if err != nil {
logger.Error(err, "failed to delete generate request")
logger.Error(err, "failed to delete update request")
}
}
} else {
@ -255,14 +250,14 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, g
}
// Apply the generate rule on resource
return c.applyGeneratePolicy(logger, policyContext, gr, applicableRules)
return c.applyGeneratePolicy(logger, policyContext, ur, applicableRules)
}
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
func (c *GenerateController) getPolicySpec(gr urkyverno.UpdateRequest) (kyverno.ClusterPolicy, error) {
func (c *GenerateController) getPolicySpec(ur urkyverno.UpdateRequest) (kyverno.ClusterPolicy, error) {
var policy kyverno.ClusterPolicy
pNamespace, pName, err := cache.SplitMetaNamespaceKey(gr.Spec.Policy)
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
if err != nil {
return policy, err
}
@ -287,18 +282,17 @@ func (c *GenerateController) getPolicySpec(gr urkyverno.UpdateRequest) (kyverno.
}
}
func updateStatus(statusControl common.StatusControlInterface, gr urkyverno.UpdateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
func updateStatus(statusControl common.StatusControlInterface, ur urkyverno.UpdateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
if err != nil {
return statusControl.Failed(gr, err.Error(), genResources)
return statusControl.Failed(ur, err.Error(), genResources)
} else if precreatedResource {
return statusControl.Skip(gr, genResources)
return statusControl.Skip(ur, genResources)
}
// Generate request successfully processed
return statusControl.Success(gr, genResources)
return statusControl.Success(ur, genResources)
}
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, gr urkyverno.UpdateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, ur urkyverno.UpdateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
// Get the response as the actions to be performed on the resource
// - - substitute values
policy := policyContext.Policy
@ -342,7 +336,7 @@ func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext
}
if !processExisting {
genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy.GetName(), gr)
genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy.GetName(), ur)
if err != nil {
log.Error(err, "failed to apply generate rule", "policy", policy.GetName(),
"rule", rule.Name, "resource", resource.GetName(), "suggestion", "users need to grant Kyverno's service account additional privileges")
@ -376,7 +370,7 @@ 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 urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, ur urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode
@ -448,7 +442,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
// Add Synchronize label
label := newResource.GetLabels()
label["policy.kyverno.io/policy-name"] = policy
label["policy.kyverno.io/gr-name"] = gr.Name
label["policy.kyverno.io/gr-name"] = ur.Name
delete(label, "generate.kyverno.io/clone-policy-name")
if mode == Create {
if rule.Generation.Synchronize {

View file

@ -15,9 +15,9 @@ func (c *Controller) ProcessUR(ur *urkyverno.UpdateRequest) error {
case urkyverno.Generate:
ctrl, _ := generate.NewGenerateController(c.kyvernoClient, c.client,
c.policyLister, c.npolicyLister, c.grLister, c.urLister, c.eventGen, c.nsLister, c.log, c.Config,
c.policyLister, c.npolicyLister, c.urLister, c.eventGen, c.nsLister, c.log, c.Config,
)
return ctrl.ProcessGR(ur)
return ctrl.ProcessUR(ur)
}
return nil
}

View file

@ -45,10 +45,10 @@ type Controller struct {
// event generator interface
eventGen event.Interface
// grStatusControl is used to update GR status
// urStatusControl is used to update UR status
statusControl common.StatusControlInterface
// GR that need to be synced
// UR that need to be synced
queue workqueue.RateLimitingInterface
// policyLister can list/get cluster policy from the shared informer's store
@ -57,9 +57,6 @@ type Controller struct {
// policyLister can list/get Namespace policy from the shared informer's store
npolicyLister kyvernolister.PolicyLister
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// urLister can list/get update request from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
@ -72,9 +69,6 @@ type Controller struct {
// policySynced returns true if the Namespace policy store has been synced at least once
npolicySynced cache.InformerSynced
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// urSynced returns true if the Update Request store has been synced at least once
urSynced cache.InformerSynced
@ -92,7 +86,6 @@ func NewController(
client *dclient.Client,
policyInformer kyvernoinformer.ClusterPolicyInformer,
npolicyInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
eventGen event.Interface,
namespaceInformer coreinformers.NamespaceInformer,
@ -116,14 +109,6 @@ func NewController(
c.npolicySynced = npolicyInformer.Informer().HasSynced
c.grSynced = grInformer.Informer().HasSynced
grInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addGR,
UpdateFunc: c.updateGR,
DeleteFunc: c.deleteGR,
})
c.urSynced = urInformer.Informer().HasSynced
urInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addUR,
@ -133,7 +118,6 @@ func NewController(
c.policyLister = policyInformer.Lister()
c.npolicyLister = npolicyInformer.Lister()
c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace)
c.urLister = urInformer.Lister().UpdateRequests(config.KyvernoNamespace)
c.nsLister = namespaceInformer.Lister()
@ -148,7 +132,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
defer c.queue.ShutDown()
defer c.log.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, c.policySynced, c.grSynced, c.urSynced, c.npolicySynced, c.nsSynced) {
if !cache.WaitForCacheSync(stopCh, c.policySynced, c.urSynced, c.npolicySynced, c.nsSynced) {
c.log.Info("failed to sync informer cache")
return
}
@ -179,7 +163,7 @@ func (c *Controller) processNextWorkItem() bool {
}
defer c.queue.Done(key)
err := c.syncGenerateRequest(key.(string))
err := c.syncUpdateRequest(key.(string))
c.handleErr(err, key)
return true
}
@ -193,53 +177,48 @@ func (c *Controller) handleErr(err error, key interface{}) {
if apierrors.IsNotFound(err) {
c.queue.Forget(key)
logger.V(4).Info("Dropping generate request from the queue", "key", key, "error", err.Error())
logger.V(4).Info("Dropping update request from the queue", "key", key, "error", err.Error())
return
}
if c.queue.NumRequeues(key) < maxRetries {
logger.V(3).Info("retrying generate request", "key", key, "error", err.Error())
logger.V(3).Info("retrying update request", "key", key, "error", err.Error())
c.queue.AddRateLimited(key)
return
}
logger.Error(err, "failed to process generate request", "key", key)
logger.Error(err, "failed to process update request", "key", key)
c.queue.Forget(key)
}
func (c *Controller) syncGenerateRequest(key string) error {
func (c *Controller) syncUpdateRequest(key string) error {
logger := c.log
var err error
startTime := time.Now()
logger.V(4).Info("started sync", "key", key, "startTime", startTime)
defer func() {
logger.V(4).Info("completed sync generate request", "key", key, "processingTime", time.Since(startTime).String())
logger.V(4).Info("completed sync update request", "key", key, "processingTime", time.Since(startTime).String())
}()
_, grName, err := cache.SplitMetaNamespaceKey(key)
_, urName, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
return err
}
gr, err := c.urLister.Get(grName)
ur, err := c.urLister.Get(urName)
if err != nil {
if apierrors.IsNotFound(err) {
return nil
}
logger.Error(err, "failed to fetch generate request", "key", key)
logger.Error(err, "failed to fetch update request", "key", key)
return err
}
return c.ProcessUR(gr)
return c.ProcessUR(ur)
}
// EnqueueGenerateRequestFromWebhook - enqueueing generate requests from webhook
func (c *Controller) EnqueueGenerateRequestFromWebhook(gr *kyverno.GenerateRequest) {
c.enqueueGenerateRequest(gr)
}
func (c *Controller) enqueueGenerateRequest(obj interface{}) {
func (c *Controller) enqueueUpdateRequest(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
c.log.Error(err, "failed to extract name")
@ -277,79 +256,22 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
logger.V(4).Info("updating policy", "name", oldP.Name)
grs, err := c.urLister.GetUpdateRequestsForClusterPolicy(curP.Name)
urs, err := c.urLister.GetUpdateRequestsForClusterPolicy(curP.Name)
if err != nil {
logger.Error(err, "failed to generate request for policy", "name", curP.Name)
logger.Error(err, "failed to update request for policy", "name", curP.Name)
return
}
// re-evaluate the GR as the policy was updated
for _, gr := range grs {
gr.Spec.Context.AdmissionRequestInfo.Operation = admissionv1.Update
c.enqueueGenerateRequest(gr)
// re-evaluate the UR as the policy was updated
for _, ur := range urs {
ur.Spec.Context.AdmissionRequestInfo.Operation = admissionv1.Update
c.enqueueUpdateRequest(ur)
}
}
func (c *Controller) addGR(obj interface{}) {
gr := obj.(*kyverno.GenerateRequest)
c.enqueueGenerateRequest(gr)
}
func (c *Controller) updateGR(old, cur interface{}) {
oldGr := old.(*kyverno.GenerateRequest)
curGr := cur.(*kyverno.GenerateRequest)
if oldGr.ResourceVersion == curGr.ResourceVersion {
// Periodic resync will send update events for all known Namespace.
// Two different versions of the same replica set will always have different RVs.
return
}
// only process the ones that are in "Pending"/"Completed" state
// if the Generate Request fails due to incorrect policy, it will be requeued during policy update
if curGr.Status.State != kyverno.Pending {
return
}
c.enqueueGenerateRequest(curGr)
}
func (c *Controller) deleteGR(obj interface{}) {
logger := c.log
gr, ok := obj.(*kyverno.GenerateRequest)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj)
return
}
gr, ok = tombstone.Obj.(*kyverno.GenerateRequest)
if !ok {
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj)
return
}
}
for _, resource := range gr.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name)
continue
}
if r != nil && r.GetLabels()["policy.kyverno.io/synchronize"] == "enable" {
if err := c.client.DeleteResource(r.GetAPIVersion(), r.GetKind(), r.GetNamespace(), r.GetName(), false); err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName())
}
}
}
logger.V(3).Info("deleting update request", "name", gr.Name)
// sync Handler will remove it from the queue
c.enqueueGenerateRequest(gr)
}
func (c *Controller) addUR(obj interface{}) {
ur := obj.(*urkyverno.UpdateRequest)
c.enqueueGenerateRequest(ur)
c.enqueueUpdateRequest(ur)
}
func (c *Controller) updateUR(old, cur interface{}) {
@ -361,31 +283,31 @@ func (c *Controller) updateUR(old, cur interface{}) {
return
}
// only process the ones that are in "Pending"/"Completed" state
// if the Generate Request fails due to incorrect policy, it will be requeued during policy update
// if the UPDATE Request fails due to incorrect policy, it will be requeued during policy update
if curUr.Status.State != urkyverno.Pending {
return
}
c.enqueueGenerateRequest(curUr)
c.enqueueUpdateRequest(curUr)
}
func (c *Controller) deleteUR(obj interface{}) {
logger := c.log
gr, ok := obj.(*urkyverno.UpdateRequest)
ur, ok := obj.(*urkyverno.UpdateRequest)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj)
return
}
gr, ok = tombstone.Obj.(*urkyverno.UpdateRequest)
ur, ok = tombstone.Obj.(*urkyverno.UpdateRequest)
if !ok {
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj)
logger.Info("tombstone contained object that is not a Update Request CR", "obj", obj)
return
}
}
if gr.Spec.GetRequestType() == urkyverno.Generate {
for _, resource := range gr.Status.GeneratedResources {
if ur.Spec.GetRequestType() == urkyverno.Generate {
for _, resource := range ur.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name)
@ -399,9 +321,9 @@ func (c *Controller) deleteUR(obj interface{}) {
}
}
logger.V(3).Info("deleting update request", "name", gr.Name)
logger.V(3).Info("deleting update request", "name", ur.Name)
}
// sync Handler will remove it from the queue
c.enqueueGenerateRequest(gr)
c.enqueueUpdateRequest(ur)
}

View file

@ -1,147 +0,0 @@
package backwardcompatibility
import (
"context"
"fmt"
"strings"
"time"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
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 len(grLabels) == 0 {
grLabels = make(map[string]string)
}
grLabels[urkyverno.URGeneratePolicyLabel] = 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
}
}
}
}
}
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 len(grLabels) == 0 {
grLabels = make(map[string]string)
}
grLabels[urkyverno.URGeneratePolicyLabel] = 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 autogen.ComputeRules(policy) {
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()))
}
}
}
}
}
}

View file

@ -70,9 +70,6 @@ type PolicyController struct {
// npLister can list/get namespace policy from the shared informer's store
npLister kyvernolister.PolicyLister
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestLister
// urLister can list/get update request from the shared informer's store
urLister urkyvernolister.UpdateRequestLister
@ -88,9 +85,6 @@ type PolicyController struct {
// nsListerSynced returns true if the namespace store has been synced at least once
nsListerSynced cache.InformerSynced
// grListerSynced returns true if the generate request store has been synced at least once
grListerSynced cache.InformerSynced
// urListerSynced returns true if the update request store has been synced at least once
urListerSynced cache.InformerSynced
@ -119,7 +113,6 @@ func NewPolicyController(
client *client.Client,
pInformer kyvernoinformer.ClusterPolicyInformer,
npInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
configHandler config.Interface,
eventGen event.Interface,
@ -160,14 +153,12 @@ func NewPolicyController(
pc.npLister = npInformer.Lister()
pc.nsLister = namespaces.Lister()
pc.grLister = grInformer.Lister()
pc.urLister = urInformer.Lister()
pc.pListerSynced = pInformer.Informer().HasSynced
pc.npListerSynced = npInformer.Informer().HasSynced
pc.nsListerSynced = namespaces.Informer().HasSynced
pc.grListerSynced = grInformer.Informer().HasSynced
pc.urListerSynced = urInformer.Informer().HasSynced
// resource manager
@ -431,7 +422,7 @@ func (pc *PolicyController) Run(workers int, reconcileCh <-chan bool, stopCh <-c
logger.Info("starting")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.npListerSynced, pc.nsListerSynced, pc.grListerSynced, pc.urListerSynced) {
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.npListerSynced, pc.nsListerSynced, pc.urListerSynced) {
logger.Info("failed to sync informer cache")
return
}

View file

@ -1,6 +1,7 @@
package webhookconfig
import (
"context"
"encoding/json"
"fmt"
"reflect"
@ -198,17 +199,19 @@ func (wrc *Register) Check() error {
// Remove removes all webhook configurations
func (wrc *Register) Remove(cleanUp chan<- struct{}) {
defer close(cleanUp)
// delete Lease object to let init container do the cleanup
err := wrc.kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Delete(context.TODO(), "kyvernopre-lock", metav1.DeleteOptions{})
if err != nil && errorsapi.IsNotFound(err) {
wrc.log.WithName("cleanup").Error(err, "failed to clean up Lease lock")
}
if !wrc.cleanupKyvernoResource() {
return
}
wrc.removeWebhookConfigurations()
wrc.removeSecrets()
err := wrc.client.DeleteResource("coordination.k8s.io/v1", "Lease", config.KyvernoNamespace, "kyvernopre-lock", false)
if err != nil && errorsapi.IsNotFound(err) {
wrc.log.WithName("cleanup").Error(err, "failed to clean up Lease lock")
}
}
// UpdateWebhookConfigurations updates resource webhook configurations dynamically
@ -272,7 +275,7 @@ func (wrc *Register) ValidateWebhookConfigurations(namespace, name string) error
return json.Unmarshal([]byte(webhooks), &webhookCfgs)
}
// cleanupKyvernoResource returns true if Kyverno lease is terminating
// cleanupKyvernoResource returns true if Kyverno is terminating
func (wrc *Register) cleanupKyvernoResource() bool {
logger := wrc.log.WithName("cleanupKyvernoResource")
deploy, err := wrc.client.GetResource("", "Deployment", config.KyvernoNamespace, config.KyvernoDeploymentName)

View file

@ -1,198 +0,0 @@
package generate
import (
"context"
"time"
backoff "github.com/cenkalti/backoff"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// GenerateRequests provides interface to manage generate requests
type GenerateRequests interface {
Apply(gr kyverno.GenerateRequestSpec, action admissionv1.Operation) error
}
// GeneratorChannel ...
type GeneratorChannel struct {
spec urkyverno.UpdateRequestSpec
action admissionv1.Operation
}
// Generator defines the implementation to mange generate request resource
type Generator struct {
// channel to receive request
client *kyvernoclient.Clientset
stopCh <-chan struct{}
log logr.Logger
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
grSynced cache.InformerSynced
// urLister can list/get update request from the shared informer's store
urLister urkyvernolister.UpdateRequestNamespaceLister
urSynced cache.InformerSynced
}
// NewGenerator returns a new instance of Generate-Request resource generator
func NewGenerator(client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer, urInformer urkyvernoinformer.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{
client: client,
stopCh: stopCh,
log: log,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
}
return gen
}
// Apply creates generate request resource (blocking call if channel is full)
func (g *Generator) Apply(gr urkyverno.UpdateRequestSpec, action admissionv1.Operation) error {
logger := g.log
logger.V(4).Info("creating Generate Request", "request", gr)
// Update to channel
message := GeneratorChannel{
action: action,
spec: gr,
}
go g.processApply(message)
return nil
}
func (g *Generator) processApply(m GeneratorChannel) {
if err := g.generate(m.spec, m.action); err != nil {
logger.Error(err, "failed to generate request CR")
}
}
func (g *Generator) generate(grSpec urkyverno.UpdateRequestSpec, action admissionv1.Operation) error {
// create/update a generate request
if err := retryApplyResource(g.client, grSpec, g.log, action, g.grLister, g.urLister); err != nil {
return err
}
return nil
}
// -> receiving channel to take requests to create request
// use worker pattern to read and create the CR resource
func retryApplyResource(client *kyvernoclient.Clientset, grSpec urkyverno.UpdateRequestSpec,
log logr.Logger, action admissionv1.Operation, grLister kyvernolister.GenerateRequestNamespaceLister,
urLister urkyvernolister.UpdateRequestNamespaceLister) error {
var i int
var err error
_, policyName, err := cache.SplitMetaNamespaceKey(grSpec.Policy)
if err != nil {
return err
}
applyResource := func() error {
gr := urkyverno.UpdateRequest{
Spec: grSpec,
}
gr.SetNamespace(config.KyvernoNamespace)
// Initial state "Pending"
// generate requests created in kyverno namespace
isExist := false
if action == admissionv1.Create || action == admissionv1.Update {
log.V(4).Info("querying all generate requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: policyName,
"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 := urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "kind", grSpec.Resource.Kind, "name", grSpec.Resource.Name, "namespace", grSpec.Resource.Namespace)
return err
}
for _, v := range grList {
grLabels := gr.Labels
if 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
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
if err != nil {
return err
}
new.Status.State = urkyverno.Pending
if _, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending")
}
isExist = true
}
if !isExist {
gr.SetGenerateName("gr-")
gr.SetLabels(map[string]string{
urkyverno.URGeneratePolicyLabel: policyName,
"generate.kyverno.io/resource-name": grSpec.Resource.Name,
"generate.kyverno.io/resource-kind": grSpec.Resource.Kind,
"generate.kyverno.io/resource-namespace": grSpec.Resource.Namespace,
})
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), &gr, metav1.CreateOptions{})
if err != nil {
return err
}
new.Status.State = urkyverno.Pending
if _, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending")
}
}
}
log.V(4).Info("retrying update generate request CR", "retryCount", i, "name", gr.GetGenerateName(), "namespace", gr.GetNamespace())
i++
return err
}
exbackoff := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
Multiplier: 1.5,
MaxInterval: time.Second,
MaxElapsedTime: 3 * time.Second,
Clock: backoff.SystemClock,
}
exbackoff.Reset()
err = backoff.Retry(applyResource, exbackoff)
if err != nil {
return err
}
return nil
}

View file

@ -75,10 +75,10 @@ func (ws *WebhookServer) handleGenerate(
go ws.registerPolicyExecutionDurationMetricGenerate(logger, string(request.Operation), policy, *engineResponse)
}
if failedResponse := applyGenerateRequest(request, urkyverno.Generate, ws.grGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
if failedResponse := applyUpdateRequest(request, urkyverno.Generate, ws.urGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
// report failure event
for _, failedGR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, policyContext.NewResource)
for _, failedUR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create Update Request: %v", failedUR.err), failedUR.ur, policyContext.NewResource)
ws.eventGen.Add(events...)
}
}
@ -126,7 +126,7 @@ func (ws *WebhookServer) handleUpdateGenerateSourceResource(resLabels map[string
_, err := ws.kyvernoClient.KyvernoV1().ClusterPolicies().Get(contextdefault.TODO(), policyName, metav1.GetOptions{})
if err != nil {
if strings.Contains(err.Error(), "not found") {
logger.V(4).Info("skipping update of generate request as policy is deleted")
logger.V(4).Info("skipping update of update request as policy is deleted")
} else {
logger.Error(err, "failed to get generate policy", "Name", policyName)
}
@ -135,46 +135,46 @@ func (ws *WebhookServer) handleUpdateGenerateSourceResource(resLabels map[string
urkyverno.URGeneratePolicyLabel: policyName,
}))
grList, err := ws.urLister.List(selector)
urList, err := ws.urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "label", urkyverno.URGeneratePolicyLabel)
logger.Error(err, "failed to get update request for the resource", "label", urkyverno.URGeneratePolicyLabel)
return
}
for _, gr := range grList {
ws.updateAnnotationInGR(gr, logger)
for _, ur := range urList {
ws.updateAnnotationInUR(ur, logger)
}
}
}
}
// updateAnnotationInGR - function used to update GR annotation
// updating GR will trigger reprocessing of GR and recreation/updation of generated resource
func (ws *WebhookServer) updateAnnotationInGR(gr *urkyverno.UpdateRequest, logger logr.Logger) {
grAnnotations := gr.Annotations
if len(grAnnotations) == 0 {
grAnnotations = make(map[string]string)
// updateAnnotationInUR - function used to update UR annotation
// updating UR will trigger reprocessing of UR and recreation/updation of generated resource
func (ws *WebhookServer) updateAnnotationInUR(ur *urkyverno.UpdateRequest, logger logr.Logger) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = make(map[string]string)
}
ws.mu.Lock()
grAnnotations["generate.kyverno.io/updation-time"] = time.Now().String()
gr.SetAnnotations(grAnnotations)
urAnnotations["generate.kyverno.io/updation-time"] = time.Now().String()
ur.SetAnnotations(urAnnotations)
ws.mu.Unlock()
patch := jsonutils.NewPatch(
"/metadata/annotations",
"replace",
gr.Annotations,
ur.Annotations,
)
new, err := gencommon.PatchGenerateRequest(gr, patch, ws.kyvernoClient)
new, err := gencommon.PatchUpdateRequest(ur, patch, ws.kyvernoClient)
if err != nil {
logger.Error(err, "failed to update generate request update-time annotations for the resource", "generate request", gr.Name)
logger.Error(err, "failed to update update request update-time annotations for the resource", "update request", ur.Name)
return
}
new.Status.State = urkyverno.Pending
if _, err := ws.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(contextdefault.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending", "update request", gr.Name)
logger.Error(err, "failed to set UpdateRequest state to Pending", "update request", ur.Name)
}
}
@ -230,13 +230,13 @@ func (ws *WebhookServer) handleUpdateGenerateTargetResource(request *admissionv1
}
if enqueueBool {
grName := resLabels["policy.kyverno.io/gr-name"]
gr, err := ws.urLister.Get(grName)
urName := resLabels["policy.kyverno.io/gr-name"]
ur, err := ws.urLister.Get(urName)
if err != nil {
logger.Error(err, "failed to get generate request", "name", grName)
logger.Error(err, "failed to get update request", "name", urName)
return
}
ws.updateAnnotationInGR(gr, logger)
ws.updateAnnotationInUR(ur, logger)
}
}
@ -346,22 +346,22 @@ func (ws *WebhookServer) handleDelete(request *admissionv1.AdmissionRequest) {
resLabels := resource.GetLabels()
if resLabels["app.kubernetes.io/managed-by"] == "kyverno" && request.Operation == admissionv1.Delete {
grName := resLabels["policy.kyverno.io/gr-name"]
gr, err := ws.urLister.Get(grName)
urName := resLabels["policy.kyverno.io/gr-name"]
ur, err := ws.urLister.Get(urName)
if err != nil {
logger.Error(err, "failed to get generate request", "name", grName)
logger.Error(err, "failed to get update request", "name", urName)
return
}
if gr.Spec.Type == urkyverno.Mutate {
if ur.Spec.Type == urkyverno.Mutate {
return
}
ws.updateAnnotationInGR(gr, logger)
ws.updateAnnotationInUR(ur, logger)
}
}
func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.EngineResponse) {
logger.V(4).Info("querying all generate requests")
logger.V(4).Info("querying all update requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: engineResponse.PolicyResponse.Policy.Name,
"generate.kyverno.io/resource-name": engineResponse.PolicyResponse.Resource.Name,
@ -369,22 +369,22 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.E
"generate.kyverno.io/resource-namespace": engineResponse.PolicyResponse.Resource.Namespace,
}))
grList, err := ws.urLister.List(selector)
urList, err := ws.urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
logger.Error(err, "failed to get update request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
return
}
for _, v := range grList {
for _, v := range urList {
err := ws.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{})
if err != nil {
logger.Error(err, "failed to update gr")
logger.Error(err, "failed to update ur")
}
}
}
func applyGenerateRequest(request *admissionv1.AdmissionRequest, ruleType urkyverno.RequestType, gnGenerator updaterequest.Interface, userRequestInfo urkyverno.RequestInfo,
action admissionv1.Operation, engineResponses ...*response.EngineResponse) (failedGenerateRequest []generateRequestResponse) {
func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType urkyverno.RequestType, grGenerator updaterequest.Interface, userRequestInfo urkyverno.RequestInfo,
action admissionv1.Operation, engineResponses ...*response.EngineResponse) (failedUpdateRequest []updateRequestResponse) {
requestBytes, err := json.Marshal(request)
if err != nil {
@ -396,9 +396,9 @@ func applyGenerateRequest(request *admissionv1.AdmissionRequest, ruleType urkyve
}
for _, er := range engineResponses {
gr := transform(admissionRequestInfo, userRequestInfo, er, ruleType)
if err := gnGenerator.Apply(gr, action); err != nil {
failedGenerateRequest = append(failedGenerateRequest, generateRequestResponse{gr: gr, err: err})
ur := transform(admissionRequestInfo, userRequestInfo, er, ruleType)
if err := grGenerator.Apply(ur, action); err != nil {
failedUpdateRequest = append(failedUpdateRequest, updateRequestResponse{ur: ur, err: err})
}
}
@ -413,7 +413,7 @@ func transform(admissionRequestInfo urkyverno.AdmissionRequestInfoObject, userRe
PolicyNameNamespaceKey = er.PolicyResponse.Policy.Name
}
gr := urkyverno.UpdateRequestSpec{
ur := urkyverno.UpdateRequestSpec{
Type: ruleType,
Policy: PolicyNameNamespaceKey,
Resource: kyverno.ResourceSpec{
@ -428,30 +428,22 @@ func transform(admissionRequestInfo urkyverno.AdmissionRequestInfoObject, userRe
},
}
return gr
return ur
}
type generateRequestResponse struct {
gr urkyverno.UpdateRequestSpec
type updateRequestResponse struct {
ur urkyverno.UpdateRequestSpec
err error
}
func (resp generateRequestResponse) info() string {
return strings.Join([]string{resp.gr.Resource.Kind, resp.gr.Resource.Namespace, resp.gr.Resource.Name}, "/")
}
func (resp generateRequestResponse) error() string {
return resp.err.Error()
}
func failedEvents(err error, gr urkyverno.UpdateRequestSpec, resource unstructured.Unstructured) []event.Info {
func failedEvents(err error, ur urkyverno.UpdateRequestSpec, resource unstructured.Unstructured) []event.Info {
re := event.Info{}
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Reason = event.PolicyFailed.String()
re.Source = event.GeneratePolicyController
re.Message = fmt.Sprintf("policy %s failed to apply: %v", gr.Policy, err)
re.Message = fmt.Sprintf("policy %s failed to apply: %v", ur.Policy, err)
return []event.Info{re}
}

View file

@ -14,7 +14,6 @@ import (
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urlister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
@ -45,12 +44,6 @@ type WebhookServer struct {
client *client.Client
kyvernoClient *kyvernoclient.Clientset
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// urLister can list/get update requests from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
@ -105,8 +98,8 @@ type WebhookServer struct {
// policy report generator
prGenerator policyreport.GeneratorInterface
// generate request generator
grGenerator webhookgenerate.Interface
// update request generator
urGenerator webhookgenerate.Interface
nsLister listerv1.NamespaceLister
@ -119,7 +112,7 @@ type WebhookServer struct {
openAPIController *openapi.Controller
grController *background.Controller
urController *background.Controller
promConfig *metrics.PromConfig
@ -132,7 +125,6 @@ func NewWebhookServer(
kyvernoClient *kyvernoclient.Clientset,
client *client.Client,
tlsPair *tlsutils.PemPair,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urinformer.UpdateRequestInformer,
pInformer kyvernoinformer.ClusterPolicyInformer,
rbInformer rbacinformer.RoleBindingInformer,
@ -146,12 +138,12 @@ func NewWebhookServer(
webhookMonitor *webhookconfig.Monitor,
configHandler config.Interface,
prGenerator policyreport.GeneratorInterface,
grGenerator webhookgenerate.Interface,
urGenerator webhookgenerate.Interface,
auditHandler AuditHandler,
cleanUp chan<- struct{},
log logr.Logger,
openAPIController *openapi.Controller,
grc *background.Controller,
urc *background.Controller,
promConfig *metrics.PromConfig,
) (*WebhookServer, error) {
if tlsPair == nil {
@ -164,8 +156,6 @@ func NewWebhookServer(
ws := &WebhookServer{
client: client,
kyvernoClient: kyvernoClient,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
pSynced: pInformer.Informer().HasSynced,
@ -186,8 +176,8 @@ func NewWebhookServer(
cleanUp: cleanUp,
webhookMonitor: webhookMonitor,
prGenerator: prGenerator,
grGenerator: grGenerator,
grController: grc,
urGenerator: urGenerator,
urController: urc,
auditHandler: auditHandler,
log: log,
openAPIController: openAPIController,
@ -265,7 +255,7 @@ func (ws *WebhookServer) buildPolicyContext(request *admissionv1.AdmissionReques
// RunAsync TLS server in separate thread and returns control immediately
func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) {
if !cache.WaitForCacheSync(stopCh, ws.grSynced, ws.urSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
if !cache.WaitForCacheSync(stopCh, ws.urSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
ws.log.Info("failed to sync informer cache")
}
go func() {

View file

@ -58,9 +58,9 @@ func (ws *WebhookServer) handleMutateExisting(request *admissionv1.AdmissionRequ
go ws.registerPolicyExecutionDurationMetricMutate(logger, string(request.Operation), policy, *engineResponse)
}
if failedResponse := applyGenerateRequest(request, urkyverno.Mutate, ws.grGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
for _, failedGR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create update request: %v", failedGR.err), failedGR.gr, policyContext.NewResource)
if failedResponse := applyUpdateRequest(request, urkyverno.Mutate, ws.urGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
for _, failedUR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create update request: %v", failedUR.err), failedUR.ur, policyContext.NewResource)
ws.eventGen.Add(events...)
}
}

View file

@ -9,9 +9,7 @@ import (
"github.com/go-logr/logr"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
admissionv1 "k8s.io/api/admission/v1"
@ -21,7 +19,7 @@ import (
"k8s.io/client-go/tools/cache"
)
// GenerateRequests provides interface to manage update requests
// UpdateRequest provides interface to manage update requests
type Interface interface {
Apply(gr urkyverno.UpdateRequestSpec, action admissionv1.Operation) error
}
@ -37,22 +35,17 @@ type Generator struct {
client *kyvernoclient.Clientset
stopCh <-chan struct{}
log logr.Logger
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
grSynced cache.InformerSynced
urLister urkyvernolister.UpdateRequestNamespaceLister
urSynced cache.InformerSynced
}
// NewGenerator returns a new instance of UpdateRequest resource generator
func NewGenerator(client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer, urInformer urkyvernoinformer.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
func NewGenerator(client *kyvernoclient.Clientset, urInformer urkyvernoinformer.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{
client: client,
stopCh: stopCh,
log: log,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
}
@ -60,13 +53,13 @@ func NewGenerator(client *kyvernoclient.Clientset, grInformer kyvernoinformer.Ge
}
// Apply creates update request resource
func (g *Generator) Apply(gr urkyverno.UpdateRequestSpec, action admissionv1.Operation) error {
func (g *Generator) Apply(ur urkyverno.UpdateRequestSpec, action admissionv1.Operation) error {
logger := g.log
logger.V(4).Info("reconcile Update Request", "request", gr)
logger.V(4).Info("reconcile Update Request", "request", ur)
message := info{
action: action,
spec: gr,
spec: ur,
}
go g.processApply(message)
return nil
@ -82,7 +75,7 @@ func (g *Generator) Run(workers int, stopCh <-chan struct{}) {
logger.V(4).Info("shutting down")
}()
if !cache.WaitForCacheSync(stopCh, g.grSynced, g.urSynced) {
if !cache.WaitForCacheSync(stopCh, g.urSynced) {
logger.Info("failed to sync informer cache")
return
}

View file

@ -327,7 +327,7 @@ func Test_Mutate_Existing(t *testing.T) {
for _, test := range mutateExistingTests {
By(fmt.Sprintf("\nStart Mutate Existing Tests: %s", test.TestDescription))
By("======Cleaning up resources======")
By("\nCleaning up resources")
By("Deleting Cluster Policies...")
e2eClient.CleanClusterPolicies(policyGVR)
@ -363,7 +363,7 @@ func Test_Mutate_Existing(t *testing.T) {
})
Expect(err).NotTo(HaveOccurred())
By("======Done cleaning up resources======")
By("Done cleaning up resources\n")
By(fmt.Sprintf("Creating target Namespace: %s...", test.TargetNamespace))
_, err = e2eClient.CreateClusteredResourceYaml(namespaceGVR, newNamespaceYaml(test.TargetNamespace))
@ -575,7 +575,7 @@ func Test_Mutate_Existing(t *testing.T) {
By(err.Error())
}
By("Done")
By("Done\n\n")
}
}