Skip to content

Commit 4740b65

Browse files
authored
fix: Requeue DNSEndpoint request when create fails with already exists error (#3637)
* Requeue DNSEndpoint when create fails with already exists error * Add python tests
1 parent 3fab418 commit 4740b65

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

internal/externaldns/sync.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func SyncFnFor(rec record.EventRecorder, client clientset.Interface, ig map[stri
4444
}
4545

4646
if vs.Status.ExternalEndpoints == nil {
47-
// It can take time for the external endpoints to sync
47+
// It can take time for the external endpoints to sync - kick it back to the queue
4848
glog.V(3).Info("Failed to determine external endpoints - retrying")
4949
return fmt.Errorf("failed to determine external endpoints")
5050
}
@@ -60,7 +60,7 @@ func SyncFnFor(rec record.EventRecorder, client clientset.Interface, ig map[stri
6060

6161
newDNSEndpoint, updateDNSEndpoint, err := buildDNSEndpoint(nsi.extdnslister, vs, targets, recordType)
6262
if err != nil {
63-
glog.Errorf("error message here %s", err)
63+
glog.Errorf("incorrect DNSEndpoint config for VirtualServer resource: %s", err)
6464
rec.Eventf(vs, corev1.EventTypeWarning, reasonBadConfig, "Incorrect DNSEndpoint config for VirtualServer resource: %s", err)
6565
return err
6666
}
@@ -72,6 +72,11 @@ func SyncFnFor(rec record.EventRecorder, client clientset.Interface, ig map[stri
7272
glog.V(3).Infof("Creating DNSEndpoint for VirtualServer resource: %v", vs.Name)
7373
dep, err = client.ExternaldnsV1().DNSEndpoints(newDNSEndpoint.Namespace).Create(ctx, newDNSEndpoint, metav1.CreateOptions{})
7474
if err != nil {
75+
if apierrors.IsAlreadyExists(err) {
76+
// Another replica likely created the DNSEndpoint since we last checked - kick it back to the queue
77+
glog.V(3).Info("DNSEndpoint has been created since we last checked - retrying")
78+
return fmt.Errorf("DNSEndpoint has already been created")
79+
}
7580
glog.Errorf("Error creating DNSEndpoint for VirtualServer resource: %v", err)
7681
rec.Eventf(vs, corev1.EventTypeWarning, reasonBadConfig, "Error creating DNSEndpoint for VirtualServer resource %s", err)
7782
return err
@@ -175,7 +180,7 @@ func buildDNSEndpoint(extdnsLister extdnslisters.DNSEndpointLister, vs *vsapi.Vi
175180
vs = vs.DeepCopy()
176181

177182
if existingDNSEndpoint != nil {
178-
glog.V(3).Infof("DNDEndpoint already exist for this object, ensuring it is up to date")
183+
glog.V(3).Infof("DNSEndpoint already exists for this object, ensuring it is up to date")
179184
if metav1.GetControllerOf(existingDNSEndpoint) == nil {
180185
glog.V(3).Infof("DNSEndpoint has no owner. refusing to update non-owned resource")
181186
return nil, nil, nil

tests/suite/test_virtual_server_externaldns.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from settings import TEST_DATA
3-
from suite.utils.custom_assertions import assert_event
4-
from suite.utils.custom_resources_utils import is_dnsendpoint_present
3+
from suite.utils.custom_assertions import assert_event, assert_event_not_present
4+
from suite.utils.custom_resources_utils import is_dnsendpoint_present, read_custom_resource
55
from suite.utils.resources_utils import get_events, patch_namespace_with_label, wait_before_test
66
from suite.utils.vs_vsr_resources_utils import patch_virtual_server_from_yaml
77
from suite.utils.yaml_utils import get_name_from_yaml, get_namespace_from_yaml
@@ -48,6 +48,21 @@ def test_responses_after_setup(
4848
wait_before_test(1)
4949
print(f"External DNS not updated, retrying... #{retry}")
5050
assert wanted_string in log_contents
51+
print("\nStep 3: Verify VS status is Valid and no bad config events occurred")
52+
events = get_events(kube_apis.v1, virtual_server_setup.namespace)
53+
vs_bad_config_event = "Error creating DNSEndpoint for VirtualServer resource"
54+
assert_event_not_present(vs_bad_config_event, events)
55+
response = read_custom_resource(
56+
kube_apis.custom_objects,
57+
virtual_server_setup.namespace,
58+
"virtualservers",
59+
virtual_server_setup.vs_name,
60+
)
61+
assert (
62+
response["status"]
63+
and response["status"]["reason"] == "AddedOrUpdated"
64+
and response["status"]["state"] == "Valid"
65+
)
5166

5267
def test_update_to_ed_in_vs(
5368
self, kube_apis, crd_ingress_controller_with_ed, create_externaldns, virtual_server_setup
@@ -65,6 +80,18 @@ def test_update_to_ed_in_vs(
6580
wait_before_test(5)
6681
events = get_events(kube_apis.v1, virtual_server_setup.namespace)
6782
assert_event(vs_event_update_text, events)
83+
print("\nStep 3: Verify VS status is Valid")
84+
response = read_custom_resource(
85+
kube_apis.custom_objects,
86+
virtual_server_setup.namespace,
87+
"virtualservers",
88+
virtual_server_setup.vs_name,
89+
)
90+
assert (
91+
response["status"]
92+
and response["status"]["reason"] == "AddedOrUpdated"
93+
and response["status"]["state"] == "Valid"
94+
)
6895

6996

7097
@pytest.mark.vs
@@ -122,3 +149,18 @@ def test_responses_after_setup(
122149
wait_before_test(1)
123150
print(f"External DNS not updated, retrying... #{retry}")
124151
assert wanted_string in log_contents
152+
print("\nStep 3: Verify VS status is Valid and no bad config events occurred")
153+
events = get_events(kube_apis.v1, virtual_server_setup.namespace)
154+
vs_bad_config_event = "Error creating DNSEndpoint for VirtualServer resource"
155+
assert_event_not_present(vs_bad_config_event, events)
156+
response = read_custom_resource(
157+
kube_apis.custom_objects,
158+
virtual_server_setup.namespace,
159+
"virtualservers",
160+
virtual_server_setup.vs_name,
161+
)
162+
assert (
163+
response["status"]
164+
and response["status"]["reason"] == "AddedOrUpdated"
165+
and response["status"]["state"] == "Valid"
166+
)

tests/suite/utils/custom_assertions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,19 @@ def assert_event(event_text, events_list) -> None:
143143
pytest.fail(f'Failed to find the event "{event_text}" in the list. Exiting...')
144144

145145

146+
def assert_event_not_present(event_text, events_list) -> None:
147+
"""
148+
Search for the event in the list.
149+
150+
:param event_text: event text
151+
:param events_list: list of events
152+
:return:
153+
"""
154+
for i in range(len(events_list) - 1, -1, -1):
155+
if event_text in events_list[i].message:
156+
pytest.fail(f'Event "{event_text}" exists in the list. Exiting...')
157+
158+
146159
def assert_event_starts_with_text_and_contains_errors(event_text, events_list, fields_list) -> None:
147160
"""
148161
Search for the event starting with the expected text in the list and check its message.

0 commit comments

Comments
 (0)