Skip to content

Commit e21d0f7

Browse files
golgoth31claude
andcommitted
fix(webhook): scope v1alpha1 DNSRecord webhook to v1alpha1 requests
The vdnsrecord-v1alpha1 validating webhook had no matchPolicy, so it defaulted to Equivalent: the apiserver converted v1alpha2 DNSRecord writes to v1alpha1 and routed them through this webhook too. Since the v2->v1 conversion stamps every record with the v1alpha2-spec annotation the validator keys on, it rejected the DNS controller's own v1alpha2 auto-record updates ("... cannot be modified via v1alpha1"), looping the DNS reconcile. Set matchPolicy=Exact so the webhook only fires for genuine v1alpha1 requests, leaving v1alpha2 controller writes untouched. A v1alpha1-native edit of a v2-backed record is still blocked (intended — it preserves the controller-SA reservation on origin=auto and the v2-only data). Reworded the message/var since it applies to any v2-backed record, not only manual. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 25b66c1 commit e21d0f7

4 files changed

Lines changed: 14 additions & 7 deletions

File tree

config/webhook/manifests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ webhooks:
9898
namespace: system
9999
path: /validate-sreportal-io-v1alpha1-dnsrecord
100100
failurePolicy: Fail
101+
matchPolicy: Exact
101102
name: vdnsrecord-v1alpha1.kb.io
102103
rules:
103104
- apiGroups:

helm/templates/validating-webhook-configuration.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ webhooks:
5555
namespace: '{{ .Release.Namespace }}'
5656
path: /validate-sreportal-io-v1alpha1-dnsrecord
5757
failurePolicy: Fail
58+
matchPolicy: Exact
5859
name: vdnsrecord-v1alpha1.kb.io
5960
rules:
6061
- apiGroups:

internal/webhook/v1alpha1/dnsrecord_webhook.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,16 @@ func SetupDNSRecordWebhookWithManager(mgr ctrl.Manager) error {
3535
Complete()
3636
}
3737

38-
// +kubebuilder:webhook:path=/validate-sreportal-io-v1alpha1-dnsrecord,mutating=false,failurePolicy=fail,sideEffects=None,groups=sreportal.io,resources=dnsrecords,verbs=update,versions=v1alpha1,name=vdnsrecord-v1alpha1.kb.io,admissionReviewVersions=v1
38+
// matchPolicy=Exact so this webhook only fires for genuine v1alpha1 requests.
39+
// With the default (Equivalent), the apiserver converts v1alpha2 writes to
40+
// v1alpha1 and routes them here too — which wrongly blocks the DNS controller's
41+
// own v1alpha2 record updates (conversion stamps every record with the
42+
// v1alpha2-spec annotation this validator keys on).
43+
// +kubebuilder:webhook:path=/validate-sreportal-io-v1alpha1-dnsrecord,mutating=false,failurePolicy=fail,matchPolicy=Exact,sideEffects=None,groups=sreportal.io,resources=dnsrecords,verbs=update,versions=v1alpha1,name=vdnsrecord-v1alpha1.kb.io,admissionReviewVersions=v1
3944

40-
// DNSRecordValidator rejects updates that would silently clobber the manual
41-
// entries stored in the v1alpha2 spec annotation when a client edits through
42-
// the v1alpha1 surface.
45+
// DNSRecordValidator rejects updates that would silently clobber the v1alpha2-only
46+
// data (origin, entries) stored in the spec annotation when a client edits a
47+
// v1alpha2-backed record through the v1alpha1 surface.
4348
type DNSRecordValidator struct{}
4449

4550
func (v *DNSRecordValidator) ValidateCreate(_ context.Context, _ *sreportalv1alpha1.DNSRecord) (admission.Warnings, error) {
@@ -50,10 +55,10 @@ func (v *DNSRecordValidator) ValidateUpdate(_ context.Context, oldObj, _ *srepor
5055
if oldObj == nil {
5156
return nil, nil
5257
}
53-
if _, manual := oldObj.Annotations[annotationV1Alpha2DNSRecordSpec]; !manual {
58+
if _, backedByV2 := oldObj.Annotations[annotationV1Alpha2DNSRecordSpec]; !backedByV2 {
5459
return nil, nil
5560
}
56-
return nil, fmt.Errorf("manual DNSRecord cannot be modified via v1alpha1; use sreportal.io/v1alpha2")
61+
return nil, fmt.Errorf("DNSRecord backed by v1alpha2 cannot be modified via v1alpha1; use sreportal.io/v1alpha2")
5762
}
5863

5964
func (v *DNSRecordValidator) ValidateDelete(_ context.Context, _ *sreportalv1alpha1.DNSRecord) (admission.Warnings, error) {

internal/webhook/v1alpha1/dnsrecord_webhook_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var _ = Describe("DNSRecord v1alpha1 Webhook", func() {
4545

4646
warnings, err := validator.ValidateUpdate(context.Background(), old, newObj)
4747
Expect(err).To(HaveOccurred())
48-
Expect(err.Error()).To(ContainSubstring("manual DNSRecord cannot be modified via v1alpha1"))
48+
Expect(err.Error()).To(ContainSubstring("DNSRecord backed by v1alpha2 cannot be modified via v1alpha1"))
4949
Expect(warnings).To(BeEmpty())
5050
})
5151

0 commit comments

Comments
 (0)