Skip to content

Commit cd4f009

Browse files
scotwellsclaude
andcommitted
fix: explicitly delete DNSRecordSets when Gateway is deleted
Owner reference-based garbage collection doesn't work for DNSRecordSets because the dns-operator sets itself as the controller owner during replication. Kubernetes GC only deletes resources when ALL owners are deleted, so the Gateway's owner reference has no effect. This adds explicit cleanup in the Gateway finalizer that deletes DNSRecordSets matching our labels (dns.datumapis.com/source-name, dns.datumapis.com/source-namespace) when the Gateway is being deleted. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c6b2ccf commit cd4f009

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

internal/controller/gateway_controller.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,14 @@ func (r *GatewayReconciler) finalizeGateway(
797797
) (result Result) {
798798
logger := log.FromContext(ctx)
799799
logger.Info("finalizing gateway")
800+
801+
// Clean up DNS records created by this gateway
802+
if r.Config.Gateway.EnableDNSIntegration {
803+
if cleanupResult := r.cleanupDNSRecordSets(ctx, upstreamClient, upstreamGateway); cleanupResult.ShouldReturn() {
804+
return cleanupResult
805+
}
806+
}
807+
800808
// Go through downstream http routes that are attached to the downstream
801809
// gateway and remove the parentRef from the status. If it's the last parent
802810
// ref, delete the downstream route. If there's a race condition on delete/create,
@@ -870,6 +878,54 @@ func (r *GatewayReconciler) finalizeGateway(
870878
return result
871879
}
872880

881+
// cleanupDNSRecordSets deletes all DNSRecordSet resources that were created by
882+
// this gateway. This is called during gateway finalization to ensure DNS records
883+
// are cleaned up when the gateway is deleted, since owner reference-based garbage
884+
// collection doesn't work (the dns-operator sets itself as the controller owner).
885+
func (r *GatewayReconciler) cleanupDNSRecordSets(
886+
ctx context.Context,
887+
upstreamClient client.Client,
888+
upstreamGateway *gatewayv1.Gateway,
889+
) (result Result) {
890+
logger := log.FromContext(ctx)
891+
892+
var recordSetList dnsv1alpha1.DNSRecordSetList
893+
if err := upstreamClient.List(ctx, &recordSetList,
894+
client.InNamespace(upstreamGateway.Namespace),
895+
client.MatchingLabels{
896+
labelDNSManaged: "true",
897+
labelManagedBy: labelManagedByValue,
898+
labelDNSSourceKind: KindGateway,
899+
labelDNSSourceName: upstreamGateway.Name,
900+
labelDNSSourceNS: upstreamGateway.Namespace,
901+
},
902+
); err != nil {
903+
// If the CRD doesn't exist, there's nothing to clean up
904+
if apimeta.IsNoMatchError(err) {
905+
return result
906+
}
907+
result.Err = fmt.Errorf("failed listing DNSRecordSets for cleanup: %w", err)
908+
return result
909+
}
910+
911+
for _, rs := range recordSetList.Items {
912+
logger.Info("deleting DNSRecordSet during gateway finalization",
913+
"name", rs.Name,
914+
"hostname", rs.Annotations[annotationDNSHostname],
915+
)
916+
if err := upstreamClient.Delete(ctx, &rs); err != nil && !apierrors.IsNotFound(err) {
917+
result.Err = fmt.Errorf("failed to delete DNSRecordSet %q: %w", rs.Name, err)
918+
return result
919+
}
920+
}
921+
922+
if len(recordSetList.Items) > 0 {
923+
logger.Info("deleted DNSRecordSets during gateway finalization", "count", len(recordSetList.Items))
924+
}
925+
926+
return result
927+
}
928+
873929
// TODO(jreese) revisit the parameters here to clean them up. It's a bit messy
874930
// as this function is used against both the upstream and downstream resources.
875931
func (r *GatewayReconciler) detachHTTPRoutes(

0 commit comments

Comments
 (0)