1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-09 17:37:12 +00:00
kyverno/pkg/background/generate/generator.go
shuting 5203809b73
chore: refactor background controller (#10850)
* chore: refactor

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: add foreach for generate.daya to api

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: refactor

Signed-off-by: ShutingZhao <shuting@nirmata.com>

---------

Signed-off-by: ShutingZhao <shuting@nirmata.com>
2024-08-14 14:32:49 +00:00

140 lines
5.4 KiB
Go

package generate
import (
"context"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/engine/validate"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
type generator struct {
client dclient.Interface
logger logr.Logger
policy kyvernov1.PolicyInterface
rule kyvernov1.Rule
trigger unstructured.Unstructured
}
func newGenerator(client dclient.Interface, logger logr.Logger, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, trigger unstructured.Unstructured) *generator {
return &generator{
client: client,
logger: logger,
policy: policy,
rule: rule,
trigger: trigger,
}
}
func (g *generator) generate() ([]kyvernov1.ResourceSpec, error) {
responses := []generateResponse{}
var err error
var newGenResources []kyvernov1.ResourceSpec
target := g.rule.Generation.ResourceSpec
logger := g.logger.WithValues("target", target.String())
if g.rule.Generation.Clone.Name != "" {
resp := manageClone(logger.WithValues("type", "clone"), target, kyvernov1.ResourceSpec{}, g.policy.GetSpec().UseServerSideApply, g.rule, g.client)
responses = append(responses, resp)
} else if len(g.rule.Generation.CloneList.Kinds) != 0 {
responses = manageCloneList(logger.WithValues("type", "cloneList"), target.GetNamespace(), g.policy.GetSpec().UseServerSideApply, g.rule, g.client)
} else {
resp := manageData(logger.WithValues("type", "data"), target, g.rule.Generation.RawData, g.rule.Generation.Synchronize, g.client)
responses = append(responses, resp)
}
for _, response := range responses {
targetMeta := response.GetTarget()
if response.GetError() != nil {
logger.Error(response.GetError(), "failed to generate resource", "mode", response.GetAction())
return newGenResources, err
}
if response.GetAction() == Skip {
continue
}
logger.V(3).Info("applying generate rule", "mode", response.GetAction())
if response.GetData() == nil && response.GetAction() == Update {
logger.V(4).Info("no changes required for generate target resource")
return newGenResources, nil
}
newResource := &unstructured.Unstructured{}
newResource.SetUnstructuredContent(response.GetData())
newResource.SetName(targetMeta.GetName())
newResource.SetNamespace(targetMeta.GetNamespace())
if newResource.GetKind() == "" {
newResource.SetKind(targetMeta.GetKind())
}
newResource.SetAPIVersion(targetMeta.GetAPIVersion())
common.ManageLabels(newResource, g.trigger, g.policy, g.rule.Name)
if response.GetAction() == Create {
newResource.SetResourceVersion("")
if g.policy.GetSpec().UseServerSideApply {
_, err = g.client.ApplyResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName(), newResource, false, "generate")
} else {
_, err = g.client.CreateResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), newResource, false)
}
if err != nil {
if !apierrors.IsAlreadyExists(err) {
return newGenResources, err
}
}
logger.V(2).Info("created generate target resource")
newGenResources = append(newGenResources, targetMeta)
} else if response.GetAction() == Update {
generatedObj, err := g.client.GetResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName())
if err != nil {
logger.V(2).Info("creating new target due to the failure when fetching", "err", err.Error())
if g.policy.GetSpec().UseServerSideApply {
_, err = g.client.ApplyResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName(), newResource, false, "generate")
} else {
_, err = g.client.CreateResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), newResource, false)
}
if err != nil {
return newGenResources, err
}
newGenResources = append(newGenResources, targetMeta)
} else {
if !g.rule.Generation.Synchronize {
logger.V(4).Info("synchronize disabled, skip syncing changes")
continue
}
if err := validate.MatchPattern(logger, newResource.Object, generatedObj.Object); err == nil {
if err := validate.MatchPattern(logger, generatedObj.Object, newResource.Object); err == nil {
logger.V(4).Info("patterns match, skipping updates")
continue
}
}
logger.V(4).Info("updating existing resource")
if targetMeta.GetAPIVersion() == "" {
generatedResourceAPIVersion := generatedObj.GetAPIVersion()
newResource.SetAPIVersion(generatedResourceAPIVersion)
}
if targetMeta.GetNamespace() == "" {
newResource.SetNamespace("default")
}
if g.policy.GetSpec().UseServerSideApply {
_, err = g.client.ApplyResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName(), newResource, false, "generate")
} else {
_, err = g.client.UpdateResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), newResource, false)
}
if err != nil {
logger.Error(err, "failed to update resource")
return newGenResources, err
}
}
logger.V(3).Info("updated generate target resource")
}
}
return newGenResources, nil
}