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
41 changes: 41 additions & 0 deletions docs/guides/service-name-override.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Service Name Override

Override default generated VPC Lattice service names for Routes to avoid conflicts or implement naming conventions.

## Usage

Add the annotation to HTTPRoute or GRPCRoute:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-service
namespace: production
annotations:
application-networking.k8s.aws/service-name-override: "custom-service-name"
spec:
parentRefs:
- name: my-gateway
rules:
- backendRefs:
- name: backend-service
port: 80
```

## Before You Start

Service name overrides must be set during route creation and cannot be modified. Adding or changing the annotation on existing routes does not work.

**To add or change a service name override for existing route:**
1. Delete the route: `kubectl delete httproute my-route`
2. Update annotation and recreate: `kubectl apply -f updated-route.yaml`

## Validation Rules

Service names must:
- Be 3-40 characters long
- Use only lowercase letters, numbers, and hyphens
- Start and end with alphanumeric characters
- Not start with `svc-`
- Not contain `--` or start/end with `-`
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import (
)

const (
AccessLogSubscriptionAnnotationKey = k8s.AnnotationPrefix + "accessLogSubscription"
AccessLogSubscriptionAnnotationKey = k8s.AnnotationPrefix + "accessLogSubscription"
AccessLogSubscriptionResourceNameAnnotationKey = k8s.AnnotationPrefix + "accessLogSubscriptionResourceName"
)

// +genclient
Expand Down
83 changes: 68 additions & 15 deletions pkg/controllers/accesslogpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,25 @@ func (r *accessLogPolicyReconciler) reconcile(ctx context.Context, req ctrl.Requ

r.eventRecorder.Event(alp, corev1.EventTypeNormal, k8s.ReconcilingEvent, "Started reconciling")

var err error
if !alp.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, alp)
err = r.reconcileDelete(ctx, alp)
} else {
return r.reconcileUpsert(ctx, alp)
err = r.reconcileUpsert(ctx, alp)
}

if err != nil {
r.eventRecorder.Event(alp, corev1.EventTypeWarning, k8s.FailedReconcileEvent, fmt.Sprintf("Reconcile failed: %s", err))
return err
}

r.eventRecorder.Event(alp, corev1.EventTypeNormal, k8s.ReconciledEvent, "Successfully reconciled")
return nil
}

func (r *accessLogPolicyReconciler) reconcileDelete(ctx context.Context, alp *anv1alpha1.AccessLogPolicy) error {
_, err := r.buildAndDeployModel(ctx, alp)
targetRefName := alp.Annotations[anv1alpha1.AccessLogSubscriptionResourceNameAnnotationKey]
_, err := r.buildAndDeployModel(ctx, alp, targetRefName)
if err != nil {
r.eventRecorder.Event(alp, corev1.EventTypeWarning,
k8s.FailedReconcileEvent, fmt.Sprintf("Failed to delete due to %s", err))
Expand Down Expand Up @@ -189,7 +199,7 @@ func (r *accessLogPolicyReconciler) reconcileUpsert(ctx context.Context, alp *an
return r.updateAccessLogPolicyStatus(ctx, alp, gwv1alpha2.PolicyReasonInvalid, message)
}

targetRefExists, err := r.targetRefExists(ctx, alp)
targetRefExists, targetRef, err := r.targetRefExists(ctx, alp)
if err != nil {
return err
}
Expand All @@ -199,7 +209,15 @@ func (r *accessLogPolicyReconciler) reconcileUpsert(ctx context.Context, alp *an
return r.updateAccessLogPolicyStatus(ctx, alp, gwv1alpha2.PolicyReasonTargetNotFound, message)
}

stack, err := r.buildAndDeployModel(ctx, alp)
targetRefName, err := r.targetRefToResourceName(alp, targetRef)
if err != nil {
if k8s.IsInvalidServiceNameOverrideError(err) {
return r.updateAccessLogPolicyStatus(ctx, alp, gwv1alpha2.PolicyReasonInvalid, err.Error())
}
return err
}

stack, err := r.buildAndDeployModel(ctx, alp, targetRefName)
if err != nil {
if services.IsConflictError(err) {
message := "An Access Log Policy with a Destination Arn for the same destination type already exists for this targetRef"
Expand All @@ -215,7 +233,7 @@ func (r *accessLogPolicyReconciler) reconcileUpsert(ctx context.Context, alp *an
return err
}

err = r.updateAccessLogPolicyAnnotations(ctx, alp, stack)
err = r.updateAccessLogPolicyAnnotations(ctx, alp, stack, targetRefName)
if err != nil {
return err
}
Expand All @@ -230,40 +248,46 @@ func (r *accessLogPolicyReconciler) reconcileUpsert(ctx context.Context, alp *an
return nil
}

func (r *accessLogPolicyReconciler) targetRefExists(ctx context.Context, alp *anv1alpha1.AccessLogPolicy) (bool, error) {
func (r *accessLogPolicyReconciler) targetRefExists(ctx context.Context, alp *anv1alpha1.AccessLogPolicy) (bool, metav1.Object, error) {
targetRefNamespacedName := types.NamespacedName{
Name: string(alp.Spec.TargetRef.Name),
Namespace: k8s.NamespaceOrDefault(alp.Spec.TargetRef.Namespace),
}

var err error
var targetObj metav1.Object

switch alp.Spec.TargetRef.Kind {
case "Gateway":
gw := &gwv1.Gateway{}
err = r.client.Get(ctx, targetRefNamespacedName, gw)
targetObj = gw
case "HTTPRoute":
httpRoute := &gwv1.HTTPRoute{}
err = r.client.Get(ctx, targetRefNamespacedName, httpRoute)
route := &gwv1.HTTPRoute{}
err = r.client.Get(ctx, targetRefNamespacedName, route)
targetObj = route
case "GRPCRoute":
grpcRoute := &gwv1.GRPCRoute{}
err = r.client.Get(ctx, targetRefNamespacedName, grpcRoute)
route := &gwv1.GRPCRoute{}
err = r.client.Get(ctx, targetRefNamespacedName, route)
targetObj = route
default:
return false, fmt.Errorf("access Log Policy targetRef is for unsupported Kind: %s", alp.Spec.TargetRef.Kind)
return false, nil, fmt.Errorf("access Log Policy targetRef is for unsupported Kind: %s", alp.Spec.TargetRef.Kind)
}

if err != nil && !apierrors.IsNotFound(err) {
return false, err
return false, nil, err
}

return err == nil, nil
exists := err == nil
return exists, targetObj, nil
}

func (r *accessLogPolicyReconciler) buildAndDeployModel(
ctx context.Context,
alp *anv1alpha1.AccessLogPolicy,
targetRefName string,
) (core.Stack, error) {
stack, _, err := r.modelBuilder.Build(ctx, alp)
stack, _, err := r.modelBuilder.Build(ctx, alp, targetRefName)
if err != nil {
return nil, err
}
Expand All @@ -286,6 +310,7 @@ func (r *accessLogPolicyReconciler) updateAccessLogPolicyAnnotations(
ctx context.Context,
alp *anv1alpha1.AccessLogPolicy,
stack core.Stack,
targetRefName string,
) error {
var accessLogSubscriptions []*model.AccessLogSubscription
err := stack.ListResources(&accessLogSubscriptions)
Expand All @@ -300,6 +325,7 @@ func (r *accessLogPolicyReconciler) updateAccessLogPolicyAnnotations(
alp.Annotations = make(map[string]string)
}
alp.Annotations[anv1alpha1.AccessLogSubscriptionAnnotationKey] = als.Status.Arn
alp.Annotations[anv1alpha1.AccessLogSubscriptionResourceNameAnnotationKey] = targetRefName
if err := r.client.Patch(ctx, alp, client.MergeFrom(oldAlp)); err != nil {
r.eventRecorder.Event(alp, corev1.EventTypeWarning, k8s.FailedReconcileEvent,
"Failed to update annotation due to "+err.Error())
Expand Down Expand Up @@ -375,3 +401,30 @@ func (r *accessLogPolicyReconciler) findImpactedAccessLogPolicies(ctx context.Co

return requests
}

func (r *accessLogPolicyReconciler) targetRefToResourceName(
alp *anv1alpha1.AccessLogPolicy,
targetObj metav1.Object,
) (string, error) {
targetRef := alp.Spec.TargetRef

if targetRef.Kind == "Gateway" {
return string(targetRef.Name), nil
}

if targetRef.Kind == "HTTPRoute" || targetRef.Kind == "GRPCRoute" {
namespace := alp.Namespace
if targetRef.Namespace != nil {
namespace = string(*targetRef.Namespace)
}

serviceNameOverride, err := k8s.GetServiceNameOverrideWithValidation(targetObj)
if err != nil {
return "", fmt.Errorf("route '%s' has %w", targetRef.Name, err)
}

return utils.LatticeServiceName(string(targetRef.Name), namespace, serviceNameOverride), nil
}

return "", fmt.Errorf("unsupported targetRef kind: %s", targetRef.Kind)
}
Loading
Loading