@@ -42,6 +42,7 @@ const (
4242 globalRateLimitPolicySuffix = ":rl-global"
4343 transformationPolicySuffix = ":transformation"
4444 csrfPolicySuffix = ":csrf"
45+ extprocPolicySuffix = ":ext-proc"
4546)
4647
4748var logger = logging .New ("agentgateway/plugins" )
@@ -398,6 +399,16 @@ func translateTrafficPolicyToAgw(
398399 agwPolicies = append (agwPolicies , csrfPolicies ... )
399400 }
400401
402+ // Process extproc policies if present
403+ if trafficPolicy .Spec .ExtProc != nil {
404+ extProcPolicies , err := processExtProcPolicy (ctx , gatewayExtensions , trafficPolicy , policyName , policyTarget )
405+ if err != nil {
406+ logger .Error ("error processing extproc policy" , "error" , err )
407+ errs = append (errs , err )
408+ }
409+ agwPolicies = append (agwPolicies , extProcPolicies ... )
410+ }
411+
401412 return agwPolicies , errors .Join (errs ... )
402413}
403414
@@ -864,6 +875,114 @@ func processRateLimitPolicy(ctx krt.HandlerContext, gatewayExtensions krt.Collec
864875 return agwPolicies , errors .Join (errs ... )
865876}
866877
878+ func processExtProcPolicy (ctx krt.HandlerContext , gatewayExtensions krt.Collection [* v1alpha1.GatewayExtension ], trafficPolicy * v1alpha1.TrafficPolicy , policyName string , policyTarget * api.PolicyTarget ) ([]AgwPolicy , error ) {
879+ var errs []error
880+
881+ // validate that unsupported ExtProcPolicy fields are not set
882+ if err := validateExtProcPolicy (trafficPolicy .Spec .ExtProc ); err != nil {
883+ errs = append (errs , err )
884+ }
885+
886+ gwExt , err := lookupGatewayExtension (ctx , gatewayExtensions , * trafficPolicy .Spec .ExtProc .ExtensionRef , trafficPolicy .Namespace , v1alpha1 .GatewayExtensionTypeExtProc )
887+ if err != nil {
888+ return nil , err
889+ }
890+
891+ extProc := (* gwExt ).Spec .ExtProc
892+ if extProc == nil {
893+ return nil , fmt .Errorf ("extproc provider is missing from gateway extension %s/%s" , gwExt .Namespace , gwExt .Namespace )
894+ }
895+
896+ // validate that unsupported ExtProcProvider fields are not set
897+ if err := validateExtProcProvider (extProc ); err != nil {
898+ errs = append (errs , err )
899+ }
900+
901+ var extProcSvcTarget * api.BackendReference
902+ if extProc .GrpcService != nil && extProc .GrpcService .BackendRef != nil {
903+ var err error
904+ extProcSvcTarget , err = buildAGWServiceRef (extProc .GrpcService .BackendRef , trafficPolicy .Namespace )
905+ if err != nil {
906+ return nil , fmt .Errorf ("failed to build extproc service reference: %w" , err )
907+ }
908+ }
909+
910+ if extProcSvcTarget == nil {
911+ return nil , fmt .Errorf ("extproc policy %s/%s missing backendRef in gateway extension %s/%s" ,
912+ trafficPolicy .Namespace , trafficPolicy .Name , (* gwExt ).Namespace , (* gwExt ).Name )
913+ }
914+
915+ failureMode := api .PolicySpec_ExtProc_FAIL_CLOSED
916+ if extProc .FailOpen {
917+ failureMode = api .PolicySpec_ExtProc_FAIL_OPEN
918+ }
919+
920+ extProcPolicy := & api.Policy {
921+ Name : policyName + extprocPolicySuffix + attachmentName (policyTarget ),
922+ Target : policyTarget ,
923+ Spec : & api.PolicySpec {
924+ Kind : & api.PolicySpec_ExtProc_ {
925+ ExtProc : & api.PolicySpec_ExtProc {
926+ Target : extProcSvcTarget ,
927+ FailureMode : failureMode ,
928+ },
929+ },
930+ },
931+ }
932+
933+ logger .Debug ("generated ExtProc policy" ,
934+ "policy" , trafficPolicy .Name ,
935+ "agentgateway_policy" , extProcPolicy .Name ,
936+ "target" , extProcSvcTarget )
937+
938+ return []AgwPolicy {{Policy : extProcPolicy }}, errors .Join (errs ... )
939+ }
940+
941+ // validateExtProcPolicy validates that unsupported ExtProcPolicy fields are not set.
942+ func validateExtProcPolicy (policy * v1alpha1.ExtProcPolicy ) error {
943+ var errs []error
944+
945+ if policy .ProcessingMode != nil {
946+ errs = append (errs , fmt .Errorf ("processingMode field is not supported for agentgateway" ))
947+ }
948+
949+ if policy .Disable != nil {
950+ errs = append (errs , fmt .Errorf ("disable field is not supported for agentgateway" ))
951+ }
952+
953+ return errors .Join (errs ... )
954+ }
955+
956+ // validateExtProcProvider validates that unsupported ExtProcProvider fields are not set.
957+ func validateExtProcProvider (provider * v1alpha1.ExtProcProvider ) error {
958+ var errs []error
959+
960+ if provider .ProcessingMode != nil {
961+ errs = append (errs , fmt .Errorf ("processingMode field in ExtProcProvider is not supported for agentgateway" ))
962+ }
963+
964+ if provider .MessageTimeout != nil {
965+ errs = append (errs , fmt .Errorf ("messageTimeout field in ExtProcProvider is not supported for agentgateway" ))
966+ }
967+
968+ if provider .MaxMessageTimeout != nil {
969+ errs = append (errs , fmt .Errorf ("maxMessageTimeout field in ExtProcProvider is not supported for agentgateway" ))
970+ }
971+
972+ if provider .StatPrefix != nil {
973+ errs = append (errs , fmt .Errorf ("statPrefix field in ExtProcProvider is not supported for agentgateway" ))
974+ }
975+
976+ // TODO: RouteCacheAction has a kubebuilder default so we don't validate it here
977+ // to avoid false positives when the default is automatically applied.
978+
979+ if provider .MetadataOptions != nil {
980+ errs = append (errs , fmt .Errorf ("metadataOptions field in ExtProcProvider is not supported for agentgateway" ))
981+ }
982+
983+ return errors .Join (errs ... )
984+ }
985+
867986// processLocalRateLimitPolicy processes local rate limiting configuration
868987func processLocalRateLimitPolicy (trafficPolicy * v1alpha1.TrafficPolicy , policyName string , policyTarget * api.PolicyTarget ) (* AgwPolicy , error ) {
869988 if trafficPolicy .Spec .RateLimit .Local .TokenBucket == nil {
0 commit comments