diff --git a/api/config/v1alpha1/envoygateway_types.go b/api/config/v1alpha1/envoygateway_types.go index d90cb3b929..86755a76cb 100644 --- a/api/config/v1alpha1/envoygateway_types.go +++ b/api/config/v1alpha1/envoygateway_types.go @@ -67,10 +67,16 @@ type EnvoyGatewaySpec struct { // +optional RateLimit *RateLimit `json:"rateLimit,omitempty"` - // Extension defines an extension to register for the Envoy Gateway Control Plane. + // ExtensionManager defines an extension manager to register for the Envoy Gateway Control Plane. // // +optional - Extension *Extension `json:"extension,omitempty"` + ExtensionManager *ExtensionManager `json:"extensionManager,omitempty"` + + // ExtensionAPIs defines the settings related to specific Gateway API Extensions + // implemented by Envoy Gateway + // + // +optional + ExtensionAPIs *ExtensionAPISettings `json:"extensionApis,omitempty"` } // EnvoyGatewayLogging defines logging for Envoy Gateway. @@ -122,6 +128,13 @@ type Gateway struct { ControllerName string `json:"controllerName,omitempty"` } +// ExtensionAPISettings defines the settings specific to Gateway API Extensions. +type ExtensionAPISettings struct { + // EnableEnvoyPatchPolicy enables Envoy Gateway to + // reconcile and implement the EnvoyPatchPolicy resources. + EnableEnvoyPatchPolicy bool `json:"enableEnvoyPatchPolicy"` +} + // EnvoyGatewayProvider defines the desired configuration of a provider. // +union type EnvoyGatewayProvider struct { @@ -304,9 +317,9 @@ type RateLimitRedisSettings struct { TLS *RedisTLSSettings `json:"tls,omitempty"` } -// Extension defines the configuration for registering an extension to +// ExtensionManager defines the configuration for registering an extension manager to // the Envoy Gateway control plane. -type Extension struct { +type ExtensionManager struct { // Resources defines the set of K8s resources the extension will handle. // // +optional diff --git a/api/config/v1alpha1/zz_generated.deepcopy.go b/api/config/v1alpha1/zz_generated.deepcopy.go index 811a22cf4d..41bdf7269c 100644 --- a/api/config/v1alpha1/zz_generated.deepcopy.go +++ b/api/config/v1alpha1/zz_generated.deepcopy.go @@ -324,11 +324,16 @@ func (in *EnvoyGatewaySpec) DeepCopyInto(out *EnvoyGatewaySpec) { *out = new(RateLimit) (*in).DeepCopyInto(*out) } - if in.Extension != nil { - in, out := &in.Extension, &out.Extension - *out = new(Extension) + if in.ExtensionManager != nil { + in, out := &in.ExtensionManager, &out.ExtensionManager + *out = new(ExtensionManager) (*in).DeepCopyInto(*out) } + if in.ExtensionAPIs != nil { + in, out := &in.ExtensionAPIs, &out.ExtensionAPIs + *out = new(ExtensionAPISettings) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyGatewaySpec. @@ -488,31 +493,16 @@ func (in *EnvoyProxyStatus) DeepCopy() *EnvoyProxyStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Extension) DeepCopyInto(out *Extension) { +func (in *ExtensionAPISettings) DeepCopyInto(out *ExtensionAPISettings) { *out = *in - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make([]GroupVersionKind, len(*in)) - copy(*out, *in) - } - if in.Hooks != nil { - in, out := &in.Hooks, &out.Hooks - *out = new(ExtensionHooks) - (*in).DeepCopyInto(*out) - } - if in.Service != nil { - in, out := &in.Service, &out.Service - *out = new(ExtensionService) - (*in).DeepCopyInto(*out) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extension. -func (in *Extension) DeepCopy() *Extension { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtensionAPISettings. +func (in *ExtensionAPISettings) DeepCopy() *ExtensionAPISettings { if in == nil { return nil } - out := new(Extension) + out := new(ExtensionAPISettings) in.DeepCopyInto(out) return out } @@ -537,6 +527,36 @@ func (in *ExtensionHooks) DeepCopy() *ExtensionHooks { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtensionManager) DeepCopyInto(out *ExtensionManager) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]GroupVersionKind, len(*in)) + copy(*out, *in) + } + if in.Hooks != nil { + in, out := &in.Hooks, &out.Hooks + *out = new(ExtensionHooks) + (*in).DeepCopyInto(*out) + } + if in.Service != nil { + in, out := &in.Service, &out.Service + *out = new(ExtensionService) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtensionManager. +func (in *ExtensionManager) DeepCopy() *ExtensionManager { + if in == nil { + return nil + } + out := new(ExtensionManager) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExtensionService) DeepCopyInto(out *ExtensionService) { *out = *in diff --git a/docs/latest/api/config_types.md b/docs/latest/api/config_types.md index d2cc1d2f09..dc90bb06f8 100644 --- a/docs/latest/api/config_types.md +++ b/docs/latest/api/config_types.md @@ -76,7 +76,8 @@ EnvoyGateway is the schema for the envoygateways API. | `logging` _[EnvoyGatewayLogging](#envoygatewaylogging)_ | Logging defines logging parameters for Envoy Gateway. | | `admin` _[EnvoyGatewayAdmin](#envoygatewayadmin)_ | Admin defines the desired admin related abilities. If unspecified, the Admin is used with default configuration parameters. | | `rateLimit` _[RateLimit](#ratelimit)_ | RateLimit defines the configuration associated with the Rate Limit service deployed by Envoy Gateway required to implement the Global Rate limiting functionality. The specific rate limit service used here is the reference implementation in Envoy. For more details visit https://github.com/envoyproxy/ratelimit. This configuration is unneeded for "Local" rate limiting. | -| `extension` _[Extension](#extension)_ | Extension defines an extension to register for the Envoy Gateway Control Plane. | +| `extensionManager` _[ExtensionManager](#extensionmanager)_ | ExtensionManager defines an extension manager to register for the Envoy Gateway Control Plane. | +| `extensionApis` _[ExtensionAPISettings](#extensionapisettings)_ | ExtensionAPIs defines the settings related to specific Gateway API Extensions implemented by Envoy Gateway | ## EnvoyGatewayAdmin @@ -255,7 +256,8 @@ _Appears in:_ | `logging` _[EnvoyGatewayLogging](#envoygatewaylogging)_ | Logging defines logging parameters for Envoy Gateway. | | `admin` _[EnvoyGatewayAdmin](#envoygatewayadmin)_ | Admin defines the desired admin related abilities. If unspecified, the Admin is used with default configuration parameters. | | `rateLimit` _[RateLimit](#ratelimit)_ | RateLimit defines the configuration associated with the Rate Limit service deployed by Envoy Gateway required to implement the Global Rate limiting functionality. The specific rate limit service used here is the reference implementation in Envoy. For more details visit https://github.com/envoyproxy/ratelimit. This configuration is unneeded for "Local" rate limiting. | -| `extension` _[Extension](#extension)_ | Extension defines an extension to register for the Envoy Gateway Control Plane. | +| `extensionManager` _[ExtensionManager](#extensionmanager)_ | ExtensionManager defines an extension manager to register for the Envoy Gateway Control Plane. | +| `extensionApis` _[ExtensionAPISettings](#extensionapisettings)_ | ExtensionAPIs defines the settings related to specific Gateway API Extensions implemented by Envoy Gateway | ## EnvoyProxy @@ -323,11 +325,11 @@ _Appears in:_ -## Extension +## ExtensionAPISettings -Extension defines the configuration for registering an extension to the Envoy Gateway control plane. +ExtensionAPISettings defines the settings specific to Gateway API Extensions. _Appears in:_ - [EnvoyGateway](#envoygateway) @@ -335,9 +337,7 @@ _Appears in:_ | Field | Description | | --- | --- | -| `resources` _[GroupVersionKind](#groupversionkind) array_ | Resources defines the set of K8s resources the extension will handle. | -| `hooks` _[ExtensionHooks](#extensionhooks)_ | Hooks defines the set of hooks the extension supports | -| `service` _[ExtensionService](#extensionservice)_ | Service defines the configuration of the extension service that the Envoy Gateway Control Plane will call through extension hooks. | +| `enableEnvoyPatchPolicy` _boolean_ | EnableEnvoyPatchPolicy enables Envoy Gateway to reconcile and implement the EnvoyPatchPolicy resources. | ## ExtensionHooks @@ -347,13 +347,30 @@ _Appears in:_ ExtensionHooks defines extension hooks across all supported runners _Appears in:_ -- [Extension](#extension) +- [ExtensionManager](#extensionmanager) | Field | Description | | --- | --- | | `xdsTranslator` _[XDSTranslatorHooks](#xdstranslatorhooks)_ | XDSTranslator defines all the supported extension hooks for the xds-translator runner | +## ExtensionManager + + + +ExtensionManager defines the configuration for registering an extension manager to the Envoy Gateway control plane. + +_Appears in:_ +- [EnvoyGateway](#envoygateway) +- [EnvoyGatewaySpec](#envoygatewayspec) + +| Field | Description | +| --- | --- | +| `resources` _[GroupVersionKind](#groupversionkind) array_ | Resources defines the set of K8s resources the extension will handle. | +| `hooks` _[ExtensionHooks](#extensionhooks)_ | Hooks defines the set of hooks the extension supports | +| `service` _[ExtensionService](#extensionservice)_ | Service defines the configuration of the extension service that the Envoy Gateway Control Plane will call through extension hooks. | + + ## ExtensionService @@ -361,7 +378,7 @@ _Appears in:_ ExtensionService defines the configuration for connecting to a registered extension service. _Appears in:_ -- [Extension](#extension) +- [ExtensionManager](#extensionmanager) | Field | Description | | --- | --- | @@ -421,7 +438,7 @@ _Appears in:_ GroupVersionKind unambiguously identifies a Kind. It can be converted to k8s.io/apimachinery/pkg/runtime/schema.GroupVersionKind _Appears in:_ -- [Extension](#extension) +- [ExtensionManager](#extensionmanager) | Field | Description | | --- | --- | diff --git a/internal/envoygateway/config/config.go b/internal/envoygateway/config/config.go index 4aaa0c5932..fac7e3bcad 100644 --- a/internal/envoygateway/config/config.go +++ b/internal/envoygateway/config/config.go @@ -99,21 +99,21 @@ func (s *Server) Validate() error { if _, err := url.Parse(s.EnvoyGateway.RateLimit.Backend.Redis.URL); err != nil { return fmt.Errorf("unknown ratelimit redis url format: %w", err) } - case s.EnvoyGateway.Extension != nil: - if s.EnvoyGateway.Extension.Hooks == nil || s.EnvoyGateway.Extension.Hooks.XDSTranslator == nil { + case s.EnvoyGateway.ExtensionManager != nil: + if s.EnvoyGateway.ExtensionManager.Hooks == nil || s.EnvoyGateway.ExtensionManager.Hooks.XDSTranslator == nil { return fmt.Errorf("registered extension has no hooks specified") } - if len(s.EnvoyGateway.Extension.Hooks.XDSTranslator.Pre) == 0 && len(s.EnvoyGateway.Extension.Hooks.XDSTranslator.Post) == 0 { + if len(s.EnvoyGateway.ExtensionManager.Hooks.XDSTranslator.Pre) == 0 && len(s.EnvoyGateway.ExtensionManager.Hooks.XDSTranslator.Post) == 0 { return fmt.Errorf("registered extension has no hooks specified") } - if s.EnvoyGateway.Extension.Service == nil { + if s.EnvoyGateway.ExtensionManager.Service == nil { return fmt.Errorf("extension service config is empty") } - if s.EnvoyGateway.Extension.Service.TLS != nil { - certificateRefKind := s.EnvoyGateway.Extension.Service.TLS.CertificateRef.Kind + if s.EnvoyGateway.ExtensionManager.Service.TLS != nil { + certificateRefKind := s.EnvoyGateway.ExtensionManager.Service.TLS.CertificateRef.Kind if certificateRefKind == nil { return fmt.Errorf("certificateRef empty in extension service server TLS settings") diff --git a/internal/envoygateway/config/config_test.go b/internal/envoygateway/config/config_test.go index fb5eafbcf5..209b225986 100644 --- a/internal/envoygateway/config/config_test.go +++ b/internal/envoygateway/config/config_test.go @@ -187,7 +187,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io", @@ -224,7 +224,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io", @@ -267,7 +267,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Hooks: &v1alpha1.ExtensionHooks{ XDSTranslator: &v1alpha1.XDSTranslatorHooks{ Pre: []v1alpha1.XDSTranslatorHook{}, @@ -303,7 +303,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io", @@ -346,7 +346,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io", @@ -379,7 +379,7 @@ func TestValidate(t *testing.T) { EnvoyGatewaySpec: v1alpha1.EnvoyGatewaySpec{ Gateway: v1alpha1.DefaultGateway(), Provider: v1alpha1.DefaultEnvoyGatewayProvider(), - Extension: &v1alpha1.Extension{ + ExtensionManager: &v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io", diff --git a/internal/extension/registry/extension_manager.go b/internal/extension/registry/extension_manager.go index 4762c51613..14f368a330 100644 --- a/internal/extension/registry/extension_manager.go +++ b/internal/extension/registry/extension_manager.go @@ -46,7 +46,7 @@ var _ extTypes.Manager = (*Manager)(nil) type Manager struct { k8sClient k8scli.Client namespace string - extension v1alpha1.Extension + extension v1alpha1.ExtensionManager extensionConnCache *grpc.ClientConn } @@ -57,14 +57,14 @@ func NewManager(cfg *config.Server) (extTypes.Manager, error) { return nil, err } - var extension *v1alpha1.Extension + var extension *v1alpha1.ExtensionManager if cfg.EnvoyGateway != nil { - extension = cfg.EnvoyGateway.Extension + extension = cfg.EnvoyGateway.ExtensionManager } // Setup an empty default in the case that no config was provided if extension == nil { - extension = &v1alpha1.Extension{} + extension = &v1alpha1.ExtensionManager{} } return &Manager{ @@ -203,7 +203,7 @@ func parseCA(caSecret *corev1.Secret) (*x509.CertPool, error) { return cp, nil } -func setupGRPCOpts(ctx context.Context, client k8scli.Client, ext *v1alpha1.Extension, namespace string) ([]grpc.DialOption, error) { +func setupGRPCOpts(ctx context.Context, client k8scli.Client, ext *v1alpha1.ExtensionManager, namespace string) ([]grpc.DialOption, error) { // These two errors shouldn't happen since we check these conditions when loading the extension if ext == nil { return nil, errors.New("the registered extension's config is nil") diff --git a/internal/extension/testutils/manager.go b/internal/extension/testutils/manager.go index 5e6a5caf90..aa85c02b4c 100644 --- a/internal/extension/testutils/manager.go +++ b/internal/extension/testutils/manager.go @@ -15,10 +15,10 @@ import ( var _ extType.Manager = (*Manager)(nil) type Manager struct { - extension v1alpha1.Extension + extension v1alpha1.ExtensionManager } -func NewManager(ext v1alpha1.Extension) extType.Manager { +func NewManager(ext v1alpha1.ExtensionManager) extType.Manager { return &Manager{ extension: ext, } diff --git a/internal/gatewayapi/runner/runner.go b/internal/gatewayapi/runner/runner.go index 45d5d3a578..050394ba30 100644 --- a/internal/gatewayapi/runner/runner.go +++ b/internal/gatewayapi/runner/runner.go @@ -65,9 +65,9 @@ func (r *Runner) subscribeAndTranslate(ctx context.Context) { } // If an extension is loaded, pass its supported groups/kinds to the translator - if r.EnvoyGateway.Extension != nil { + if r.EnvoyGateway.ExtensionManager != nil { var extGKs []schema.GroupKind - for _, gvk := range r.EnvoyGateway.Extension.Resources { + for _, gvk := range r.EnvoyGateway.ExtensionManager.Resources { extGKs = append(extGKs, schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}) } t.ExtensionGroupKinds = extGKs diff --git a/internal/gatewayapi/runner/runner_test.go b/internal/gatewayapi/runner/runner_test.go index 5e54da6374..227135896c 100644 --- a/internal/gatewayapi/runner/runner_test.go +++ b/internal/gatewayapi/runner/runner_test.go @@ -33,7 +33,7 @@ func TestRunner(t *testing.T) { ProviderResources: pResources, XdsIR: xdsIR, InfraIR: infraIR, - ExtensionManager: testutils.NewManager(egv1a1cfg.Extension{}), + ExtensionManager: testutils.NewManager(egv1a1cfg.ExtensionManager{}), }) ctx := context.Background() // Start diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index ea309cf2bd..7ede2a01ab 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -63,6 +63,7 @@ type gatewayAPIReconciler struct { classController gwapiv1b1.GatewayController store *kubernetesProviderStore namespace string + envoyGateway *egcfgv1a1.EnvoyGateway resources *message.ProviderResources extGVKs []schema.GroupVersionKind @@ -74,8 +75,8 @@ func newGatewayAPIController(mgr manager.Manager, cfg *config.Server, su status. // Gather additional resources to watch from registered extensions var extGVKs []schema.GroupVersionKind - if cfg.EnvoyGateway.Extension != nil { - for _, rsrc := range cfg.EnvoyGateway.Extension.Resources { + if cfg.EnvoyGateway.ExtensionManager != nil { + for _, rsrc := range cfg.EnvoyGateway.ExtensionManager.Resources { gvk := schema.GroupVersionKind(rsrc) extGVKs = append(extGVKs, gvk) } @@ -90,6 +91,7 @@ func newGatewayAPIController(mgr manager.Manager, cfg *config.Server, su status. resources: resources, extGVKs: extGVKs, store: newProviderStore(), + envoyGateway: cfg.EnvoyGateway, } c, err := controller.New("gatewayapi", mgr, controller.Options{Reconciler: r}) @@ -1226,11 +1228,14 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M return err } - // Watch EnvoyPatchPolicy CRUDs - if err := c.Watch( - source.Kind(mgr.GetCache(), &egv1a1.EnvoyPatchPolicy{}), - &handler.EnqueueRequestForObject{}); err != nil { - return err + // Watch EnvoyPatchPolicy if enabled in config + if r.envoyGateway.ExtensionAPIs != nil && r.envoyGateway.ExtensionAPIs.EnableEnvoyPatchPolicy { + // Watch EnvoyPatchPolicy CRUDs + if err := c.Watch( + source.Kind(mgr.GetCache(), &egv1a1.EnvoyPatchPolicy{}), + &handler.EnqueueRequestForObject{}); err != nil { + return err + } } r.log.Info("Watching gatewayAPI related objects") diff --git a/internal/xds/translator/translator_test.go b/internal/xds/translator/translator_test.go index 8efa02880a..e3403fd2a6 100644 --- a/internal/xds/translator/translator_test.go +++ b/internal/xds/translator/translator_test.go @@ -287,7 +287,7 @@ func TestTranslateXdsWithExtension(t *testing.T) { ServiceURL: ratelimit.GetServiceURL("envoy-gateway-system", "cluster.local"), }, } - ext := v1alpha1.Extension{ + ext := v1alpha1.ExtensionManager{ Resources: []v1alpha1.GroupVersionKind{ { Group: "foo.example.io",