1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/pkg/background/generate/clone.go
Mike Bryant 93bbc57c7a
fix: Remove ownerReferences when cloning across Namespaces (#7517)
Signed-off-by: Mike Bryant <mike.bryant@mettle.co.uk>
Co-authored-by: shuting <shuting@nirmata.com>
2023-06-13 15:35:10 +00:00

106 lines
4.4 KiB
Go

package generate
import (
"context"
"fmt"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func manageClone(log logr.Logger, target, sourceSpec kyvernov1.ResourceSpec, policy kyvernov1.PolicyInterface, ur kyvernov1beta1.UpdateRequest, rule kyvernov1.Rule, client dclient.Interface) generateResponse {
source := sourceSpec
clone := rule.Generation
if clone.Clone.Name != "" {
source = kyvernov1.ResourceSpec{
APIVersion: target.GetAPIVersion(),
Kind: target.GetKind(),
Namespace: clone.Clone.Namespace,
Name: clone.Clone.Name,
}
}
if source.GetNamespace() == "" {
log.V(4).Info("namespace is optional in case of cluster scope resource", "source namespace", source.GetNamespace())
}
if source.GetNamespace() == target.GetNamespace() && source.GetName() == target.GetName() ||
(rule.Generation.CloneList.Kinds != nil) && (source.GetNamespace() == target.GetNamespace()) {
log.V(4).Info("skip resource self-clone")
return newSkipGenerateResponse(nil, target, nil)
}
sourceObj, err := client.GetResource(context.TODO(), source.GetAPIVersion(), source.GetKind(), source.GetNamespace(), source.GetName())
if err != nil {
return newSkipGenerateResponse(nil, target, fmt.Errorf("source resource %s not found: %v", target.String(), err))
}
if err := updateSourceLabel(client, sourceObj); err != nil {
log.Error(err, "failed to add labels to the source", "kind", sourceObj.GetKind(), "namespace", sourceObj.GetNamespace(), "name", sourceObj.GetName())
}
sourceObjCopy := sourceObj.DeepCopy()
addSourceLabels(sourceObjCopy)
if sourceObjCopy.GetNamespace() != target.GetNamespace() && sourceObjCopy.GetOwnerReferences() != nil {
sourceObjCopy.SetOwnerReferences(nil)
}
targetObj, err := client.GetResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
if err != nil {
if apierrors.IsNotFound(err) && len(ur.Status.GeneratedResources) != 0 && !clone.Synchronize {
log.V(4).Info("synchronization is disabled, recreation will be skipped", "target resource", targetObj)
return newSkipGenerateResponse(nil, target, nil)
}
if apierrors.IsNotFound(err) {
return newCreateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
}
return newSkipGenerateResponse(nil, target, fmt.Errorf("failed to get the target source: %v", err))
}
if targetObj != nil {
sourceObjCopy.SetUID(targetObj.GetUID())
sourceObjCopy.SetSelfLink(targetObj.GetSelfLink())
sourceObjCopy.SetCreationTimestamp(targetObj.GetCreationTimestamp())
sourceObjCopy.SetManagedFields(targetObj.GetManagedFields())
sourceObjCopy.SetResourceVersion(targetObj.GetResourceVersion())
if datautils.DeepEqual(sourceObjCopy, targetObj) {
return newSkipGenerateResponse(nil, target, nil)
}
return newUpdateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
}
return newCreateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
}
func manageCloneList(log logr.Logger, targetNamespace string, ur kyvernov1beta1.UpdateRequest, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, client dclient.Interface) []generateResponse {
var responses []generateResponse
cloneList := rule.Generation.CloneList
sourceNamespace := cloneList.Namespace
kinds := cloneList.Kinds
for _, kind := range kinds {
apiVersion, kind := kubeutils.GetKindFromGVK(kind)
sources, err := client.ListResource(context.TODO(), apiVersion, kind, sourceNamespace, cloneList.Selector)
if err != nil {
responses = append(responses,
newSkipGenerateResponse(
nil,
newResourceSpec(apiVersion, kind, targetNamespace, ""),
fmt.Errorf("failed to list source resource for cloneList %s %s/%s. %v", apiVersion, kind, sourceNamespace, err),
),
)
}
for _, source := range sources.Items {
target := newResourceSpec(source.GetAPIVersion(), source.GetKind(), targetNamespace, source.GetName())
responses = append(responses,
manageClone(log, target, newResourceSpec(source.GetAPIVersion(), source.GetKind(), source.GetNamespace(), source.GetName()), policy, ur, rule, client))
}
}
return responses
}