Skip to content

Commit a1afc9d

Browse files
authored
Truncate long resource names when provisioning (#4387)
Problem: When provisioning the NGINX Service, if the Gateway name was very long, it could result in a failure to create the Service. A Service name must be 63 characters or less. This also could affect the shadow Service that we create for InferencePools if the InferencePool name is long. Solution: If the name of the resource that we create is going to be over the max, create a hash of the name and truncate to ensure that it is less than the max. The suffix is still included, since we rely on that for certain resources. Just the prefix is shortened as necessary to include the hash.
1 parent 6fba1e3 commit a1afc9d

File tree

12 files changed

+155
-36
lines changed

12 files changed

+155
-36
lines changed

internal/controller/provisioner/handler.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ func (h *eventHandler) HandleEventBatch(ctx context.Context, logger logr.Logger,
6767
objLabels := labels.Set(obj.GetLabels())
6868
if h.labelSelector.Matches(objLabels) {
6969
gatewayName := objLabels.Get(controller.GatewayLabel)
70+
if gatewayName == "" {
71+
gatewayName = obj.GetAnnotations()[controller.GatewayLabel]
72+
}
7073
gatewayNSName := types.NamespacedName{Namespace: obj.GetNamespace(), Name: gatewayName}
71-
7274
if err := h.updateOrDeleteResources(ctx, logger, obj, gatewayNSName); err != nil {
7375
logger.Error(err, "error handling resource update")
7476
}
@@ -77,12 +79,13 @@ func (h *eventHandler) HandleEventBatch(ctx context.Context, logger logr.Logger,
7779
objLabels := labels.Set(obj.GetLabels())
7880
if h.labelSelector.Matches(objLabels) {
7981
gatewayName := objLabels.Get(controller.GatewayLabel)
82+
if gatewayName == "" {
83+
gatewayName = obj.GetAnnotations()[controller.GatewayLabel]
84+
}
8085
gatewayNSName := types.NamespacedName{Namespace: obj.GetNamespace(), Name: gatewayName}
81-
8286
if err := h.updateOrDeleteResources(ctx, logger, obj, gatewayNSName); err != nil {
8387
logger.Error(err, "error handling resource update")
8488
}
85-
8689
statusUpdate := &status.QueueObject{
8790
Deployment: client.ObjectKeyFromObject(obj),
8891
UpdateType: status.UpdateGateway,
@@ -94,8 +97,10 @@ func (h *eventHandler) HandleEventBatch(ctx context.Context, logger logr.Logger,
9497
objLabels := labels.Set(obj.GetLabels())
9598
if h.labelSelector.Matches(objLabels) {
9699
gatewayName := objLabels.Get(controller.GatewayLabel)
100+
if gatewayName == "" {
101+
gatewayName = obj.GetAnnotations()[controller.GatewayLabel]
102+
}
97103
gatewayNSName := types.NamespacedName{Namespace: obj.GetNamespace(), Name: gatewayName}
98-
99104
if err := h.updateOrDeleteResources(ctx, logger, obj, gatewayNSName); err != nil {
100105
logger.Error(err, "error handling resource update")
101106
}

internal/controller/provisioner/objects.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,17 @@ func (p *NginxProvisioner) buildNginxResourceObjects(
9090

9191
selectorLabels := make(map[string]string)
9292
maps.Copy(selectorLabels, p.baseLabelSelector.MatchLabels)
93-
selectorLabels[controller.GatewayLabel] = gateway.GetName()
9493
selectorLabels[controller.AppNameLabel] = resourceName
9594

9695
labels := make(map[string]string)
9796
annotations := make(map[string]string)
9897

98+
if len(gateway.GetName()) > controller.MaxServiceNameLen {
99+
annotations[controller.GatewayLabel] = gateway.GetName()
100+
} else {
101+
selectorLabels[controller.GatewayLabel] = gateway.GetName()
102+
}
103+
99104
maps.Copy(labels, selectorLabels)
100105

101106
if gateway.Spec.Infrastructure != nil {

internal/controller/state/graph/backend_refs.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
1515
"github.com/nginx/nginx-gateway-fabric/v2/internal/controller/sort"
1616
"github.com/nginx/nginx-gateway-fabric/v2/internal/controller/state/conditions"
17-
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/controller"
1817
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/helpers"
1918
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/kinds"
2019
)
@@ -116,7 +115,7 @@ func addBackendRefsToRules(
116115
}
117116

118117
poolName := types.NamespacedName{
119-
Name: controller.GetInferencePoolName(string(ref.Name)),
118+
Name: ref.InferencePoolName,
120119
Namespace: namespace,
121120
}
122121

@@ -596,7 +595,7 @@ func validateBackendRefHTTPRoute(
596595
inferencePool = true
597596
inferencePoolName = types.NamespacedName{
598597
Namespace: string(*ref.Namespace),
599-
Name: controller.GetInferencePoolName(string(ref.Name)),
598+
Name: ref.InferencePoolName,
600599
}
601600
default:
602601
refNsName := types.NamespacedName{Namespace: string(*ref.Namespace), Name: string(ref.Name)}

internal/controller/state/graph/backend_refs_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ func TestValidateRouteBackendRef(t *testing.T) {
106106
backend.Name = gatewayv1.ObjectName(controller.CreateInferencePoolServiceName("ipool"))
107107
return backend
108108
}),
109-
IsInferencePool: true,
109+
IsInferencePool: true,
110+
InferencePoolName: "ipool",
110111
},
111112
expectedValid: true,
112113
},
@@ -393,7 +394,8 @@ func TestValidateBackendRefHTTPRoute(t *testing.T) {
393394
backend.Namespace = helpers.GetPointer[gatewayv1.Namespace]("invalid")
394395
return backend
395396
}),
396-
IsInferencePool: true,
397+
IsInferencePool: true,
398+
InferencePoolName: "ipool",
397399
},
398400
refGrantResolver: alwaysFalseRefGrantResolver,
399401
expectedValid: false,
@@ -1220,6 +1222,7 @@ func TestAddBackendRefsToRules(t *testing.T) {
12201222
route := createRoute("hr-inference", RouteTypeHTTP, "Service", 1, svcInferenceName)
12211223
// Mark the backend ref as IsInferencePool and set the port to nil (simulate InferencePool logic)
12221224
route.Spec.Rules[0].RouteBackendRefs[0].IsInferencePool = true
1225+
route.Spec.Rules[0].RouteBackendRefs[0].InferencePoolName = "ipool"
12231226
route.Spec.Rules[0].RouteBackendRefs[0].Port = nil
12241227
return route
12251228
}(),

internal/controller/state/graph/graph_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ func TestBuildGraph(t *testing.T) {
239239
}
240240
rbrs := []RouteBackendRef{
241241
{
242-
IsInferencePool: true,
242+
IsInferencePool: true,
243+
InferencePoolName: "ipool",
243244
BackendRef: gatewayv1.BackendRef{
244245
BackendObjectReference: gatewayv1.BackendObjectReference{
245246
Group: helpers.GetPointer[gatewayv1.Group](""),

internal/controller/state/graph/httproute.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func processHTTPRouteRule(
224224
// If route specifies an InferencePool backend, we need to convert it to its associated
225225
// headless Service backend (that we created), so nginx config can be built properly.
226226
// Only do this if the InferencePool actually exists.
227-
if inferencePoolBackend(b, routeNamespace, inferencePools) {
227+
if ok, key := inferencePoolBackend(b, routeNamespace, inferencePools); ok {
228228
// We don't support traffic splitting at the Route level for
229229
// InferencePool backends, so if there's more than one backendRef, and one of them
230230
// is an InferencePool, we mark the rule as invalid.
@@ -239,7 +239,8 @@ func processHTTPRouteRule(
239239

240240
svcName := controller.CreateInferencePoolServiceName(string(b.Name))
241241
rbr = RouteBackendRef{
242-
IsInferencePool: true,
242+
IsInferencePool: true,
243+
InferencePoolName: key.Name,
243244
BackendRef: v1.BackendRef{
244245
BackendObjectReference: v1.BackendObjectReference{
245246
Group: helpers.GetPointer[v1.Group](""),
@@ -346,12 +347,12 @@ func processHTTPRouteRules(
346347
}
347348

348349
// inferencePoolBackend returns if a Route references an InferencePool backend
349-
// and that InferencePool exists.
350+
// and that InferencePool exists. Also returns the NamespacedName of the InferencePool.
350351
func inferencePoolBackend(
351352
backendRef v1.HTTPBackendRef,
352353
routeNamespace string,
353354
inferencePools map[types.NamespacedName]*inference.InferencePool,
354-
) bool {
355+
) (bool, types.NamespacedName) {
355356
if backendRef.Group != nil &&
356357
*backendRef.Group == inferenceAPIGroup &&
357358
*backendRef.Kind == kinds.InferencePool {
@@ -364,11 +365,11 @@ func inferencePoolBackend(
364365
Namespace: namespace,
365366
}
366367
if _, exists := inferencePools[key]; exists {
367-
return true
368+
return true, key
368369
}
369370
}
370371

371-
return false
372+
return false, types.NamespacedName{}
372373
}
373374

374375
func validateMatch(

internal/controller/state/graph/httproute_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,8 @@ func TestBuildHTTPRoute(t *testing.T) {
10381038
Matches: hrInferencePool.Spec.Rules[0].Matches,
10391039
RouteBackendRefs: []RouteBackendRef{
10401040
{
1041-
IsInferencePool: true,
1041+
IsInferencePool: true,
1042+
InferencePoolName: "ipool",
10421043
BackendRef: gatewayv1.BackendRef{
10431044
BackendObjectReference: gatewayv1.BackendObjectReference{
10441045
Group: helpers.GetPointer[gatewayv1.Group](""),

internal/controller/state/graph/inferencepools.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
apiv1 "sigs.k8s.io/gateway-api/apis/v1"
1111

1212
"github.com/nginx/nginx-gateway-fabric/v2/internal/controller/state/conditions"
13-
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/controller"
1413
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/kinds"
1514
)
1615

@@ -101,7 +100,7 @@ func processInferencePoolsForGateway(
101100
}
102101

103102
poolName := types.NamespacedName{
104-
Name: controller.GetInferencePoolName(string(ref.Name)),
103+
Name: ref.InferencePoolName,
105104
Namespace: namespace,
106105
}
107106

internal/controller/state/graph/inferencepools_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ func TestBuildReferencedInferencePools(t *testing.T) {
5050
{
5151
RouteBackendRefs: []RouteBackendRef{
5252
{
53-
IsInferencePool: true,
53+
IsInferencePool: true,
54+
InferencePoolName: "pool",
5455
BackendRef: gatewayv1.BackendRef{
5556
BackendObjectReference: gatewayv1.BackendObjectReference{
5657
Namespace: helpers.GetPointer[gatewayv1.Namespace]("test"),
@@ -111,7 +112,8 @@ func TestBuildReferencedInferencePools(t *testing.T) {
111112
{
112113
RouteBackendRefs: []RouteBackendRef{
113114
{
114-
IsInferencePool: true,
115+
IsInferencePool: true,
116+
InferencePoolName: "pool",
115117
BackendRef: gatewayv1.BackendRef{
116118
BackendObjectReference: gatewayv1.BackendObjectReference{
117119
Kind: helpers.GetPointer[gatewayv1.Kind](kinds.Service),

internal/controller/state/graph/route_common.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ type RouteBackendRef struct {
169169
// EndpointPickerConfig is the configuration for the EndpointPicker, if this backendRef is for an InferencePool.
170170
EndpointPickerConfig EndpointPickerConfig
171171

172+
// InferencePoolName is the name of the InferencePool, if this backendRef is for an InferencePool.
173+
InferencePoolName string
174+
172175
Filters []any
173176

174177
// IsInferencePool indicates if this backend is an InferencePool disguised as a Service.

0 commit comments

Comments
 (0)