Skip to content

Commit 7cc809b

Browse files
authored
Merge pull request #414 from containeroo/fix/ingress
fix(ingress): delete orphaned dns records
2 parents cae2e52 + 86dab32 commit 7cc809b

File tree

5 files changed

+98
-3
lines changed

5 files changed

+98
-3
lines changed

internal/controller/ingress_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ func (r *IngressReconciler) reconcileIngress(ctx context.Context, ingress *netwo
7979

8080
annotations := ingress.GetAnnotations()
8181

82+
if annotations["cloudflare-operator.io/content"] == "" && annotations["cloudflare-operator.io/ip-ref"] == "" {
83+
for _, record := range dnsRecords.Items {
84+
if err := r.Delete(ctx, &record); err != nil {
85+
log.Error(err, "Failed to delete DNSRecord", "name", record.Name)
86+
}
87+
}
88+
89+
return ctrl.Result{}, nil
90+
}
91+
8292
dnsRecordSpec := r.parseAnnotations(annotations)
8393
existingRecords := make(map[string]cloudflareoperatoriov1.DNSRecord)
8494
for _, record := range dnsRecords.Items {

internal/controller/ingress_controller_test.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
. "github.com/onsi/gomega"
2626

2727
networkingv1 "k8s.io/api/networking/v1"
28+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2829
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930
"sigs.k8s.io/controller-runtime/pkg/client"
3031
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -77,6 +78,23 @@ func TestIngressReconciler_reconcileIngress(t *testing.T) {
7778
g.Expect(dnsRecord.Spec).To(HaveField("Content", Equal("1.1.1.1")))
7879
})
7980

81+
t.Run("change dnsrecord spec when annotations change", func(t *testing.T) {
82+
g := NewWithT(t)
83+
ingress.Annotations = map[string]string{
84+
"cloudflare-operator.io/content": "2.2.2.2",
85+
}
86+
87+
_, err := r.reconcileIngress(context.TODO(), ingress)
88+
g.Expect(err).NotTo(HaveOccurred())
89+
90+
dnsRecord := &cloudflareoperatoriov1.DNSRecord{}
91+
err = r.Get(context.TODO(), client.ObjectKey{Namespace: "default", Name: "ingtest-containeroo-test-org"}, dnsRecord)
92+
g.Expect(err).NotTo(HaveOccurred())
93+
94+
g.Expect(dnsRecord.Spec).To(HaveField("Name", Equal("ingtest.containeroo-test.org")))
95+
g.Expect(dnsRecord.Spec).To(HaveField("Content", Equal("2.2.2.2")))
96+
})
97+
8098
t.Run("reconcile ingress wildcard", func(t *testing.T) {
8199
g := NewWithT(t)
82100
ingress.Spec = networkingv1.IngressSpec{
@@ -92,7 +110,19 @@ func TestIngressReconciler_reconcileIngress(t *testing.T) {
92110
g.Expect(err).NotTo(HaveOccurred())
93111

94112
g.Expect(dnsRecord.Spec).To(HaveField("Name", Equal("*.containeroo-test.org")))
95-
g.Expect(dnsRecord.Spec).To(HaveField("Content", Equal("1.1.1.1")))
113+
g.Expect(dnsRecord.Spec).To(HaveField("Content", Equal("2.2.2.2")))
114+
})
115+
116+
t.Run("remove dnsrecord when annotations are absent", func(t *testing.T) {
117+
g := NewWithT(t)
118+
ingress.Annotations = map[string]string{}
119+
120+
_, err := r.reconcileIngress(context.TODO(), ingress)
121+
g.Expect(err).NotTo(HaveOccurred())
122+
123+
dnsRecord := &cloudflareoperatoriov1.DNSRecord{}
124+
err = r.Get(context.TODO(), client.ObjectKey{Namespace: "default", Name: "wildcard-containeroo-test-org"}, dnsRecord)
125+
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
96126
})
97127

98128
t.Run("ingress annotation parsing", func(t *testing.T) {

internal/predicates/predicates.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package predicates
1818

1919
import (
2020
"reflect"
21+
"slices"
2122

2223
cloudflareoperatoriov1 "github.com/containeroo/cloudflare-operator/api/v1"
2324
networkingv1 "k8s.io/api/networking/v1"
@@ -46,13 +47,28 @@ func (DNSFromIngressPredicate) Update(e event.UpdateEvent) bool {
4647
oldAnnotations := e.ObjectOld.GetAnnotations()
4748
newAnnotations := e.ObjectNew.GetAnnotations()
4849

50+
oldObjectHadRequiredAnnotations := ingressHasRequiredAnnotations(oldAnnotations)
51+
newObjectHasRequiredAnnotations := ingressHasRequiredAnnotations(newAnnotations)
52+
4953
oldObj := e.ObjectOld.(*networkingv1.Ingress)
5054
newObj := e.ObjectNew.(*networkingv1.Ingress)
5155

5256
annotationsChanged := !reflect.DeepEqual(oldAnnotations, newAnnotations)
53-
rulesChanged := !reflect.DeepEqual(oldObj.Spec.Rules, newObj.Spec.Rules)
57+
oldHosts := []string{}
58+
for _, rule := range oldObj.Spec.Rules {
59+
oldHosts = append(oldHosts, rule.Host)
60+
}
61+
newHosts := []string{}
62+
for _, rule := range newObj.Spec.Rules {
63+
newHosts = append(newHosts, rule.Host)
64+
}
65+
66+
slices.Sort(oldHosts)
67+
slices.Sort(newHosts)
68+
69+
hostsChanged := !reflect.DeepEqual(oldHosts, newHosts)
5470

55-
return ingressHasRequiredAnnotations(newAnnotations) && (annotationsChanged || rulesChanged)
71+
return (newObjectHasRequiredAnnotations && (annotationsChanged || hostsChanged)) || (oldObjectHadRequiredAnnotations && !newObjectHasRequiredAnnotations)
5672
}
5773

5874
func (DNSFromIngressPredicate) Delete(e event.DeleteEvent) bool {

test/e2e/e2e_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,24 @@ var _ = Describe("controller", Ordered, func() {
202202
Eventually(utils.VerifyDNSRecordContent, time.Minute, time.Second).
203203
WithArguments("ingress-containeroo-test-org", "145.145.145.145").Should(Succeed())
204204
})
205+
206+
It("should recreate dnsrecord when it gets deleted", func() {
207+
cmd := exec.Command("kubectl", "-n", namespace, "delete", "dnsrecord", "ingress-containeroo-test-org")
208+
_, err := utils.Run(cmd)
209+
Expect(err).NotTo(HaveOccurred())
210+
211+
Eventually(utils.VerifyObjectReady, time.Minute, time.Second).
212+
WithArguments("dnsrecord", "ingress-containeroo-test-org").Should(Succeed())
213+
})
214+
215+
It("should delete dnsrecord when ingress annotations are absent", func() {
216+
cmd := exec.Command(
217+
"kubectl", "-n", namespace, "patch", "ingress", "ingress-sample",
218+
"--type=json", "-p", `[{"op": "remove", "path": "/metadata/annotations"}]`)
219+
_, err := utils.Run(cmd)
220+
Expect(err).NotTo(HaveOccurred())
221+
222+
Eventually(utils.VerifyDNSRecordAbsent, time.Minute, time.Second).
223+
WithArguments("ingress-containeroo-test-org").Should(Succeed())
224+
})
205225
})

test/utils/utils.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,22 @@ func VerifyDNSRecordContent(objName, expectedContent string) error {
148148
}
149149
return nil
150150
}
151+
152+
func VerifyDNSRecordAbsent(objName string) error {
153+
cmd := exec.Command(
154+
"kubectl",
155+
"get",
156+
"dnsrecord",
157+
objName,
158+
"-n",
159+
"cloudflare-operator-system",
160+
)
161+
status, err := Run(cmd)
162+
if err != nil {
163+
if strings.Contains(string(status), "NotFound") {
164+
return nil
165+
}
166+
return err
167+
}
168+
return fmt.Errorf("dnsrecord %s still exists", objName)
169+
}

0 commit comments

Comments
 (0)