Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/kgateway/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type GatewayConfig struct {
Mgr manager.Manager
// Dev enables development mode for the controller.
Dev bool
// ControllerName is the name of the controller. Any GatewayClass objects
// ControllerName is the name of the Envoy controller. Any GatewayClass objects
// managed by this controller must have this name as their ControllerName.
ControllerName string
// AgwControllerName is the name of the agentgateway controller. Any GatewayClass objects
Expand Down Expand Up @@ -175,6 +175,7 @@ func (c *controllerBuilder) watchGw(ctx context.Context) error {
GatewayClassName: c.cfg.GatewayClassName,
WaypointGatewayClassName: c.cfg.WaypointGatewayClassName,
AgentgatewayClassName: c.cfg.AgentgatewayClassName,
EnvoyControllerName: c.cfg.ControllerName,
AgentgatewayControllerName: c.cfg.AgwControllerName,
}

Expand Down
44 changes: 27 additions & 17 deletions internal/kgateway/deployer/gateway_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,15 @@ func (k *kGatewayParameters) getGatewayParametersForGateway(ctx context.Context,
if err != nil {
return nil, err
}
mergedGwp = deployer.GetInMemoryGatewayParameters(gwc.GetName(), k.inputs.ImageInfo, k.inputs.GatewayClassName, k.inputs.WaypointGatewayClassName, k.inputs.AgentgatewayClassName, true)
mergedGwp = deployer.GetInMemoryGatewayParameters(deployer.InMemoryGatewayParametersConfig{
ControllerName: string(gwc.Spec.ControllerName),
ClassName: gwc.GetName(),
ImageInfo: k.inputs.ImageInfo,
WaypointClassName: k.inputs.WaypointGatewayClassName,
EnvoyControllerName: k.inputs.EnvoyControllerName,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: true,
})
}
deployer.DeepMergeGatewayParameters(mergedGwp, gwp)
return mergedGwp, nil
Expand All @@ -222,14 +230,15 @@ func (k *kGatewayParameters) getDefaultGatewayParameters(ctx context.Context, gw
func (k *kGatewayParameters) getGatewayParametersForGatewayClass(ctx context.Context, gwc *api.GatewayClass) (*v1alpha1.GatewayParameters, error) {
// Our defaults depend on OmitDefaultSecurityContext, but these are the defaults
// when not OmitDefaultSecurityContext:
defaultGwp := deployer.GetInMemoryGatewayParameters(
gwc.GetName(),
k.inputs.ImageInfo,
k.inputs.GatewayClassName,
k.inputs.WaypointGatewayClassName,
k.inputs.AgentgatewayClassName,
false,
)
defaultGwp := deployer.GetInMemoryGatewayParameters(deployer.InMemoryGatewayParametersConfig{
ControllerName: string(gwc.Spec.ControllerName),
ClassName: gwc.GetName(),
ImageInfo: k.inputs.ImageInfo,
WaypointClassName: k.inputs.WaypointGatewayClassName,
EnvoyControllerName: k.inputs.EnvoyControllerName,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: false,
})

paramRef := gwc.Spec.ParametersRef
if paramRef == nil {
Expand Down Expand Up @@ -268,14 +277,15 @@ func (k *kGatewayParameters) getGatewayParametersForGatewayClass(ctx context.Con
// correctly set when they aren't overridden by the GatewayParameters.
mergedGwp := defaultGwp
if ptr.Deref(gwp.Spec.Kube.GetOmitDefaultSecurityContext(), false) {
mergedGwp = deployer.GetInMemoryGatewayParameters(
gwc.GetName(),
k.inputs.ImageInfo,
k.inputs.GatewayClassName,
k.inputs.WaypointGatewayClassName,
k.inputs.AgentgatewayClassName,
true,
)
mergedGwp = deployer.GetInMemoryGatewayParameters(deployer.InMemoryGatewayParametersConfig{
ControllerName: string(gwc.Spec.ControllerName),
ClassName: gwc.GetName(),
ImageInfo: k.inputs.ImageInfo,
WaypointClassName: k.inputs.WaypointGatewayClassName,
EnvoyControllerName: k.inputs.EnvoyControllerName,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: true,
})
}
deployer.DeepMergeGatewayParameters(mergedGwp, gwp)
return mergedGwp, nil
Expand Down
8 changes: 5 additions & 3 deletions internal/kgateway/deployer/gateway_parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,11 @@ func defaultInputs(t *testing.T, objs ...client.Object) *deployer.Inputs {
Registry: "foo",
Tag: "bar",
},
GatewayClassName: wellknown.DefaultGatewayClassName,
WaypointGatewayClassName: wellknown.DefaultWaypointClassName,
AgentgatewayClassName: wellknown.DefaultAgwClassName,
GatewayClassName: wellknown.DefaultGatewayClassName,
WaypointGatewayClassName: wellknown.DefaultWaypointClassName,
AgentgatewayClassName: wellknown.DefaultAgwClassName,
EnvoyControllerName: wellknown.DefaultGatewayControllerName,
AgentgatewayControllerName: wellknown.DefaultAgwControllerName,
}
}

Expand Down
10 changes: 9 additions & 1 deletion pkg/deployer/deployer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1918,7 +1918,15 @@ var _ = Describe("Deployer", func() {

// assert istio container
istioContainer := dep.Spec.Template.Spec.Containers[2]
defaultIstioVersion := *deployer.GetInMemoryGatewayParameters("a", &deployer.ImageInfo{}, "b", "c", "d", true).Spec.Kube.Istio.IstioProxyContainer.Image.Tag
defaultIstioVersion := *deployer.GetInMemoryGatewayParameters(deployer.InMemoryGatewayParametersConfig{
ControllerName: "kgateway.dev/a",
ClassName: "a",
ImageInfo: &deployer.ImageInfo{},
WaypointClassName: "b",
EnvoyControllerName: "kgateway.dev/kgateway",
AgwControllerName: "c",
OmitDefaultSecurityContext: true,
}).Spec.Kube.Istio.IstioProxyContainer.Image.Tag
helpTestImage(expectedGwp.Istio.IstioProxyContainer.Image, istioContainer, defaultIstioVersion)
Expect(istioContainer.Resources.Limits.Cpu()).To(Equal(expectedGwp.Istio.IstioProxyContainer.Resources.Limits.Cpu()))
Expect(istioContainer.Resources.Requests.Cpu()).To(Equal(expectedGwp.Istio.IstioProxyContainer.Resources.Requests.Cpu()))
Expand Down
38 changes: 27 additions & 11 deletions pkg/deployer/gateway_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Inputs struct {
GatewayClassName string
WaypointGatewayClassName string
AgentgatewayClassName string
EnvoyControllerName string
AgentgatewayControllerName string
}

Expand Down Expand Up @@ -72,18 +73,33 @@ func allowPrivilegedPorts(cfg *v1alpha1.KubernetesProxyConfig) {
})
}

// GetInMemoryGatewayParameters returns an in-memory GatewayParameters based on the name of the gateway class.
func GetInMemoryGatewayParameters(name string, imageInfo *ImageInfo, gatewayClassName, waypointClassName, agentgatewayClassName string, omitDefaultSecurityContext bool) *v1alpha1.GatewayParameters {
switch name {
case waypointClassName:
return defaultWaypointGatewayParameters(imageInfo, omitDefaultSecurityContext)
case gatewayClassName:
return defaultGatewayParameters(imageInfo, omitDefaultSecurityContext)
case agentgatewayClassName:
return defaultAgentgatewayParameters(imageInfo, omitDefaultSecurityContext)
default:
return defaultGatewayParameters(imageInfo, omitDefaultSecurityContext)
// InMemoryGatewayParametersConfig holds the configuration for creating in-memory GatewayParameters.
type InMemoryGatewayParametersConfig struct {
ControllerName string
ClassName string
ImageInfo *ImageInfo
WaypointClassName string
EnvoyControllerName string
AgwControllerName string
OmitDefaultSecurityContext bool
}

// GetInMemoryGatewayParameters returns an in-memory GatewayParameters.
// Priority order:
// 1. Agentgateway controller name (highest priority)
// 2. Waypoint class name (must check before envoy controller since waypoint uses the same controller)
// 3. Envoy controller name, or no controller name -- either way, use default gateway parameters
//
// This allows users to define their own GatewayClass that acts very much like a
// built-in class but is not an exact name match.
func GetInMemoryGatewayParameters(cfg InMemoryGatewayParametersConfig) *v1alpha1.GatewayParameters {
if cfg.ControllerName == cfg.AgwControllerName {
return defaultAgentgatewayParameters(cfg.ImageInfo, cfg.OmitDefaultSecurityContext)
}
if cfg.ClassName == cfg.WaypointClassName {
return defaultWaypointGatewayParameters(cfg.ImageInfo, cfg.OmitDefaultSecurityContext)
}
return defaultGatewayParameters(cfg.ImageInfo, cfg.OmitDefaultSecurityContext)
}

// defaultAgentgatewayParameters returns an in-memory GatewayParameters with default values
Expand Down
108 changes: 108 additions & 0 deletions pkg/deployer/gateway_parameters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package deployer_test

import (
"testing"

"github.com/kgateway-dev/kgateway/v2/pkg/deployer"
)

// TestGetInMemoryGatewayParameters_ControllerNamePriority tests that the controller name
// takes priority over the class name when determining which gateway parameters to return.
func TestGetInMemoryGatewayParameters_ControllerNamePriority(t *testing.T) {
imageInfo := &deployer.ImageInfo{
Registry: "test-registry",
Tag: "test-tag",
PullPolicy: "IfNotPresent",
}

const (
envoyController = "kgateway.dev/kgateway"
agwController = "kgateway.dev/agentgateway"
waypointClass = "waypoint"
)

tests := []struct {
name string
controllerName string
className string
expectedAgwEnabled bool
expectedServicePorts int // waypoint has an extra port
description string
}{
{
name: "agentgateway controller name - ignores class name",
controllerName: agwController,
className: waypointClass, // should be ignored
expectedAgwEnabled: true,
expectedServicePorts: 0,
description: "When controller name matches agentgateway, it should return agentgateway parameters regardless of class name",
},
{
name: "waypoint class name takes priority over envoy controller",
controllerName: envoyController,
className: waypointClass, // waypoint class checked before controller
expectedAgwEnabled: false,
expectedServicePorts: 1, // waypoint adds a mesh port
description: "When both envoy controller and waypoint class match, waypoint class takes priority",
},
{
name: "waypoint class name - no controller match",
controllerName: "some.other/controller",
className: waypointClass,
expectedAgwEnabled: false,
expectedServicePorts: 1, // waypoint adds a mesh port
description: "When controller name doesn't match known controllers, it should check class name for waypoint",
},
{
name: "default - no matches",
controllerName: "some.other/controller",
className: "some-other-class",
expectedAgwEnabled: false,
expectedServicePorts: 0,
description: "When neither controller name nor class name match, it should return default gateway parameters",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := deployer.InMemoryGatewayParametersConfig{
ControllerName: tt.controllerName,
ClassName: tt.className,
ImageInfo: imageInfo,
WaypointClassName: waypointClass,
EnvoyControllerName: envoyController,
AgwControllerName: agwController,
OmitDefaultSecurityContext: false,
}

gwp := deployer.GetInMemoryGatewayParameters(cfg)

if gwp == nil {
t.Fatal("GetInMemoryGatewayParameters returned nil")
}

// Check if agentgateway is enabled
if gwp.Spec.Kube == nil {
t.Fatal("GatewayParameters.Spec.Kube is nil")
}

agwEnabled := gwp.Spec.Kube.Agentgateway != nil &&
gwp.Spec.Kube.Agentgateway.Enabled != nil &&
*gwp.Spec.Kube.Agentgateway.Enabled

if agwEnabled != tt.expectedAgwEnabled {
t.Errorf("%s: agentgateway enabled = %v, want %v", tt.description, agwEnabled, tt.expectedAgwEnabled)
}

// Check service ports for waypoint
var servicePorts int
if gwp.Spec.Kube.Service != nil && gwp.Spec.Kube.Service.Ports != nil {
servicePorts = len(gwp.Spec.Kube.Service.Ports)
}

if servicePorts != tt.expectedServicePorts {
t.Errorf("%s: service ports count = %d, want %d", tt.description, servicePorts, tt.expectedServicePorts)
}
})
}
}
8 changes: 5 additions & 3 deletions test/deployer/deployer_helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,11 @@ func DefaultDeployerInputs(dt DeployerTester, commonCols *collections.CommonColl
Registry: "ghcr.io",
Tag: "v2.1.0-dev",
},
GatewayClassName: dt.ClassName,
WaypointGatewayClassName: dt.WaypointClassName,
AgentgatewayClassName: dt.AgwClassName,
GatewayClassName: dt.ClassName,
WaypointGatewayClassName: dt.WaypointClassName,
AgentgatewayClassName: dt.AgwClassName,
EnvoyControllerName: dt.ControllerName,
AgentgatewayControllerName: dt.AgwControllerName,
}
}

Expand Down
8 changes: 8 additions & 0 deletions test/deployer/internal_helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ func TestRenderHelmChart(t *testing.T) {
Name: "agentgateway-infrastructure",
InputFile: "agentgateway-infrastructure",
},
{
Name: "agentgateway-controller-but-custom-gatewayclass",
InputFile: "agentgateway-controller-but-custom-gatewayclass",
},
{
Name: "envoy-controller-ignores-agentgateway-class-name",
InputFile: "envoy-controller-ignores-agentgateway-class-name",
},
{
Name: "envoy-infrastructure",
InputFile: "envoy-infrastructure",
Expand Down
Loading