From d08ba787ab365d1726e43348aab9f2f1486e7140 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Mon, 8 Dec 2025 01:11:58 -0500 Subject: [PATCH 1/8] Splitting HelmConfig into AgentgatewayHelmConfig A follow-up for 13018 Signed-off-by: David L. Chandler --- pkg/deployer/agentgateway_values.go | 74 +++++++++++++++++++ pkg/deployer/deployer.go | 36 ++++++--- pkg/deployer/helm_values_generator.go | 14 ++++ pkg/deployer/values.go | 27 +------ .../deployer/agentgateway_parameters.go | 18 +++-- .../deployer/agentgateway_parameters_test.go | 28 +++---- pkg/kgateway/deployer/gateway_parameters.go | 32 +++++++- .../deployer/gateway_parameters_test.go | 4 + 8 files changed, 175 insertions(+), 58 deletions(-) create mode 100644 pkg/deployer/agentgateway_values.go diff --git a/pkg/deployer/agentgateway_values.go b/pkg/deployer/agentgateway_values.go new file mode 100644 index 00000000000..a817eef7b0d --- /dev/null +++ b/pkg/deployer/agentgateway_values.go @@ -0,0 +1,74 @@ +package deployer + +import ( + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + + "github.com/kgateway-dev/kgateway/v2/api/v1alpha1/kgateway" +) + +// AgentgatewayHelmConfig stores the top-level helm values used by the deployer +// for agentgateway deployments. +type AgentgatewayHelmConfig struct { + Gateway *AgentgatewayHelmGateway `json:"gateway,omitempty"` +} + +// AgentgatewayHelmGateway contains helm values specific to agentgateway deployments. +type AgentgatewayHelmGateway struct { + // naming + Name *string `json:"name,omitempty"` + GatewayName *string `json:"gatewayName,omitempty"` + GatewayNamespace *string `json:"gatewayNamespace,omitempty"` + GatewayClassName *string `json:"gatewayClassName,omitempty"` + GatewayAnnotations map[string]string `json:"gatewayAnnotations,omitempty"` + GatewayLabels map[string]string `json:"gatewayLabels,omitempty"` + NameOverride *string `json:"nameOverride,omitempty"` + FullnameOverride *string `json:"fullnameOverride,omitempty"` + + // deployment/service values + ReplicaCount *uint32 `json:"replicaCount,omitempty"` + Ports []HelmPort `json:"ports,omitempty"` + Service *HelmService `json:"service,omitempty"` + Strategy *appsv1.DeploymentStrategy `json:"strategy,omitempty"` + + // serviceaccount values + ServiceAccount *HelmServiceAccount `json:"serviceAccount,omitempty"` + + // pod template values + ExtraPodAnnotations map[string]string `json:"extraPodAnnotations,omitempty"` + ExtraPodLabels map[string]string `json:"extraPodLabels,omitempty"` + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + Affinity *corev1.Affinity `json:"affinity,omitempty"` + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + StartupProbe *corev1.Probe `json:"startupProbe,omitempty"` + ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty"` + LivenessProbe *corev1.Probe `json:"livenessProbe,omitempty"` + ExtraVolumes []corev1.Volume `json:"extraVolumes,omitempty"` + GracefulShutdown *kgateway.GracefulShutdownSpec `json:"gracefulShutdown,omitempty"` + TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` + TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` + PriorityClassName *string `json:"priorityClassName,omitempty"` + + // agentgateway container values + LogLevel *string `json:"logLevel,omitempty"` + Image *HelmImage `json:"image,omitempty"` + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"` + Env []corev1.EnvVar `json:"env,omitempty"` + ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"` + + // agentgateway xds values + // Note: agentgateway uses agwXds for its xds connection, but the helm template + // also references xds.host for constructing the XDS_ADDRESS + Xds *HelmXds `json:"xds,omitempty"` + AgwXds *HelmXds `json:"agwXds,omitempty"` + + // agentgateway-specific config + CustomConfigMapName *string `json:"customConfigMapName,omitempty"` + // LogFormat specifies the logging format for agentgateway (Json or Text) + LogFormat *string `json:"logFormat,omitempty"` + // RawConfig provides opaque config to be merged into config.yaml + RawConfig map[string]any `json:"rawConfig,omitempty"` +} diff --git a/pkg/deployer/deployer.go b/pkg/deployer/deployer.go index 0c67ac29328..3f5274976db 100644 --- a/pkg/deployer/deployer.go +++ b/pkg/deployer/deployer.go @@ -158,6 +158,14 @@ func JsonConvert(in *HelmConfig, out any) error { return json.Unmarshal(b, out) } +func AgentgatewayJsonConvert(in *AgentgatewayHelmConfig, out any) error { + b, err := json.Marshal(in) + if err != nil { + return err + } + return json.Unmarshal(b, out) +} + func (d *Deployer) RenderChartToObjects(ns, name string, vals map[string]any) ([]client.Object, error) { objs, err := d.RenderToObjects(ns, name, vals) if err != nil { @@ -175,7 +183,12 @@ func (d *Deployer) RenderChartToObjects(ns, name string, vals map[string]any) ([ // It returns the list of Objects that are rendered, and an optional error if rendering failed, // or converting the rendered manifests to objects failed. func (d *Deployer) RenderToObjects(ns, name string, vals map[string]any) ([]client.Object, error) { - manifest, err := d.RenderManifest(ns, name, vals) + return d.RenderToObjectsWithChartType(ns, name, vals, ChartTypeEnvoy) +} + +// RenderToObjectsWithChartType renders the helm chart with the specified chart type. +func (d *Deployer) RenderToObjectsWithChartType(ns, name string, vals map[string]any, chartType ChartType) ([]client.Object, error) { + manifest, err := d.RenderManifestWithChartType(ns, name, vals, chartType) if err != nil { return nil, err } @@ -188,6 +201,11 @@ func (d *Deployer) RenderToObjects(ns, name string, vals map[string]any) ([]clie } func (d *Deployer) RenderManifest(ns, name string, vals map[string]any) ([]byte, error) { + return d.RenderManifestWithChartType(ns, name, vals, ChartTypeEnvoy) +} + +// RenderManifestWithChartType renders the helm chart with the specified chart type. +func (d *Deployer) RenderManifestWithChartType(ns, name string, vals map[string]any, chartType ChartType) ([]byte, error) { mem := driver.NewMemory() mem.SetNamespace(ns) cfg := &action.Configuration{ @@ -203,16 +221,10 @@ func (d *Deployer) RenderManifest(ns, name string, vals map[string]any) ([]byte, install.ClientOnly = true installCtx := context.Background() - // Select the appropriate chart based on whether agentgateway is enabled + // Select the appropriate chart based on chart type chartToUse := d.chart - if d.agentgatewayChart != nil { - if gateway, ok := vals["gateway"].(map[string]any); ok { - if dataPlaneType, ok := gateway["dataPlaneType"].(string); ok { - if dataPlaneType == string(DataPlaneAgentgateway) { - chartToUse = d.agentgatewayChart - } - } - } + if chartType == ChartTypeAgentgateway && d.agentgatewayChart != nil { + chartToUse = d.agentgatewayChart } release, err := install.RunWithContext(installCtx, chartToUse, vals) @@ -250,8 +262,10 @@ func (d *Deployer) GetObjsToDeploy(ctx context.Context, obj client.Object) ([]cl "values", vals, ) + chartType := d.helmValues.GetChartType(ctx, obj) + rname, rns := d.helmReleaseNameAndNamespaceGenerator(obj) - objs, err := d.RenderToObjects(rns, rname, vals) + objs, err := d.RenderToObjectsWithChartType(rns, rname, vals, chartType) if err != nil { return nil, fmt.Errorf("failed to get objects to deploy %s.%s: %w", obj.GetNamespace(), obj.GetName(), err) } diff --git a/pkg/deployer/helm_values_generator.go b/pkg/deployer/helm_values_generator.go index 38218628a89..c7e589ba72b 100644 --- a/pkg/deployer/helm_values_generator.go +++ b/pkg/deployer/helm_values_generator.go @@ -17,6 +17,9 @@ type HelmValuesGenerator interface { // GetCacheSyncHandlers returns the cache sync handlers for the HelmValuesGenerator controller GetCacheSyncHandlers() []cache.InformerSynced + + // GetChartType returns the chart type to use for rendering the given object. + GetChartType(ctx context.Context, obj client.Object) ChartType } // ObjectPostProcessor is an optional interface that can be implemented by HelmValuesGenerator @@ -27,3 +30,14 @@ type ObjectPostProcessor interface { // This is called after helm rendering but before deployment. PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error } + +// ChartType indicates which helm chart to use for rendering. +type ChartType int + +const ( + // ChartTypeEnvoy indicates the Envoy proxy chart should be used. + ChartTypeEnvoy ChartType = iota + // ChartTypeAgentgateway indicates the agentgateway chart should be used. + ChartTypeAgentgateway +) + diff --git a/pkg/deployer/values.go b/pkg/deployer/values.go index 3c497ef7200..d269093415a 100644 --- a/pkg/deployer/values.go +++ b/pkg/deployer/values.go @@ -7,24 +7,14 @@ import ( "github.com/kgateway-dev/kgateway/v2/api/v1alpha1/kgateway" ) -type DataPlaneType string - -const ( - DataPlaneAgentgateway DataPlaneType = "agentgateway" - DataPlaneEnvoy DataPlaneType = "envoy" -) - -// helmConfig stores the top-level helm values used by the deployer. +// HelmConfig stores the top-level helm values used by the deployer for Envoy deployments. type HelmConfig struct { Gateway *HelmGateway `json:"gateway,omitempty"` InferenceExtension *HelmInferenceExtension `json:"inferenceExtension,omitempty"` } +// HelmGateway contains helm values specific to Envoy gateway deployments. type HelmGateway struct { - // not needed by the helm charts, but by the code that select the correct - // helm chart: - DataPlaneType DataPlaneType `json:"dataPlaneType"` - // naming Name *string `json:"name,omitempty"` GatewayName *string `json:"gatewayName,omitempty"` @@ -69,12 +59,8 @@ type HelmGateway struct { Istio *HelmIstio `json:"istio,omitempty"` // envoy container values - ComponentLogLevel *string `json:"componentLogLevel,omitempty"` - - // envoy or agentgateway container values - // Note: ideally, these should be mapped to container specific values, but right now they - // map to the proxy container LogLevel *string `json:"logLevel,omitempty"` + ComponentLogLevel *string `json:"componentLogLevel,omitempty"` Image *HelmImage `json:"image,omitempty"` Resources *corev1.ResourceRequirements `json:"resources,omitempty"` SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"` @@ -83,16 +69,9 @@ type HelmGateway struct { // xds values Xds *HelmXds `json:"xds,omitempty"` - // agentgateway xds values - AgwXds *HelmXds `json:"agwXds,omitempty"` // stats values Stats *HelmStatsConfig `json:"stats,omitempty"` - - // LogFormat specifies the logging format for agentgateway (Json or Text) - LogFormat *string `json:"logFormat,omitempty"` - // RawConfig provides opaque config to be merged into config.yaml - RawConfig map[string]any `json:"rawConfig,omitempty"` } // helmPort represents a Gateway Listener port diff --git a/pkg/kgateway/deployer/agentgateway_parameters.go b/pkg/kgateway/deployer/agentgateway_parameters.go index 2bdde478720..e8a92e75766 100644 --- a/pkg/kgateway/deployer/agentgateway_parameters.go +++ b/pkg/kgateway/deployer/agentgateway_parameters.go @@ -35,7 +35,7 @@ func NewAgentgatewayParametersApplier(params *agentgateway.AgentgatewayParameter // ApplyToHelmValues applies the AgentgatewayParameters configs to the helm // values. This is called before rendering the helm chart. (We render a helm // chart, but we do not use helm beyond that point.) -func (a *AgentgatewayParametersApplier) ApplyToHelmValues(vals *deployer.HelmConfig) { +func (a *AgentgatewayParametersApplier) ApplyToHelmValues(vals *deployer.AgentgatewayHelmConfig) { if a.params == nil || vals == nil || vals.Gateway == nil { return } @@ -189,13 +189,13 @@ func (g *agentgatewayParametersHelmValuesGenerator) GetValues(ctx context.Contex } if g.inputs.ControlPlane.XdsTLS { - if err := injectXdsCACertificate(g.inputs.ControlPlane.XdsTlsCaPath, vals); err != nil { + if err := injectXdsCACertificate(g.inputs.ControlPlane.XdsTlsCaPath, vals.Gateway.Xds, vals.Gateway.AgwXds); err != nil { return nil, fmt.Errorf("failed to inject xDS CA certificate: %w", err) } } var jsonVals map[string]any - err = deployer.JsonConvert(vals, &jsonVals) + err = deployer.AgentgatewayJsonConvert(vals, &jsonVals) return jsonVals, err } @@ -262,6 +262,10 @@ func (g *agentgatewayParametersHelmValuesGenerator) GetCacheSyncHandlers() []cac return []cache.InformerSynced{g.agwParamClient.HasSynced, g.gwClassClient.HasSynced} } +func (g *agentgatewayParametersHelmValuesGenerator) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { + return deployer.ChartTypeAgentgateway +} + // GetResolvedParametersForGateway returns both the GatewayClass-level and Gateway-level // AgentgatewayParameters for the given Gateway. This allows callers to apply overlays // in order (GatewayClass first, then Gateway). @@ -269,15 +273,14 @@ func (g *agentgatewayParametersHelmValuesGenerator) GetResolvedParametersForGate return g.resolveParameters(gw) } -func (g *agentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.HelmConfig, error) { +func (g *agentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.AgentgatewayHelmConfig, error) { irGW := deployer.GetGatewayIR(gw, g.inputs.CommonCollections) ports := deployer.GetPortsValues(irGW, nil, true) // true = agentgateway if len(ports) == 0 { return nil, ErrNoValidPorts } - gtw := &deployer.HelmGateway{ - DataPlaneType: deployer.DataPlaneAgentgateway, + gtw := &deployer.AgentgatewayHelmGateway{ Name: &gw.Name, GatewayName: &gw.Name, GatewayNamespace: &gw.Namespace, @@ -315,7 +318,6 @@ func (g *agentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmVa Tag: ptr.To(deployer.AgentgatewayDefaultTag), PullPolicy: ptr.To(""), } - gtw.DataPlaneType = deployer.DataPlaneAgentgateway gtw.TerminationGracePeriodSeconds = ptr.To(int64(60)) gtw.GracefulShutdown = &kgateway.GracefulShutdownSpec{ @@ -363,5 +365,5 @@ func (g *agentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmVa RunAsUser: ptr.To(int64(10101)), } - return &deployer.HelmConfig{Gateway: gtw}, nil + return &deployer.AgentgatewayHelmConfig{Gateway: gtw}, nil } diff --git a/pkg/kgateway/deployer/agentgateway_parameters_test.go b/pkg/kgateway/deployer/agentgateway_parameters_test.go index b8e95956dc7..e4709714be3 100644 --- a/pkg/kgateway/deployer/agentgateway_parameters_test.go +++ b/pkg/kgateway/deployer/agentgateway_parameters_test.go @@ -19,8 +19,8 @@ import ( func TestAgentgatewayParametersApplier_ApplyToHelmValues_NilParams(t *testing.T) { applier := NewAgentgatewayParametersApplier(nil) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{ + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{ LogLevel: ptr.To("info"), }, } @@ -45,8 +45,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_Image(t *testing.T) { } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{}, + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{}, } applier.ApplyToHelmValues(vals) @@ -76,8 +76,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_Resources(t *testing.T) } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{}, + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{}, } applier.ApplyToHelmValues(vals) @@ -100,8 +100,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_Env(t *testing.T) { } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{ + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{ Env: []corev1.EnvVar{ {Name: "EXISTING_VAR", Value: "existing_value"}, }, @@ -128,8 +128,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_Logging(t *testing.T) { } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{}, + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{}, } applier.ApplyToHelmValues(vals) @@ -227,8 +227,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_RawConfig(t *testing.T) } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{}, + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{}, } applier.ApplyToHelmValues(vals) @@ -267,8 +267,8 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_RawConfigWithLogging(t } applier := NewAgentgatewayParametersApplier(params) - vals := &deployer.HelmConfig{ - Gateway: &deployer.HelmGateway{}, + vals := &deployer.AgentgatewayHelmConfig{ + Gateway: &deployer.AgentgatewayHelmGateway{}, } applier.ApplyToHelmValues(vals) diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 57428c2d3a6..4c97aa9d039 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -122,6 +122,32 @@ func GatewayReleaseNameAndNamespace(obj client.Object) (string, string) { return obj.GetName(), obj.GetNamespace() } +// GetChartType implements deployer.ChartSelector. +// It returns the chart type to use based on the GatewayClass controller name. +func (gp *GatewayParameters) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { + gw, ok := obj.(*gwv1.Gateway) + if !ok { + return deployer.ChartTypeEnvoy + } + + // Check if there's an override + if gp.helmValuesGeneratorOverride != nil { + return gp.helmValuesGeneratorOverride.GetChartType(ctx, obj) + } + + // Get the GatewayClass to check the controller name + gwc := gp.kgwParameters.gwClassClient.Get(string(gw.Spec.GatewayClassName), metav1.NamespaceNone) + if gwc == nil { + return deployer.ChartTypeEnvoy + } + + if string(gwc.Spec.ControllerName) == gp.inputs.AgentgatewayControllerName { + return deployer.ChartTypeAgentgateway + } + + return deployer.ChartTypeEnvoy +} + func (gp *GatewayParameters) getHelmValuesGenerator(obj client.Object) (deployer.HelmValuesGenerator, error) { gw, ok := obj.(*gwv1.Gateway) if !ok { @@ -196,6 +222,10 @@ func (k *kgatewayParameters) GetCacheSyncHandlers() []cache.InformerSynced { return []cache.InformerSynced{k.gwClassClient.HasSynced, k.gwParamClient.HasSynced} } +func (k *kgatewayParameters) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { + return deployer.ChartTypeEnvoy +} + // getGatewayParametersForGateway returns the merged GatewayParameters object resulting from the default GwParams object and // the GwParam object specifically associated with the given Gateway (if one exists). func (k *kgatewayParameters) getGatewayParametersForGateway(gw *gwv1.Gateway) (*kgateway.GatewayParameters, error) { @@ -385,7 +415,7 @@ func (k *kgatewayParameters) getValues(gw *gwv1.Gateway, gwParam *kgateway.Gatew // Inject xDS CA certificate into Helm values if TLS is enabled if k.inputs.ControlPlane.XdsTLS { - if err := injectXdsCACertificate(k.inputs.ControlPlane.XdsTlsCaPath, vals); err != nil { + if err := injectXdsCACertificate(k.inputs.ControlPlane.XdsTlsCaPath, vals.Gateway.Xds); err != nil { return nil, fmt.Errorf("failed to inject xDS CA certificate: %w", err) } } diff --git a/pkg/kgateway/deployer/gateway_parameters_test.go b/pkg/kgateway/deployer/gateway_parameters_test.go index 924a4fa9455..9868f08ac02 100644 --- a/pkg/kgateway/deployer/gateway_parameters_test.go +++ b/pkg/kgateway/deployer/gateway_parameters_test.go @@ -44,6 +44,10 @@ func (thv *testHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynce return nil } +func (thv *testHelmValuesGenerator) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { + return deployer.ChartTypeEnvoy +} + func TestShouldUseDefaultGatewayParameters(t *testing.T) { gwc := defaultGatewayClass() gwParams := emptyGatewayParameters() From ed8d3fe1ce0b858a80ccd1d935255e4f30ad35d8 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Mon, 8 Dec 2025 01:40:56 -0500 Subject: [PATCH 2/8] Two deployers Signed-off-by: David L. Chandler --- pkg/deployer/deployer.go | 57 +------------- pkg/deployer/deployer_test.go | 66 ++++++++-------- pkg/deployer/helm_values_generator.go | 12 --- pkg/kgateway/controller/controller.go | 19 ++++- pkg/kgateway/controller/gw_controller.go | 24 ++++-- .../deployer/agentgateway_parameters.go | 49 +++++++++--- pkg/kgateway/deployer/deployer_factory.go | 27 ++++++- pkg/kgateway/deployer/gateway_parameters.go | 76 ++++++++----------- .../deployer/gateway_parameters_test.go | 4 - test/deployer/deployer_helm.go | 44 +++++++++-- 10 files changed, 203 insertions(+), 175 deletions(-) diff --git a/pkg/deployer/deployer.go b/pkg/deployer/deployer.go index 3f5274976db..71979ed6e75 100644 --- a/pkg/deployer/deployer.go +++ b/pkg/deployer/deployer.go @@ -59,7 +59,6 @@ type Deployer struct { agwControllerName string agwGatewayClassName string chart *chart.Chart - agentgatewayChart *chart.Chart scheme *runtime.Scheme client apiclient.Client helmValues HelmValuesGenerator @@ -82,7 +81,7 @@ func WithGVKToGVRMapper(m map[schema.GroupVersionKind]schema.GroupVersionResourc } } -// NewDeployer creates a new gateway/inference pool/etc +// NewDeployer creates a new gateway/inference pool/etc deployer with a single chart. // TODO [danehans]: Reloading the chart for every reconciliation is inefficient. // See https://github.com/kgateway-dev/kgateway/issues/10672 for details. func NewDeployer( @@ -101,36 +100,6 @@ func NewDeployer( scheme: scheme, client: client, chart: chart, - agentgatewayChart: nil, - helmValues: hvg, - helmReleaseNameAndNamespaceGenerator: helmReleaseNameAndNamespaceGenerator, - patcher: applyPatch, - } - for _, o := range opts { - o(d) - } - return d -} - -// NewDeployerWithMultipleCharts creates a new gateway deployer that supports both envoy and agentgateway charts -func NewDeployerWithMultipleCharts( - controllerName, agwControllerName, agwGatewayClassName string, - scheme *runtime.Scheme, - client apiclient.Client, - envoyChart *chart.Chart, - agentgatewayChart *chart.Chart, - hvg HelmValuesGenerator, - helmReleaseNameAndNamespaceGenerator func(obj client.Object) (string, string), - opts ...Option, -) *Deployer { - d := &Deployer{ - controllerName: controllerName, - agwControllerName: agwControllerName, - agwGatewayClassName: agwGatewayClassName, - scheme: scheme, - client: client, - chart: envoyChart, - agentgatewayChart: agentgatewayChart, helmValues: hvg, helmReleaseNameAndNamespaceGenerator: helmReleaseNameAndNamespaceGenerator, patcher: applyPatch, @@ -183,12 +152,7 @@ func (d *Deployer) RenderChartToObjects(ns, name string, vals map[string]any) ([ // It returns the list of Objects that are rendered, and an optional error if rendering failed, // or converting the rendered manifests to objects failed. func (d *Deployer) RenderToObjects(ns, name string, vals map[string]any) ([]client.Object, error) { - return d.RenderToObjectsWithChartType(ns, name, vals, ChartTypeEnvoy) -} - -// RenderToObjectsWithChartType renders the helm chart with the specified chart type. -func (d *Deployer) RenderToObjectsWithChartType(ns, name string, vals map[string]any, chartType ChartType) ([]client.Object, error) { - manifest, err := d.RenderManifestWithChartType(ns, name, vals, chartType) + manifest, err := d.RenderManifest(ns, name, vals) if err != nil { return nil, err } @@ -201,11 +165,6 @@ func (d *Deployer) RenderToObjectsWithChartType(ns, name string, vals map[string } func (d *Deployer) RenderManifest(ns, name string, vals map[string]any) ([]byte, error) { - return d.RenderManifestWithChartType(ns, name, vals, ChartTypeEnvoy) -} - -// RenderManifestWithChartType renders the helm chart with the specified chart type. -func (d *Deployer) RenderManifestWithChartType(ns, name string, vals map[string]any, chartType ChartType) ([]byte, error) { mem := driver.NewMemory() mem.SetNamespace(ns) cfg := &action.Configuration{ @@ -221,13 +180,7 @@ func (d *Deployer) RenderManifestWithChartType(ns, name string, vals map[string] install.ClientOnly = true installCtx := context.Background() - // Select the appropriate chart based on chart type - chartToUse := d.chart - if chartType == ChartTypeAgentgateway && d.agentgatewayChart != nil { - chartToUse = d.agentgatewayChart - } - - release, err := install.RunWithContext(installCtx, chartToUse, vals) + release, err := install.RunWithContext(installCtx, d.chart, vals) if err != nil { return nil, fmt.Errorf("failed to render helm chart for %s.%s: %w", ns, name, err) } @@ -262,10 +215,8 @@ func (d *Deployer) GetObjsToDeploy(ctx context.Context, obj client.Object) ([]cl "values", vals, ) - chartType := d.helmValues.GetChartType(ctx, obj) - rname, rns := d.helmReleaseNameAndNamespaceGenerator(obj) - objs, err := d.RenderToObjectsWithChartType(rns, rname, vals, chartType) + objs, err := d.RenderToObjects(rns, rname, vals) if err != nil { return nil, fmt.Errorf("failed to get objects to deploy %s.%s: %w", obj.GetNamespace(), obj.GetName(), err) } diff --git a/pkg/deployer/deployer_test.go b/pkg/deployer/deployer_test.go index 1258960b23d..b90c80b3311 100644 --- a/pkg/deployer/deployer_test.go +++ b/pkg/deployer/deployer_test.go @@ -390,13 +390,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwp, + gwp.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -477,13 +477,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err = deployerinternal.NewGatewayDeployer( + d, err = deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -557,13 +557,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewAgentgatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.AgentgatewayHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -675,13 +675,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -748,13 +748,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -837,13 +837,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -932,13 +932,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1023,13 +1023,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d1, err := deployerinternal.NewGatewayDeployer( + d1, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams1, + gwParams1.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) @@ -1050,13 +1050,13 @@ var _ = Describe("Deployer", func() { AgentgatewayClassName: wellknown.DefaultAgwClassName, AgentgatewayControllerName: wellknown.DefaultAgwControllerName, }) - d2, err := deployerinternal.NewGatewayDeployer( + d2, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams2, + gwParams2.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1123,13 +1123,13 @@ var _ = Describe("Deployer", func() { Tag: "bar", }, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1171,13 +1171,13 @@ var _ = Describe("Deployer", func() { Tag: "bar", }, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1232,13 +1232,13 @@ var _ = Describe("Deployer", func() { Tag: tag, }, }) - d, err = deployerinternal.NewGatewayDeployer( + d, err = deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1323,13 +1323,13 @@ var _ = Describe("Deployer", func() { Tag: tag, }, }) - d, err = deployerinternal.NewGatewayDeployer( + d, err = deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -1418,13 +1418,13 @@ var _ = Describe("Deployer", func() { Tag: tag, }, }) - d, err = deployerinternal.NewGatewayDeployer( + d, err = deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -2045,13 +2045,13 @@ var _ = Describe("Deployer", func() { fakeClient := fake.NewClient(GinkgoT(), gwc, defaultGwp, overrideGwp) gwParams := deployerinternal.NewGatewayParameters(fakeClient, inp.dInputs) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -2472,13 +2472,13 @@ var _ = Describe("Deployer", func() { Tag: "bar", }, }) - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) @@ -2709,7 +2709,7 @@ var _ = Describe("DeployObjs", func() { ) getDeployer := func(fc apiclient.Client, patcher deployer.Patcher) *deployer.Deployer { - d, err := deployerinternal.NewGatewayDeployer( + d, err := deployerinternal.NewEnvoyGatewayDeployer( wellknown.DefaultGatewayControllerName, wellknown.DefaultAgwControllerName, wellknown.DefaultAgwClassName, diff --git a/pkg/deployer/helm_values_generator.go b/pkg/deployer/helm_values_generator.go index c7e589ba72b..c64ed84bd75 100644 --- a/pkg/deployer/helm_values_generator.go +++ b/pkg/deployer/helm_values_generator.go @@ -17,9 +17,6 @@ type HelmValuesGenerator interface { // GetCacheSyncHandlers returns the cache sync handlers for the HelmValuesGenerator controller GetCacheSyncHandlers() []cache.InformerSynced - - // GetChartType returns the chart type to use for rendering the given object. - GetChartType(ctx context.Context, obj client.Object) ChartType } // ObjectPostProcessor is an optional interface that can be implemented by HelmValuesGenerator @@ -31,13 +28,4 @@ type ObjectPostProcessor interface { PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error } -// ChartType indicates which helm chart to use for rendering. -type ChartType int - -const ( - // ChartTypeEnvoy indicates the Envoy proxy chart should be used. - ChartTypeEnvoy ChartType = iota - // ChartTypeAgentgateway indicates the agentgateway chart should be used. - ChartTypeAgentgateway -) diff --git a/pkg/kgateway/controller/controller.go b/pkg/kgateway/controller/controller.go index cca6495e38f..776b4777b01 100644 --- a/pkg/kgateway/controller/controller.go +++ b/pkg/kgateway/controller/controller.go @@ -115,17 +115,30 @@ func watchGw( gwParams.WithHelmValuesGeneratorOverride(helmValuesGeneratorOverride(inputs)) } - d, err := internaldeployer.NewGatewayDeployer( + // Create separate deployers for envoy and agentgateway + envoyDeployer, err := internaldeployer.NewEnvoyGatewayDeployer( cfg.ControllerName, cfg.AgwControllerName, cfg.AgentgatewayClassName, cfg.Mgr.GetScheme(), cfg.Client, - gwParams, + gwParams.EnvoyHelmValuesGenerator(), ) if err != nil { return err } - return cfg.Mgr.Add(NewGatewayReconciler(cfg, d, gwParams, gatewayControllerExtension)) + agwDeployer, err := internaldeployer.NewAgentgatewayDeployer( + cfg.ControllerName, + cfg.AgwControllerName, + cfg.AgentgatewayClassName, + cfg.Mgr.GetScheme(), + cfg.Client, + gwParams.AgentgatewayHelmValuesGenerator(), + ) + if err != nil { + return err + } + + return cfg.Mgr.Add(NewGatewayReconciler(cfg, envoyDeployer, agwDeployer, gwParams, gatewayControllerExtension)) } diff --git a/pkg/kgateway/controller/gw_controller.go b/pkg/kgateway/controller/gw_controller.go index 37538e28109..0f6a5e4c7ce 100644 --- a/pkg/kgateway/controller/gw_controller.go +++ b/pkg/kgateway/controller/gw_controller.go @@ -50,7 +50,8 @@ var logger = logging.New("gateway-controller") var _ manager.LeaderElectionRunnable = (*gatewayReconciler)(nil) type gatewayReconciler struct { - deployer *deployer.Deployer + envoyDeployer *deployer.Deployer + agwDeployer *deployer.Deployer gwParams *internaldeployer.GatewayParameters scheme *runtime.Scheme controllerName string @@ -74,13 +75,15 @@ type gatewayReconciler struct { func NewGatewayReconciler( cfg GatewayConfig, - deployer *deployer.Deployer, + envoyDeployer *deployer.Deployer, + agwDeployer *deployer.Deployer, gwParams *internaldeployer.GatewayParameters, controllerExtension pluginsdk.GatewayControllerExtension, ) *gatewayReconciler { filter := kclient.Filter{ObjectFilter: cfg.Client.ObjectFilter()} r := &gatewayReconciler{ - deployer: deployer, + envoyDeployer: envoyDeployer, + agwDeployer: agwDeployer, gwParams: gwParams, scheme: cfg.Mgr.GetScheme(), controllerName: cfg.ControllerName, @@ -298,7 +301,16 @@ func (r *gatewayReconciler) Reconcile(req types.NamespacedName) (rErr error) { logger.Info("reconciling Gateway", "ref", req) ctx := context.Background() - objs, err := r.deployer.GetObjsToDeploy(ctx, gw) + + // Select the appropriate deployer based on the GatewayClass controller + var d *deployer.Deployer + if isEnvoyGateway { + d = r.envoyDeployer + } else { + d = r.agwDeployer + } + + objs, err := d.GetObjsToDeploy(ctx, gw) if err != nil { if errors.Is(err, internaldeployer.ErrNoValidPorts) { // status is reported from translator, so return normally @@ -333,8 +345,8 @@ func (r *gatewayReconciler) Reconcile(req types.NamespacedName) (rErr error) { return fmt.Errorf("failed to update status for Gateway %s: %w", req, statusErr) } } - objs = r.deployer.SetNamespaceAndOwnerWithGVK(gw, wellknown.GatewayGVK, objs) - err = r.deployer.DeployObjsWithSource(ctx, objs, gw) + objs = d.SetNamespaceAndOwnerWithGVK(gw, wellknown.GatewayGVK, objs) + err = d.DeployObjsWithSource(ctx, objs, gw) if err != nil { return err } diff --git a/pkg/kgateway/deployer/agentgateway_parameters.go b/pkg/kgateway/deployer/agentgateway_parameters.go index e8a92e75766..73053aa649e 100644 --- a/pkg/kgateway/deployer/agentgateway_parameters.go +++ b/pkg/kgateway/deployer/agentgateway_parameters.go @@ -146,14 +146,14 @@ func (a *AgentgatewayParametersApplier) ApplyOverlaysToObjects(objs []client.Obj return applier.ApplyOverlays(objs) } -type agentgatewayParametersHelmValuesGenerator struct { +type AgentgatewayParametersHelmValuesGenerator struct { agwParamClient kclient.Client[*agentgateway.AgentgatewayParameters] gwClassClient kclient.Client[*gwv1.GatewayClass] inputs *deployer.Inputs } -func newAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs *deployer.Inputs) *agentgatewayParametersHelmValuesGenerator { - return &agentgatewayParametersHelmValuesGenerator{ +func newAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs *deployer.Inputs) *AgentgatewayHelmValuesGenerator { + return &AgentgatewayParametersHelmValuesGenerator{ agwParamClient: kclient.NewFilteredDelayed[*agentgateway.AgentgatewayParameters](cli, wellknown.AgentgatewayParametersGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), gwClassClient: kclient.NewFilteredDelayed[*gwv1.GatewayClass](cli, wellknown.GatewayClassGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), inputs: inputs, @@ -161,7 +161,7 @@ func newAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs * } // GetValues returns helm values derived from AgentgatewayParameters. -func (g *agentgatewayParametersHelmValuesGenerator) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { +func (g *AgentgatewayHelmValuesGenerator) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { gw, ok := obj.(*gwv1.Gateway) if !ok { return nil, fmt.Errorf("expected a Gateway resource, got %s", obj.GetObjectKind().GroupVersionKind().String()) @@ -211,7 +211,7 @@ type resolvedParameters struct { // resolveParameters resolves the AgentgatewayParameters for the Gateway. // It returns both GatewayClass-level and Gateway-level // separately to support ordered overlay merging (GatewayClass first, then Gateway). -func (g *agentgatewayParametersHelmValuesGenerator) resolveParameters(gw *gwv1.Gateway) (*resolvedParameters, error) { +func (g *AgentgatewayHelmValuesGenerator) resolveParameters(gw *gwv1.Gateway) (*resolvedParameters, error) { result := &resolvedParameters{} // Get GatewayClass parameters first @@ -258,22 +258,51 @@ func (g *agentgatewayParametersHelmValuesGenerator) resolveParameters(gw *gwv1.G return result, nil } -func (g *agentgatewayParametersHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynced { +func (g *AgentgatewayHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynced { return []cache.InformerSynced{g.agwParamClient.HasSynced, g.gwClassClient.HasSynced} } -func (g *agentgatewayParametersHelmValuesGenerator) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { - return deployer.ChartTypeAgentgateway +// PostProcessObjects implements deployer.ObjectPostProcessor. +// It applies AgentgatewayParameters overlays to the rendered objects. +// When both GatewayClass and Gateway have AgentgatewayParameters, the overlays +// are applied in order: GatewayClass first, then Gateway on top. +func (g *AgentgatewayHelmValuesGenerator) PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error { + gw, ok := obj.(*gwv1.Gateway) + if !ok { + return nil + } + + resolved, err := g.GetResolvedParametersForGateway(gw) + if err != nil { + return nil + } + + // Apply overlays in order: GatewayClass first, then Gateway. + // This allows Gateway-level overlays to override GatewayClass-level overlays. + if resolved.gatewayClassAGWP != nil { + applier := NewAgentgatewayParametersApplier(resolved.gatewayClassAGWP) + if err := applier.ApplyOverlaysToObjects(rendered); err != nil { + return err + } + } + if resolved.gatewayAGWP != nil { + applier := NewAgentgatewayParametersApplier(resolved.gatewayAGWP) + if err := applier.ApplyOverlaysToObjects(rendered); err != nil { + return err + } + } + + return nil } // GetResolvedParametersForGateway returns both the GatewayClass-level and Gateway-level // AgentgatewayParameters for the given Gateway. This allows callers to apply overlays // in order (GatewayClass first, then Gateway). -func (g *agentgatewayParametersHelmValuesGenerator) GetResolvedParametersForGateway(gw *gwv1.Gateway) (*resolvedParameters, error) { +func (g *AgentgatewayHelmValuesGenerator) GetResolvedParametersForGateway(gw *gwv1.Gateway) (*resolvedParameters, error) { return g.resolveParameters(gw) } -func (g *agentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.AgentgatewayHelmConfig, error) { +func (g *AgentgatewayHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.AgentgatewayHelmConfig, error) { irGW := deployer.GetGatewayIR(gw, g.inputs.CommonCollections) ports := deployer.GetPortsValues(irGW, nil, true) // true = agentgateway if len(ports) == 0 { diff --git a/pkg/kgateway/deployer/deployer_factory.go b/pkg/kgateway/deployer/deployer_factory.go index 6935cb22b6b..06f1d697c49 100644 --- a/pkg/kgateway/deployer/deployer_factory.go +++ b/pkg/kgateway/deployer/deployer_factory.go @@ -7,15 +7,36 @@ import ( "github.com/kgateway-dev/kgateway/v2/pkg/deployer" ) -func NewGatewayDeployer(controllerName, agwControllerName, agwGatewayClassName string, scheme *runtime.Scheme, client apiclient.Client, gwParams *GatewayParameters, opts ...deployer.Option) (*deployer.Deployer, error) { +// NewEnvoyGatewayDeployer creates a deployer for Envoy-based gateways. +func NewEnvoyGatewayDeployer( + controllerName, agwControllerName, agwGatewayClassName string, + scheme *runtime.Scheme, + client apiclient.Client, + hvg deployer.HelmValuesGenerator, + opts ...deployer.Option, +) (*deployer.Deployer, error) { envoyChart, err := LoadEnvoyChart() if err != nil { return nil, err } + return deployer.NewDeployer( + controllerName, agwControllerName, agwGatewayClassName, + scheme, client, envoyChart, hvg, GatewayReleaseNameAndNamespace, opts...), nil +} + +// NewAgentgatewayDeployer creates a deployer for agentgateway-based gateways. +func NewAgentgatewayDeployer( + controllerName, agwControllerName, agwGatewayClassName string, + scheme *runtime.Scheme, + client apiclient.Client, + hvg deployer.HelmValuesGenerator, + opts ...deployer.Option, +) (*deployer.Deployer, error) { agentgatewayChart, err := LoadAgentgatewayChart() if err != nil { return nil, err } - return deployer.NewDeployerWithMultipleCharts( - controllerName, agwControllerName, agwGatewayClassName, scheme, client, envoyChart, agentgatewayChart, gwParams, GatewayReleaseNameAndNamespace, opts...), nil + return deployer.NewDeployer( + controllerName, agwControllerName, agwGatewayClassName, + scheme, client, agentgatewayChart, hvg, GatewayReleaseNameAndNamespace, opts...), nil } diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 4c97aa9d039..06b483c7302 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -35,8 +35,8 @@ func NewGatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *Gatewa gp := &GatewayParameters{ inputs: inputs, // build this once versus on every getHelmValuesGenerator call - kgwParameters: newkgatewayParameters(cli, inputs), - agwHelmValuesGenerator: newAgentgatewayParametersHelmValuesGenerator(cli, inputs), + kgwParameters: NewEnvoyGatewayParameters(cli, inputs), + agwHelmValuesGenerator: NewAgentgatewayHelmValuesGenerator(cli, inputs), } return gp @@ -45,11 +45,12 @@ func NewGatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *Gatewa type GatewayParameters struct { inputs *deployer.Inputs helmValuesGeneratorOverride deployer.HelmValuesGenerator - kgwParameters *kgatewayParameters - agwHelmValuesGenerator *agentgatewayParametersHelmValuesGenerator + kgwParameters *EnvoyGatewayParameters + agwHelmValuesGenerator *AgentgatewayHelmValuesGenerator } -type kgatewayParameters struct { +// EnvoyGatewayParameters generates helm values for Envoy-based gateways. +type EnvoyGatewayParameters struct { gwParamClient kclient.Client[*kgateway.GatewayParameters] gwClassClient kclient.Client[*gwv1.GatewayClass] inputs *deployer.Inputs @@ -85,6 +86,24 @@ func (gp *GatewayParameters) GetCacheSyncHandlers() []cache.InformerSynced { return gp.kgwParameters.GetCacheSyncHandlers() } +// EnvoyHelmValuesGenerator returns the helm values generator for Envoy-based gateways. +// If a helm values generator override is set, it returns that instead. +func (gp *GatewayParameters) EnvoyHelmValuesGenerator() deployer.HelmValuesGenerator { + if gp.helmValuesGeneratorOverride != nil { + return gp.helmValuesGeneratorOverride + } + return gp.kgwParameters +} + +// AgentgatewayHelmValuesGenerator returns the helm values generator for agentgateway-based gateways. +// If a helm values generator override is set, it returns that instead. +func (gp *GatewayParameters) AgentgatewayHelmValuesGenerator() deployer.HelmValuesGenerator { + if gp.helmValuesGeneratorOverride != nil { + return gp.helmValuesGeneratorOverride + } + return gp.agwHelmValuesGenerator +} + // PostProcessObjects implements deployer.ObjectPostProcessor. // It applies AgentgatewayParameters overlays to the rendered objects. // When both GatewayClass and Gateway have AgentgatewayParameters, the overlays @@ -122,32 +141,6 @@ func GatewayReleaseNameAndNamespace(obj client.Object) (string, string) { return obj.GetName(), obj.GetNamespace() } -// GetChartType implements deployer.ChartSelector. -// It returns the chart type to use based on the GatewayClass controller name. -func (gp *GatewayParameters) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { - gw, ok := obj.(*gwv1.Gateway) - if !ok { - return deployer.ChartTypeEnvoy - } - - // Check if there's an override - if gp.helmValuesGeneratorOverride != nil { - return gp.helmValuesGeneratorOverride.GetChartType(ctx, obj) - } - - // Get the GatewayClass to check the controller name - gwc := gp.kgwParameters.gwClassClient.Get(string(gw.Spec.GatewayClassName), metav1.NamespaceNone) - if gwc == nil { - return deployer.ChartTypeEnvoy - } - - if string(gwc.Spec.ControllerName) == gp.inputs.AgentgatewayControllerName { - return deployer.ChartTypeAgentgateway - } - - return deployer.ChartTypeEnvoy -} - func (gp *GatewayParameters) getHelmValuesGenerator(obj client.Object) (deployer.HelmValuesGenerator, error) { gw, ok := obj.(*gwv1.Gateway) if !ok { @@ -186,15 +179,16 @@ func (gp *GatewayParameters) getHelmValuesGenerator(obj client.Object) (deployer return gp.kgwParameters, nil } -func newkgatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *kgatewayParameters { - return &kgatewayParameters{ +// NewEnvoyGatewayParameters creates a new EnvoyGatewayParameters. +func NewEnvoyGatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *EnvoyGatewayParameters { + return &EnvoyGatewayParameters{ gwParamClient: kclient.NewFilteredDelayed[*kgateway.GatewayParameters](cli, wellknown.GatewayParametersGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), gwClassClient: kclient.NewFilteredDelayed[*gwv1.GatewayClass](cli, wellknown.GatewayClassGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), inputs: inputs, } } -func (h *kgatewayParameters) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { +func (h *EnvoyGatewayParameters) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { gw, ok := obj.(*gwv1.Gateway) if !ok { return nil, fmt.Errorf("expected a Gateway resource, got %s", obj.GetObjectKind().GroupVersionKind().String()) @@ -218,17 +212,13 @@ func (h *kgatewayParameters) GetValues(ctx context.Context, obj client.Object) ( return jsonVals, err } -func (k *kgatewayParameters) GetCacheSyncHandlers() []cache.InformerSynced { +func (k *EnvoyGatewayParameters) GetCacheSyncHandlers() []cache.InformerSynced { return []cache.InformerSynced{k.gwClassClient.HasSynced, k.gwParamClient.HasSynced} } -func (k *kgatewayParameters) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { - return deployer.ChartTypeEnvoy -} - // getGatewayParametersForGateway returns the merged GatewayParameters object resulting from the default GwParams object and // the GwParam object specifically associated with the given Gateway (if one exists). -func (k *kgatewayParameters) getGatewayParametersForGateway(gw *gwv1.Gateway) (*kgateway.GatewayParameters, error) { +func (k *EnvoyGatewayParameters) getGatewayParametersForGateway(gw *gwv1.Gateway) (*kgateway.GatewayParameters, error) { // attempt to get the GatewayParameters name from the Gateway. If we can't find it, // we'll check for the default GWP for the GatewayClass. if gw.Spec.Infrastructure == nil || gw.Spec.Infrastructure.ParametersRef == nil { @@ -294,7 +284,7 @@ func (k *kgatewayParameters) getGatewayParametersForGateway(gw *gwv1.Gateway) (* } // gets the default GatewayParameters associated with the GatewayClass of the provided Gateway -func (k *kgatewayParameters) getDefaultGatewayParameters(gw *gwv1.Gateway) (*kgateway.GatewayParameters, error) { +func (k *EnvoyGatewayParameters) getDefaultGatewayParameters(gw *gwv1.Gateway) (*kgateway.GatewayParameters, error) { gwc, err := getGatewayClassFromGateway(k.gwClassClient, gw) if err != nil { return nil, err @@ -303,7 +293,7 @@ func (k *kgatewayParameters) getDefaultGatewayParameters(gw *gwv1.Gateway) (*kga } // Gets the GatewayParameters object associated with a given GatewayClass. -func (k *kgatewayParameters) getGatewayParametersForGatewayClass(gwc *gwv1.GatewayClass) (*kgateway.GatewayParameters, error) { +func (k *EnvoyGatewayParameters) getGatewayParametersForGatewayClass(gwc *gwv1.GatewayClass) (*kgateway.GatewayParameters, error) { // Our defaults depend on OmitDefaultSecurityContext, but these are the defaults // when not OmitDefaultSecurityContext: defaultGwp, err := deployer.GetInMemoryGatewayParameters(deployer.InMemoryGatewayParametersConfig{ @@ -379,7 +369,7 @@ func (k *kgatewayParameters) getGatewayParametersForGatewayClass(gwc *gwv1.Gatew return mergedGwp, nil } -func (k *kgatewayParameters) getValues(gw *gwv1.Gateway, gwParam *kgateway.GatewayParameters) (*deployer.HelmConfig, error) { +func (k *EnvoyGatewayParameters) getValues(gw *gwv1.Gateway, gwParam *kgateway.GatewayParameters) (*deployer.HelmConfig, error) { irGW := deployer.GetGatewayIR(gw, k.inputs.CommonCollections) // kgatewayParameters is only used for envoy gateways (agentgateway uses agentgatewayParametersHelmValuesGenerator) ports := deployer.GetPortsValues(irGW, gwParam, false) diff --git a/pkg/kgateway/deployer/gateway_parameters_test.go b/pkg/kgateway/deployer/gateway_parameters_test.go index 9868f08ac02..924a4fa9455 100644 --- a/pkg/kgateway/deployer/gateway_parameters_test.go +++ b/pkg/kgateway/deployer/gateway_parameters_test.go @@ -44,10 +44,6 @@ func (thv *testHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynce return nil } -func (thv *testHelmValuesGenerator) GetChartType(ctx context.Context, obj client.Object) deployer.ChartType { - return deployer.ChartTypeEnvoy -} - func TestShouldUseDefaultGatewayParameters(t *testing.T) { gwc := defaultGatewayClass() gwParams := emptyGatewayParameters() diff --git a/test/deployer/deployer_helm.go b/test/deployer/deployer_helm.go index 36ad159ff18..644d96c49eb 100644 --- a/test/deployer/deployer_helm.go +++ b/test/deployer/deployer_helm.go @@ -108,6 +108,18 @@ func ExtractCommonObjs(t *testing.T, objs []client.Object) ([]client.Object, *gw return commonObjs, gtw } +// isAgentgatewayClass returns true if the Gateway's GatewayClass uses the agentgateway controller. +func (dt DeployerTester) isAgentgatewayClass(gw *gwv1.Gateway, objs []client.Object) bool { + for _, obj := range objs { + if gwc, ok := obj.(*gwv1.GatewayClass); ok { + if gwc.Name == string(gw.Spec.GatewayClassName) { + return string(gwc.Spec.ControllerName) == dt.AgwControllerName + } + } + } + return false +} + func (dt DeployerTester) GetObjects( t *testing.T, tt HelmTestCase, @@ -158,14 +170,30 @@ func (dt DeployerTester) RunHelmChartTest( if tt.HelmValuesGeneratorOverride != nil { gwParams.WithHelmValuesGeneratorOverride(tt.HelmValuesGeneratorOverride(inputs)) } - deployer, err := internaldeployer.NewGatewayDeployer( - dt.ControllerName, - dt.AgwControllerName, - dt.AgwClassName, - scheme, - fakeClient, - gwParams, - ) + + // Determine which deployer to use based on the GatewayClass + var deployer *pkgdeployer.Deployer + var err error + isAgentgateway := dt.isAgentgatewayClass(gtw, commonObjs) + if isAgentgateway { + deployer, err = internaldeployer.NewAgentgatewayDeployer( + dt.ControllerName, + dt.AgwControllerName, + dt.AgwClassName, + scheme, + fakeClient, + gwParams.AgentgatewayHelmValuesGenerator(), + ) + } else { + deployer, err = internaldeployer.NewEnvoyGatewayDeployer( + dt.ControllerName, + dt.AgwControllerName, + dt.AgwClassName, + scheme, + fakeClient, + gwParams.EnvoyHelmValuesGenerator(), + ) + } assert.NoError(t, err, "error creating gateway deployer") ctx := t.Context() From f91c67e9c752b94b41bc864c22576c470bace0bd Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Tue, 9 Dec 2025 02:20:04 -0500 Subject: [PATCH 3/8] fixup Signed-off-by: David L. Chandler --- pkg/deployer/deployer_test.go | 2 +- pkg/deployer/helm_values_generator.go | 2 -- pkg/kgateway/controller/controller.go | 2 +- pkg/kgateway/deployer/agentgateway_parameters.go | 14 +++++++------- pkg/kgateway/deployer/gateway_parameters.go | 11 ++++------- pkg/kgateway/deployer/tls.go | 12 ++++++------ test/deployer/deployer_helm.go | 2 +- 7 files changed, 20 insertions(+), 25 deletions(-) diff --git a/pkg/deployer/deployer_test.go b/pkg/deployer/deployer_test.go index b90c80b3311..fd11dbdf22b 100644 --- a/pkg/deployer/deployer_test.go +++ b/pkg/deployer/deployer_test.go @@ -563,7 +563,7 @@ var _ = Describe("Deployer", func() { wellknown.DefaultAgwClassName, scheme, fakeClient, - gwParams.AgentgatewayHelmValuesGenerator(), + gwParams.AgentgatewayParametersHelmValuesGenerator(), ) Expect(err).NotTo(HaveOccurred()) fakeClient.RunAndWait(context.Background().Done()) diff --git a/pkg/deployer/helm_values_generator.go b/pkg/deployer/helm_values_generator.go index c64ed84bd75..38218628a89 100644 --- a/pkg/deployer/helm_values_generator.go +++ b/pkg/deployer/helm_values_generator.go @@ -27,5 +27,3 @@ type ObjectPostProcessor interface { // This is called after helm rendering but before deployment. PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error } - - diff --git a/pkg/kgateway/controller/controller.go b/pkg/kgateway/controller/controller.go index 776b4777b01..af597ea77d1 100644 --- a/pkg/kgateway/controller/controller.go +++ b/pkg/kgateway/controller/controller.go @@ -134,7 +134,7 @@ func watchGw( cfg.AgentgatewayClassName, cfg.Mgr.GetScheme(), cfg.Client, - gwParams.AgentgatewayHelmValuesGenerator(), + gwParams.AgentgatewayParametersHelmValuesGenerator(), ) if err != nil { return err diff --git a/pkg/kgateway/deployer/agentgateway_parameters.go b/pkg/kgateway/deployer/agentgateway_parameters.go index 73053aa649e..ccceb23edf2 100644 --- a/pkg/kgateway/deployer/agentgateway_parameters.go +++ b/pkg/kgateway/deployer/agentgateway_parameters.go @@ -152,7 +152,7 @@ type AgentgatewayParametersHelmValuesGenerator struct { inputs *deployer.Inputs } -func newAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs *deployer.Inputs) *AgentgatewayHelmValuesGenerator { +func NewAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs *deployer.Inputs) *AgentgatewayParametersHelmValuesGenerator { return &AgentgatewayParametersHelmValuesGenerator{ agwParamClient: kclient.NewFilteredDelayed[*agentgateway.AgentgatewayParameters](cli, wellknown.AgentgatewayParametersGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), gwClassClient: kclient.NewFilteredDelayed[*gwv1.GatewayClass](cli, wellknown.GatewayClassGVR, kclient.Filter{ObjectFilter: cli.ObjectFilter()}), @@ -161,7 +161,7 @@ func newAgentgatewayParametersHelmValuesGenerator(cli apiclient.Client, inputs * } // GetValues returns helm values derived from AgentgatewayParameters. -func (g *AgentgatewayHelmValuesGenerator) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { +func (g *AgentgatewayParametersHelmValuesGenerator) GetValues(ctx context.Context, obj client.Object) (map[string]any, error) { gw, ok := obj.(*gwv1.Gateway) if !ok { return nil, fmt.Errorf("expected a Gateway resource, got %s", obj.GetObjectKind().GroupVersionKind().String()) @@ -211,7 +211,7 @@ type resolvedParameters struct { // resolveParameters resolves the AgentgatewayParameters for the Gateway. // It returns both GatewayClass-level and Gateway-level // separately to support ordered overlay merging (GatewayClass first, then Gateway). -func (g *AgentgatewayHelmValuesGenerator) resolveParameters(gw *gwv1.Gateway) (*resolvedParameters, error) { +func (g *AgentgatewayParametersHelmValuesGenerator) resolveParameters(gw *gwv1.Gateway) (*resolvedParameters, error) { result := &resolvedParameters{} // Get GatewayClass parameters first @@ -258,7 +258,7 @@ func (g *AgentgatewayHelmValuesGenerator) resolveParameters(gw *gwv1.Gateway) (* return result, nil } -func (g *AgentgatewayHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynced { +func (g *AgentgatewayParametersHelmValuesGenerator) GetCacheSyncHandlers() []cache.InformerSynced { return []cache.InformerSynced{g.agwParamClient.HasSynced, g.gwClassClient.HasSynced} } @@ -266,7 +266,7 @@ func (g *AgentgatewayHelmValuesGenerator) GetCacheSyncHandlers() []cache.Informe // It applies AgentgatewayParameters overlays to the rendered objects. // When both GatewayClass and Gateway have AgentgatewayParameters, the overlays // are applied in order: GatewayClass first, then Gateway on top. -func (g *AgentgatewayHelmValuesGenerator) PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error { +func (g *AgentgatewayParametersHelmValuesGenerator) PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error { gw, ok := obj.(*gwv1.Gateway) if !ok { return nil @@ -298,11 +298,11 @@ func (g *AgentgatewayHelmValuesGenerator) PostProcessObjects(ctx context.Context // GetResolvedParametersForGateway returns both the GatewayClass-level and Gateway-level // AgentgatewayParameters for the given Gateway. This allows callers to apply overlays // in order (GatewayClass first, then Gateway). -func (g *AgentgatewayHelmValuesGenerator) GetResolvedParametersForGateway(gw *gwv1.Gateway) (*resolvedParameters, error) { +func (g *AgentgatewayParametersHelmValuesGenerator) GetResolvedParametersForGateway(gw *gwv1.Gateway) (*resolvedParameters, error) { return g.resolveParameters(gw) } -func (g *AgentgatewayHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.AgentgatewayHelmConfig, error) { +func (g *AgentgatewayParametersHelmValuesGenerator) getDefaultAgentgatewayHelmValues(gw *gwv1.Gateway) (*deployer.AgentgatewayHelmConfig, error) { irGW := deployer.GetGatewayIR(gw, g.inputs.CommonCollections) ports := deployer.GetPortsValues(irGW, nil, true) // true = agentgateway if len(ports) == 0 { diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 06b483c7302..526a51b0808 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -36,7 +36,7 @@ func NewGatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *Gatewa inputs: inputs, // build this once versus on every getHelmValuesGenerator call kgwParameters: NewEnvoyGatewayParameters(cli, inputs), - agwHelmValuesGenerator: NewAgentgatewayHelmValuesGenerator(cli, inputs), + agwHelmValuesGenerator: NewAgentgatewayParametersHelmValuesGenerator(cli, inputs), } return gp @@ -46,7 +46,7 @@ type GatewayParameters struct { inputs *deployer.Inputs helmValuesGeneratorOverride deployer.HelmValuesGenerator kgwParameters *EnvoyGatewayParameters - agwHelmValuesGenerator *AgentgatewayHelmValuesGenerator + agwHelmValuesGenerator *AgentgatewayParametersHelmValuesGenerator } // EnvoyGatewayParameters generates helm values for Envoy-based gateways. @@ -95,9 +95,9 @@ func (gp *GatewayParameters) EnvoyHelmValuesGenerator() deployer.HelmValuesGener return gp.kgwParameters } -// AgentgatewayHelmValuesGenerator returns the helm values generator for agentgateway-based gateways. +// AgentgatewayParametersHelmValuesGenerator returns the helm values generator for agentgateway-based gateways. // If a helm values generator override is set, it returns that instead. -func (gp *GatewayParameters) AgentgatewayHelmValuesGenerator() deployer.HelmValuesGenerator { +func (gp *GatewayParameters) AgentgatewayParametersHelmValuesGenerator() deployer.HelmValuesGenerator { if gp.helmValuesGeneratorOverride != nil { return gp.helmValuesGeneratorOverride } @@ -371,7 +371,6 @@ func (k *EnvoyGatewayParameters) getGatewayParametersForGatewayClass(gwc *gwv1.G func (k *EnvoyGatewayParameters) getValues(gw *gwv1.Gateway, gwParam *kgateway.GatewayParameters) (*deployer.HelmConfig, error) { irGW := deployer.GetGatewayIR(gw, k.inputs.CommonCollections) - // kgatewayParameters is only used for envoy gateways (agentgateway uses agentgatewayParametersHelmValuesGenerator) ports := deployer.GetPortsValues(irGW, gwParam, false) if len(ports) == 0 { return nil, ErrNoValidPorts @@ -466,8 +465,6 @@ func (k *EnvoyGatewayParameters) getValues(gw *gwv1.Gateway, gwParam *kgateway.G gateway.ExtraVolumes = podConfig.GetExtraVolumes() gateway.PriorityClassName = podConfig.GetPriorityClassName() - // kgatewayParameters is only used for envoy gateways (agentgateway uses agentgatewayParametersHelmValuesGenerator) - gateway.DataPlaneType = deployer.DataPlaneEnvoy logLevel := envoyContainerConfig.GetBootstrap().GetLogLevel() gateway.LogLevel = logLevel compLogLevels := envoyContainerConfig.GetBootstrap().GetComponentLogLevels() diff --git a/pkg/kgateway/deployer/tls.go b/pkg/kgateway/deployer/tls.go index 82dc4ab4320..3dace1c66a3 100644 --- a/pkg/kgateway/deployer/tls.go +++ b/pkg/kgateway/deployer/tls.go @@ -9,7 +9,8 @@ import ( // injectXdsCACertificate reads the CA certificate from the control plane's mounted TLS Secret // and injects it into the Helm values so it can be used by the proxy templates. -func injectXdsCACertificate(caCertPath string, vals *deployer.HelmConfig) error { +// It accepts variadic HelmXds pointers to support both Envoy (single Xds) and agentgateway (Xds + AgwXds). +func injectXdsCACertificate(caCertPath string, xdsConfigs ...*deployer.HelmXds) error { if _, err := os.Stat(caCertPath); os.IsNotExist(err) { return fmt.Errorf("xDS TLS is enabled but CA certificate file not found at %s. "+ "Ensure the xDS TLS secret is properly mounted and contains ca.crt", caCertPath, @@ -25,11 +26,10 @@ func injectXdsCACertificate(caCertPath string, vals *deployer.HelmConfig) error } caCertStr := string(caCert) - if vals.Gateway.Xds != nil && vals.Gateway.Xds.Tls != nil { - vals.Gateway.Xds.Tls.CaCert = &caCertStr - } - if vals.Gateway.AgwXds != nil && vals.Gateway.AgwXds.Tls != nil { - vals.Gateway.AgwXds.Tls.CaCert = &caCertStr + for _, xds := range xdsConfigs { + if xds != nil && xds.Tls != nil { + xds.Tls.CaCert = &caCertStr + } } return nil diff --git a/test/deployer/deployer_helm.go b/test/deployer/deployer_helm.go index 644d96c49eb..4b606a5b20e 100644 --- a/test/deployer/deployer_helm.go +++ b/test/deployer/deployer_helm.go @@ -182,7 +182,7 @@ func (dt DeployerTester) RunHelmChartTest( dt.AgwClassName, scheme, fakeClient, - gwParams.AgentgatewayHelmValuesGenerator(), + gwParams.AgentgatewayParametersHelmValuesGenerator(), ) } else { deployer, err = internaldeployer.NewEnvoyGatewayDeployer( From 84483e273714fcd7576a5fd4b10a1bfc3f252472 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Tue, 9 Dec 2025 12:02:02 -0500 Subject: [PATCH 4/8] fixup Signed-off-by: David L. Chandler --- pkg/kgateway/deployer/gateway_parameters.go | 33 --------------------- 1 file changed, 33 deletions(-) diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 526a51b0808..02aa37ef7bf 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -104,39 +104,6 @@ func (gp *GatewayParameters) AgentgatewayParametersHelmValuesGenerator() deploye return gp.agwHelmValuesGenerator } -// PostProcessObjects implements deployer.ObjectPostProcessor. -// It applies AgentgatewayParameters overlays to the rendered objects. -// When both GatewayClass and Gateway have AgentgatewayParameters, the overlays -// are applied in order: GatewayClass first, then Gateway on top. -func (gp *GatewayParameters) PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) error { - gw, ok := obj.(*gwv1.Gateway) - if !ok || gp.agwHelmValuesGenerator == nil { - return nil - } - - resolved, err := gp.agwHelmValuesGenerator.GetResolvedParametersForGateway(gw) - if err != nil { - return nil - } - - // Apply overlays in order: GatewayClass first, then Gateway. - // This allows Gateway-level overlays to override GatewayClass-level overlays. - if resolved.gatewayClassAGWP != nil { - applier := NewAgentgatewayParametersApplier(resolved.gatewayClassAGWP) - if err := applier.ApplyOverlaysToObjects(rendered); err != nil { - return err - } - } - if resolved.gatewayAGWP != nil { - applier := NewAgentgatewayParametersApplier(resolved.gatewayAGWP) - if err := applier.ApplyOverlaysToObjects(rendered); err != nil { - return err - } - } - - return nil -} - func GatewayReleaseNameAndNamespace(obj client.Object) (string, string) { return obj.GetName(), obj.GetNamespace() } From efb6472d0989a6e54bed44bdf9cebf286a944465 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Tue, 9 Dec 2025 12:24:33 -0500 Subject: [PATCH 5/8] fixup Signed-off-by: David L. Chandler --- pkg/deployer/agentgateway_values.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pkg/deployer/agentgateway_values.go b/pkg/deployer/agentgateway_values.go index a817eef7b0d..86cfb574f7d 100644 --- a/pkg/deployer/agentgateway_values.go +++ b/pkg/deployer/agentgateway_values.go @@ -1,7 +1,6 @@ package deployer import ( - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "github.com/kgateway-dev/kgateway/v2/api/v1alpha1/kgateway" @@ -26,10 +25,9 @@ type AgentgatewayHelmGateway struct { FullnameOverride *string `json:"fullnameOverride,omitempty"` // deployment/service values - ReplicaCount *uint32 `json:"replicaCount,omitempty"` - Ports []HelmPort `json:"ports,omitempty"` - Service *HelmService `json:"service,omitempty"` - Strategy *appsv1.DeploymentStrategy `json:"strategy,omitempty"` + ReplicaCount *uint32 `json:"replicaCount,omitempty"` + Ports []HelmPort `json:"ports,omitempty"` + Service *HelmService `json:"service,omitempty"` // serviceaccount values ServiceAccount *HelmServiceAccount `json:"serviceAccount,omitempty"` @@ -49,7 +47,6 @@ type AgentgatewayHelmGateway struct { GracefulShutdown *kgateway.GracefulShutdownSpec `json:"gracefulShutdown,omitempty"` TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` - PriorityClassName *string `json:"priorityClassName,omitempty"` // agentgateway container values LogLevel *string `json:"logLevel,omitempty"` @@ -66,7 +63,6 @@ type AgentgatewayHelmGateway struct { AgwXds *HelmXds `json:"agwXds,omitempty"` // agentgateway-specific config - CustomConfigMapName *string `json:"customConfigMapName,omitempty"` // LogFormat specifies the logging format for agentgateway (Json or Text) LogFormat *string `json:"logFormat,omitempty"` // RawConfig provides opaque config to be merged into config.yaml From 656c861849c78faede9544d799dff3a013b35c47 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Tue, 9 Dec 2025 12:30:48 -0500 Subject: [PATCH 6/8] fixup Signed-off-by: David L. Chandler --- pkg/kgateway/deployer/gateway_parameters.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 02aa37ef7bf..d8b38d66c7c 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -96,11 +96,7 @@ func (gp *GatewayParameters) EnvoyHelmValuesGenerator() deployer.HelmValuesGener } // AgentgatewayParametersHelmValuesGenerator returns the helm values generator for agentgateway-based gateways. -// If a helm values generator override is set, it returns that instead. func (gp *GatewayParameters) AgentgatewayParametersHelmValuesGenerator() deployer.HelmValuesGenerator { - if gp.helmValuesGeneratorOverride != nil { - return gp.helmValuesGeneratorOverride - } return gp.agwHelmValuesGenerator } From 704c96a203760be6ea479e797e63935633597cd3 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Tue, 9 Dec 2025 12:38:34 -0500 Subject: [PATCH 7/8] Remove more fields, even though they exist in the helm chart Signed-off-by: David L. Chandler --- pkg/deployer/agentgateway_values.go | 40 +++++-------------- .../deployer/agentgateway_parameters_test.go | 4 +- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/pkg/deployer/agentgateway_values.go b/pkg/deployer/agentgateway_values.go index 86cfb574f7d..f54562c9167 100644 --- a/pkg/deployer/agentgateway_values.go +++ b/pkg/deployer/agentgateway_values.go @@ -21,40 +21,22 @@ type AgentgatewayHelmGateway struct { GatewayClassName *string `json:"gatewayClassName,omitempty"` GatewayAnnotations map[string]string `json:"gatewayAnnotations,omitempty"` GatewayLabels map[string]string `json:"gatewayLabels,omitempty"` - NameOverride *string `json:"nameOverride,omitempty"` - FullnameOverride *string `json:"fullnameOverride,omitempty"` - // deployment/service values - ReplicaCount *uint32 `json:"replicaCount,omitempty"` - Ports []HelmPort `json:"ports,omitempty"` - Service *HelmService `json:"service,omitempty"` - - // serviceaccount values - ServiceAccount *HelmServiceAccount `json:"serviceAccount,omitempty"` + // deployment values + Ports []HelmPort `json:"ports,omitempty"` // pod template values - ExtraPodAnnotations map[string]string `json:"extraPodAnnotations,omitempty"` - ExtraPodLabels map[string]string `json:"extraPodLabels,omitempty"` - ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` - PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - Affinity *corev1.Affinity `json:"affinity,omitempty"` - Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - StartupProbe *corev1.Probe `json:"startupProbe,omitempty"` - ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty"` - LivenessProbe *corev1.Probe `json:"livenessProbe,omitempty"` - ExtraVolumes []corev1.Volume `json:"extraVolumes,omitempty"` - GracefulShutdown *kgateway.GracefulShutdownSpec `json:"gracefulShutdown,omitempty"` - TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` - TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` + PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + StartupProbe *corev1.Probe `json:"startupProbe,omitempty"` + ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty"` + GracefulShutdown *kgateway.GracefulShutdownSpec `json:"gracefulShutdown,omitempty"` + TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` // agentgateway container values - LogLevel *string `json:"logLevel,omitempty"` - Image *HelmImage `json:"image,omitempty"` - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` - SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"` - Env []corev1.EnvVar `json:"env,omitempty"` - ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"` + Image *HelmImage `json:"image,omitempty"` + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"` + Env []corev1.EnvVar `json:"env,omitempty"` // agentgateway xds values // Note: agentgateway uses agwXds for its xds connection, but the helm template diff --git a/pkg/kgateway/deployer/agentgateway_parameters_test.go b/pkg/kgateway/deployer/agentgateway_parameters_test.go index e4709714be3..e8af546b053 100644 --- a/pkg/kgateway/deployer/agentgateway_parameters_test.go +++ b/pkg/kgateway/deployer/agentgateway_parameters_test.go @@ -21,14 +21,14 @@ func TestAgentgatewayParametersApplier_ApplyToHelmValues_NilParams(t *testing.T) applier := NewAgentgatewayParametersApplier(nil) vals := &deployer.AgentgatewayHelmConfig{ Gateway: &deployer.AgentgatewayHelmGateway{ - LogLevel: ptr.To("info"), + LogFormat: ptr.To("json"), }, } applier.ApplyToHelmValues(vals) // Values should be unchanged - assert.Equal(t, "info", *vals.Gateway.LogLevel) + assert.Equal(t, "json", *vals.Gateway.LogFormat) } func TestAgentgatewayParametersApplier_ApplyToHelmValues_Image(t *testing.T) { From 7125d56f8faac82547d267e10fc5858931987720 Mon Sep 17 00:00:00 2001 From: "David L. Chandler" Date: Mon, 15 Dec 2025 10:55:31 -0500 Subject: [PATCH 8/8] fixup Signed-off-by: David L. Chandler --- pkg/kgateway/controller/gw_controller.go | 1 - pkg/kgateway/deployer/gateway_parameters.go | 2 +- test/e2e/features/oauth/suite.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/kgateway/controller/gw_controller.go b/pkg/kgateway/controller/gw_controller.go index 3ea8c49d121..d53b6d30189 100644 --- a/pkg/kgateway/controller/gw_controller.go +++ b/pkg/kgateway/controller/gw_controller.go @@ -53,7 +53,6 @@ var _ manager.LeaderElectionRunnable = (*gatewayReconciler)(nil) type gatewayReconciler struct { envoyDeployer *deployer.Deployer agwDeployer *deployer.Deployer - deployer *deployer.Deployer gwParams *internaldeployer.GatewayParameters scheme *runtime.Scheme controllerName string diff --git a/pkg/kgateway/deployer/gateway_parameters.go b/pkg/kgateway/deployer/gateway_parameters.go index 967a12fc87c..39455b0e9f4 100644 --- a/pkg/kgateway/deployer/gateway_parameters.go +++ b/pkg/kgateway/deployer/gateway_parameters.go @@ -38,7 +38,7 @@ func NewGatewayParameters(cli apiclient.Client, inputs *deployer.Inputs) *Gatewa // Only create the kgateway parameters client if Envoy is enabled if inputs.CommonCollections.Settings.EnableEnvoy { - gp.kgwParameters = NewkgatewayParameters(cli, inputs) + gp.kgwParameters = NewEnvoyGatewayParameters(cli, inputs) } // Only create the agentgateway parameters client if agentgateway is enabled diff --git a/test/e2e/features/oauth/suite.go b/test/e2e/features/oauth/suite.go index 6c95ad650dc..c00203b1bdb 100644 --- a/test/e2e/features/oauth/suite.go +++ b/test/e2e/features/oauth/suite.go @@ -160,7 +160,7 @@ func (s *tsuite) TestOIDC() { resp, err = client.Get(ctx, logoutURL, true) r.NoError(err) r.NotNil(resp) - // TODO: enable this check after determining why somtimes the /logout returns invalid_redirect_uri + // TODO: enable this check after determining why sometimes the /logout returns invalid_redirect_uri // r.Equal(http.StatusOK, resp.StatusCode) }