2023-03-27 10:09:46 +02:00
package mutation
import (
"context"
2024-07-25 20:36:19 +03:00
"strings"
2023-03-27 10:09:46 +02:00
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2024-06-24 23:36:55 +07:00
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
2023-03-27 10:09:46 +02:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/handlers"
"github.com/kyverno/kyverno/pkg/engine/mutate"
2023-11-13 17:43:25 +02:00
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
2023-03-27 10:09:46 +02:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2023-11-13 17:43:25 +02:00
"k8s.io/client-go/tools/cache"
2023-03-27 10:09:46 +02:00
)
2023-04-03 06:57:48 +02:00
type mutateResourceHandler struct { }
2023-03-27 10:09:46 +02:00
2023-04-03 21:58:58 +02:00
func NewMutateResourceHandler ( ) ( handlers . Handler , error ) {
return mutateResourceHandler { } , nil
2023-03-27 10:09:46 +02:00
}
2023-03-28 07:47:53 +02:00
func ( h mutateResourceHandler ) Process (
2023-03-27 10:09:46 +02:00
ctx context . Context ,
logger logr . Logger ,
policyContext engineapi . PolicyContext ,
resource unstructured . Unstructured ,
rule kyvernov1 . Rule ,
2023-04-03 06:57:48 +02:00
contextLoader engineapi . EngineContextLoader ,
2024-06-24 23:36:55 +07:00
exceptions [ ] * kyvernov2 . PolicyException ,
2023-03-27 10:09:46 +02:00
) ( unstructured . Unstructured , [ ] engineapi . RuleResponse ) {
2024-07-25 20:36:19 +03:00
// check if there are policy exceptions that match the incoming resource
matchedExceptions := engineutils . MatchesException ( exceptions , policyContext , logger )
if len ( matchedExceptions ) > 0 {
2025-02-25 18:11:19 +02:00
exceptions := make ( [ ] engineapi . GenericException , 0 , len ( matchedExceptions ) )
2024-07-25 20:36:19 +03:00
var keys [ ] string
for i , exception := range matchedExceptions {
key , err := cache . MetaNamespaceKeyFunc ( & matchedExceptions [ i ] )
if err != nil {
logger . Error ( err , "failed to compute policy exception key" , "namespace" , exception . GetNamespace ( ) , "name" , exception . GetName ( ) )
return resource , handlers . WithError ( rule , engineapi . Mutation , "failed to compute exception key" , err )
}
keys = append ( keys , key )
2025-02-25 18:11:19 +02:00
exceptions = append ( exceptions , engineapi . NewPolicyException ( & exception ) )
2023-11-13 17:43:25 +02:00
}
2024-07-25 20:36:19 +03:00
logger . V ( 3 ) . Info ( "policy rule is skipped due to policy exceptions" , "exceptions" , keys )
return resource , handlers . WithResponses (
2025-02-25 18:11:19 +02:00
engineapi . RuleSkip ( rule . Name , engineapi . Mutation , "rule is skipped due to policy exceptions" + strings . Join ( keys , ", " ) , rule . ReportProperties ) . WithExceptions ( exceptions ) ,
2024-07-25 20:36:19 +03:00
)
2023-11-13 17:43:25 +02:00
}
2023-03-27 13:22:54 +02:00
_ , subresource := policyContext . ResourceKind ( )
2023-03-27 10:09:46 +02:00
logger . V ( 3 ) . Info ( "processing mutate rule" )
var parentResourceGVR metav1 . GroupVersionResource
if subresource != "" {
parentResourceGVR = policyContext . RequestResource ( )
}
resourceInfo := resourceInfo {
unstructured : resource ,
subresource : subresource ,
parentResourceGVR : parentResourceGVR ,
}
// logger.V(4).Info("apply rule to resource", "resource namespace", patchedResource.unstructured.GetNamespace(), "resource name", patchedResource.unstructured.GetName())
var mutateResp * mutate . Response
if rule . Mutation . ForEachMutation != nil {
m := & forEachMutator {
2023-04-03 21:58:58 +02:00
rule : rule ,
2023-03-27 10:09:46 +02:00
foreach : rule . Mutation . ForEachMutation ,
policyContext : policyContext ,
resource : resourceInfo ,
2023-04-03 21:58:58 +02:00
logger : logger ,
2023-03-27 10:09:46 +02:00
contextLoader : contextLoader ,
nesting : 0 ,
}
mutateResp = m . mutateForEach ( ctx )
} else {
2023-04-03 21:58:58 +02:00
mutateResp = mutate . Mutate ( & rule , policyContext . JSONContext ( ) , resource , logger )
2023-03-27 10:09:46 +02:00
}
if mutateResp == nil {
return resource , nil
}
2023-04-05 12:35:38 +02:00
return mutateResp . PatchedResource , handlers . WithResponses ( buildRuleResponse ( & rule , mutateResp , resourceInfo ) )
2023-03-27 10:09:46 +02:00
}