Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 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
41 changes: 24 additions & 17 deletions internal/kgateway/deployer/gateway_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,14 @@ 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,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: true,
})
}
deployer.DeepMergeGatewayParameters(mergedGwp, gwp)
return mergedGwp, nil
Expand All @@ -222,14 +229,14 @@ 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,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: false,
})

paramRef := gwc.Spec.ParametersRef
if paramRef == nil {
Expand Down Expand Up @@ -268,14 +275,14 @@ 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,
AgwControllerName: k.inputs.AgentgatewayControllerName,
OmitDefaultSecurityContext: true,
})
}
deployer.DeepMergeGatewayParameters(mergedGwp, gwp)
return mergedGwp, nil
Expand Down
7 changes: 4 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,10 @@ 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,
AgentgatewayControllerName: wellknown.DefaultAgwControllerName,
}
}

Expand Down
9 changes: 8 additions & 1 deletion pkg/deployer/deployer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1917,7 +1917,14 @@ 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",
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
36 changes: 25 additions & 11 deletions pkg/deployer/gateway_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,32 @@ 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
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
107 changes: 107 additions & 0 deletions pkg/deployer/gateway_parameters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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,
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)
}
})
}
}
7 changes: 4 additions & 3 deletions test/deployer/deployer_helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,10 @@ 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,
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