From f2af4a94f013c29b1479403b3aea25717b4959e1 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Wed, 30 Oct 2024 16:47:01 +0100 Subject: [PATCH 01/11] adds waiting for dns --- services/dns/src/stackit/dns/wait.py | 253 +++++++++++++++++++++++++++ services/dns/tests/test_wait.py | 143 +++++++++++++++ 2 files changed, 396 insertions(+) create mode 100644 services/dns/src/stackit/dns/wait.py create mode 100644 services/dns/tests/test_wait.py diff --git a/services/dns/src/stackit/dns/wait.py b/services/dns/src/stackit/dns/wait.py new file mode 100644 index 000000000..b57d4d626 --- /dev/null +++ b/services/dns/src/stackit/dns/wait.py @@ -0,0 +1,253 @@ +from enum import Enum +from typing import Any, Callable, Tuple, Union +from stackit.dns.api.default_api import DefaultApi +from stackit.dns.models.record_set_response import RecordSetResponse +from stackit.dns.models.zone_response import ZoneResponse +from stackit.dns.exceptions import ApiException +from stackit.core.wait import Wait + + +class _States(str, Enum): + CreateSuccess = "CREATE_SUCCEEDED" + CreateFail = "CREATE_FAILED" + UpdateSuccess = "UPDATE_SUCCEEDED" + UpdateFail = "UPDATE_FAILED" + DeleteSuccess = "DELETE_SUCCEEDED" + DeleteFail = "DELETE_FAILED" + + +def wait_for_create_zone( + api_client: DefaultApi, + project_id: str, + zone_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> ZoneResponse: + + def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id + + try: + response = api_client.get_zone(project_id, zone_id) + if response.zone.id != zone_id: + return False, ValueError("ID of zone in return not equal to ID of requested zone."), None, None + elif response.zone.state == _States.CreateSuccess: + return True, None, None, response + elif response.zone.state == _States.CreateFail: + return True, Exception("Create failed for zone with id %s" % zone_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_zone_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() + + +def wait_for_partial_update_zone( + api_client: DefaultApi, + project_id: str, + zone_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> ZoneResponse: + + def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id + + try: + response = api_client.get_zone(project_id, zone_id) + if response.zone.id != zone_id: + return False, ValueError("ID of zone in return not equal to ID of requested zone."), None, None + elif response.zone.state == _States.UpdateSuccess: + return True, None, None, response + elif response.zone.state == _States.UpdateFail: + return True, Exception("Update failed for zone with id %s" % zone_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_zone_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() + + +def wait_for_delete_zone( + api_client: DefaultApi, + project_id: str, + zone_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> ZoneResponse: + + def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id + + try: + response = api_client.get_zone(project_id, zone_id) + if response.zone.id != zone_id: + return False, ValueError("ID of zone in return not equal to ID of requested zone."), None, None + elif response.zone.state == _States.DeleteSuccess: + return True, None, None, response + elif response.zone.state == _States.DeleteFail: + return True, Exception("Delete failed for zone with id %s" % zone_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_zone_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() + + +def wait_for_create_recordset( + api_client: DefaultApi, + project_id: str, + zone_id: str, + rr_set_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> RecordSetResponse: + + def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id, rr_set_id + + try: + response = api_client.get_record_set(project_id, zone_id, rr_set_id) + if response.rrset.id != zone_id: + return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None + elif response.rrset.state == _States.CreateSuccess: + return True, None, None, response + elif response.rrset.state == _States.CreateFail: + return True, Exception("Create failed for rrset with id %s" % rr_set_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_rr_set_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() + + +def wait_for_partial_update_recordset( + api_client: DefaultApi, + project_id: str, + zone_id: str, + rr_set_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> RecordSetResponse: + + def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id, rr_set_id + + try: + response = api_client.get_record_set(project_id, zone_id, rr_set_id) + if response.rrset.id != zone_id: + return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None + elif response.rrset.state == _States.UpdateSuccess: + return True, None, None, response + elif response.rrset.state == _States.UpdateFail: + return True, Exception("Update failed for rrset with id %s" % rr_set_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_rr_set_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() + + +def wait_for_delete_recordset( + api_client: DefaultApi, + project_id: str, + zone_id: str, + rr_set_id: str, + sleep_before_wait: int = 0, + throttle: int = 5, + timeout: int = 30, + temp_error_retry_limit: int = 5, +) -> RecordSetResponse: + + def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: + + nonlocal api_client, project_id, zone_id, rr_set_id + + try: + response = api_client.get_record_set(project_id, zone_id, rr_set_id) + if response.rrset.id != zone_id: + return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None + elif response.rrset.state == _States.DeleteSuccess: + return True, None, None, response + elif response.rrset.state == _States.DeleteFail: + return True, Exception("Delete failed for rrset with id %s" % rr_set_id), None, response + else: + return False, None, None, None + except ApiException as e: + return False, e, e.status, None + except Exception as e: + return False, e, None, None + + wait = Wait( + get_rr_set_execute_state, + sleep_before_wait=sleep_before_wait, + throttle=throttle, + timeout=timeout, + temp_error_retry_limit=temp_error_retry_limit, + ) + return wait.wait() diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py new file mode 100644 index 000000000..b1b210ea0 --- /dev/null +++ b/services/dns/tests/test_wait.py @@ -0,0 +1,143 @@ +import pytest +from stackit.dns.wait import * +from stackit.core.wait import Wait +from stackit.dns.models.zone_response import ZoneResponse +from stackit.dns.models.zone import Zone +from unittest.mock import Mock + + +def test_create_zone_wait_handler_fails_for_wrong_id(): + zone_id = "zone_id" + project_id = "project_id" + + api_response = ZoneResponse( + zone=Zone( + id="incorrect_id", + acl="acl", + creationFinished="creationFinished", + creationStarted="creationStarted", + defaultTTL=60, + dnsName="dnsName", + expireTime=60, + name="name", + negativeCache=60, + primaryNameServer="fqdn", + refreshTime=60, + retryTime=60, + serialNumber=123456, + state="CREATING", + type="primary", + updateFinished="updateFinished", + updateStarted="updateStarted", + visibility="public", + ) + ) + + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(ValueError, match="ID of zone in return not equal to ID of requested zone."): + wait_for_create_zone(api_client, project_id, zone_id) + + +def test_create_zone_wait_handler_retuns_response(): + zone_id = "zone_id" + project_id = "project_id" + + expected_api_response = ZoneResponse( + zone=Zone( + id=zone_id, + acl="acl", + creationFinished="creationFinished", + creationStarted="creationStarted", + defaultTTL=60, + dnsName="dnsName", + expireTime=60, + name="name", + negativeCache=60, + primaryNameServer="fqdn", + refreshTime=60, + retryTime=60, + serialNumber=123456, + state="CREATE_SUCCEEDED", + type="primary", + updateFinished="updateFinished", + updateStarted="updateStarted", + visibility="public", + ) + ) + + api_client = Mock() + api_client.get_zone.return_value = expected_api_response + + response = wait_for_create_zone(api_client, project_id, zone_id) + + assert response == expected_api_response + + +def test_create_zone_wait_handler_fails_for_failure(): + zone_id = "zone_id" + project_id = "project_id" + + api_response = ZoneResponse( + zone=Zone( + id=zone_id, + acl="acl", + creationFinished="creationFinished", + creationStarted="creationStarted", + defaultTTL=60, + dnsName="dnsName", + expireTime=60, + name="name", + negativeCache=60, + primaryNameServer="fqdn", + refreshTime=60, + retryTime=60, + serialNumber=123456, + state="CREATE_FAILED", + type="primary", + updateFinished="updateFinished", + updateStarted="updateStarted", + visibility="public", + ) + ) + + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(Exception, match=f"Create failed for zone with id {zone_id}"): + wait_for_create_zone(api_client, project_id, zone_id) + + +def test_create_zone_wait_handler_waits(): + zone_id = "zone_id" + project_id = "project_id" + + api_response = ZoneResponse( + zone=Zone( + id=zone_id, + acl="acl", + creationFinished="creationFinished", + creationStarted="creationStarted", + defaultTTL=60, + dnsName="dnsName", + expireTime=60, + name="name", + negativeCache=60, + primaryNameServer="fqdn", + refreshTime=60, + retryTime=60, + serialNumber=123456, + state="CREATING", + type="primary", + updateFinished="updateFinished", + updateStarted="updateStarted", + visibility="public", + ) + ) + + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(TimeoutError, match="Wait has timed out"): + wait_for_create_zone(api_client, project_id, zone_id, timeout=1) From e673231c114b6750d55b195e9f8afb867141f34d Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Wed, 30 Oct 2024 16:48:20 +0100 Subject: [PATCH 02/11] linting --- services/dns/src/stackit/dns/wait.py | 8 +++++--- services/dns/tests/test_wait.py | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/services/dns/src/stackit/dns/wait.py b/services/dns/src/stackit/dns/wait.py index b57d4d626..5e1c09883 100644 --- a/services/dns/src/stackit/dns/wait.py +++ b/services/dns/src/stackit/dns/wait.py @@ -1,10 +1,12 @@ from enum import Enum -from typing import Any, Callable, Tuple, Union +from typing import Any, Tuple, Union + +from stackit.core.wait import Wait + from stackit.dns.api.default_api import DefaultApi +from stackit.dns.exceptions import ApiException from stackit.dns.models.record_set_response import RecordSetResponse from stackit.dns.models.zone_response import ZoneResponse -from stackit.dns.exceptions import ApiException -from stackit.core.wait import Wait class _States(str, Enum): diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index b1b210ea0..83dfbf251 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -1,9 +1,10 @@ +from unittest.mock import Mock + import pytest -from stackit.dns.wait import * -from stackit.core.wait import Wait -from stackit.dns.models.zone_response import ZoneResponse + from stackit.dns.models.zone import Zone -from unittest.mock import Mock +from stackit.dns.models.zone_response import ZoneResponse +from stackit.dns.wait import * def test_create_zone_wait_handler_fails_for_wrong_id(): From 850bd36ab6322fd480529a589ea7e62834f2d2b9 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 08:32:41 +0100 Subject: [PATCH 03/11] improve tests --- services/dns/tests/test_wait.py | 109 ++++++-------------------------- 1 file changed, 21 insertions(+), 88 deletions(-) diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index 83dfbf251..7653f7367 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -7,13 +7,10 @@ from stackit.dns.wait import * -def test_create_zone_wait_handler_fails_for_wrong_id(): - zone_id = "zone_id" - project_id = "project_id" - - api_response = ZoneResponse( +def zone_response(state: str, zone_id: str) -> ZoneResponse: + return ZoneResponse( zone=Zone( - id="incorrect_id", + id=zone_id, acl="acl", creationFinished="creationFinished", creationStarted="creationStarted", @@ -26,7 +23,7 @@ def test_create_zone_wait_handler_fails_for_wrong_id(): refreshTime=60, retryTime=60, serialNumber=123456, - state="CREATING", + state=state, type="primary", updateFinished="updateFinished", updateStarted="updateStarted", @@ -34,6 +31,10 @@ def test_create_zone_wait_handler_fails_for_wrong_id(): ) ) +@pytest.mark.parametrize("zone_id,project_id,api_response",[ + ("zone_id", "project_id", zone_response("CREATING", "incorrect_zone_id")) +]) +def test_create_zone_wait_handler_fails_for_wrong_id(zone_id:str, project_id:str, api_response:ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response @@ -41,33 +42,11 @@ def test_create_zone_wait_handler_fails_for_wrong_id(): wait_for_create_zone(api_client, project_id, zone_id) -def test_create_zone_wait_handler_retuns_response(): - zone_id = "zone_id" - project_id = "project_id" - - expected_api_response = ZoneResponse( - zone=Zone( - id=zone_id, - acl="acl", - creationFinished="creationFinished", - creationStarted="creationStarted", - defaultTTL=60, - dnsName="dnsName", - expireTime=60, - name="name", - negativeCache=60, - primaryNameServer="fqdn", - refreshTime=60, - retryTime=60, - serialNumber=123456, - state="CREATE_SUCCEEDED", - type="primary", - updateFinished="updateFinished", - updateStarted="updateStarted", - visibility="public", - ) - ) - +@pytest.mark.parametrize("zone_id,project_id,expected_api_response", [ + ("zone_id", "project_id", zone_response( + "CREATE_SUCCEEDED", "zone_id")) +]) +def test_create_zone_wait_handler_retuns_response(zone_id: str, project_id: str, expected_api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = expected_api_response @@ -76,33 +55,10 @@ def test_create_zone_wait_handler_retuns_response(): assert response == expected_api_response -def test_create_zone_wait_handler_fails_for_failure(): - zone_id = "zone_id" - project_id = "project_id" - - api_response = ZoneResponse( - zone=Zone( - id=zone_id, - acl="acl", - creationFinished="creationFinished", - creationStarted="creationStarted", - defaultTTL=60, - dnsName="dnsName", - expireTime=60, - name="name", - negativeCache=60, - primaryNameServer="fqdn", - refreshTime=60, - retryTime=60, - serialNumber=123456, - state="CREATE_FAILED", - type="primary", - updateFinished="updateFinished", - updateStarted="updateStarted", - visibility="public", - ) - ) - +@pytest.mark.parametrize("zone_id,project_id,api_response", [ + ("zone_id", "project_id", zone_response("CREATE_FAILED", "zone_id")) +]) +def test_create_zone_wait_handler_fails_for_failure(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response @@ -110,33 +66,10 @@ def test_create_zone_wait_handler_fails_for_failure(): wait_for_create_zone(api_client, project_id, zone_id) -def test_create_zone_wait_handler_waits(): - zone_id = "zone_id" - project_id = "project_id" - - api_response = ZoneResponse( - zone=Zone( - id=zone_id, - acl="acl", - creationFinished="creationFinished", - creationStarted="creationStarted", - defaultTTL=60, - dnsName="dnsName", - expireTime=60, - name="name", - negativeCache=60, - primaryNameServer="fqdn", - refreshTime=60, - retryTime=60, - serialNumber=123456, - state="CREATING", - type="primary", - updateFinished="updateFinished", - updateStarted="updateStarted", - visibility="public", - ) - ) - +@pytest.mark.parametrize("zone_id,project_id,api_response", [ + ("zone_id", "project_id", zone_response("CREATING", "zone_id")) +]) +def test_create_zone_wait_handler_waits(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response From 2b24e82476bd7e8cb3a4d44d0e80476a3641d3e9 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 08:39:24 +0100 Subject: [PATCH 04/11] made tests better --- services/dns/tests/test_wait.py | 48 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index 7653f7367..cf517e416 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -1,3 +1,4 @@ +from typing import List from unittest.mock import Mock import pytest @@ -31,10 +32,11 @@ def zone_response(state: str, zone_id: str) -> ZoneResponse: ) ) -@pytest.mark.parametrize("zone_id,project_id,api_response",[ - ("zone_id", "project_id", zone_response("CREATING", "incorrect_zone_id")) -]) -def test_create_zone_wait_handler_fails_for_wrong_id(zone_id:str, project_id:str, api_response:ZoneResponse): + +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("CREATING", "incorrect_zone_id"))] +) +def test_create_zone_wait_handler_fails_for_wrong_id(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response @@ -42,10 +44,10 @@ def test_create_zone_wait_handler_fails_for_wrong_id(zone_id:str, project_id:str wait_for_create_zone(api_client, project_id, zone_id) -@pytest.mark.parametrize("zone_id,project_id,expected_api_response", [ - ("zone_id", "project_id", zone_response( - "CREATE_SUCCEEDED", "zone_id")) -]) +@pytest.mark.parametrize( + "zone_id,project_id,expected_api_response", + [("zone_id", "project_id", zone_response("CREATE_SUCCEEDED", "zone_id"))], +) def test_create_zone_wait_handler_retuns_response(zone_id: str, project_id: str, expected_api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = expected_api_response @@ -55,9 +57,9 @@ def test_create_zone_wait_handler_retuns_response(zone_id: str, project_id: str, assert response == expected_api_response -@pytest.mark.parametrize("zone_id,project_id,api_response", [ - ("zone_id", "project_id", zone_response("CREATE_FAILED", "zone_id")) -]) +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("CREATE_FAILED", "zone_id"))] +) def test_create_zone_wait_handler_fails_for_failure(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response @@ -66,12 +68,22 @@ def test_create_zone_wait_handler_fails_for_failure(zone_id: str, project_id: st wait_for_create_zone(api_client, project_id, zone_id) -@pytest.mark.parametrize("zone_id,project_id,api_response", [ - ("zone_id", "project_id", zone_response("CREATING", "zone_id")) -]) -def test_create_zone_wait_handler_waits(zone_id: str, project_id: str, api_response: ZoneResponse): +@pytest.mark.parametrize( + "zone_id,project_id,api_responses", + [ + ( + "zone_id", + "project_id", + [ + zone_response("CREATING", "zone_id"), + zone_response("CREATING", "zone_id"), + zone_response("CREATE_SUCCEEDED", "zone_id"), + ], + ) + ], +) +def test_create_zone_wait_handler_waits(zone_id: str, project_id: str, api_responses: List[ZoneResponse]): api_client = Mock() - api_client.get_zone.return_value = api_response + api_client.get_zone.side_effect = api_responses - with pytest.raises(TimeoutError, match="Wait has timed out"): - wait_for_create_zone(api_client, project_id, zone_id, timeout=1) + assert wait_for_create_zone(api_client, project_id, zone_id) == api_responses[-1] From 6c32affa6dd10744b16d6343eaeca93602a11229 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 08:53:40 +0100 Subject: [PATCH 05/11] zone tests completed --- services/dns/tests/test_wait.py | 124 ++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index cf517e416..9eb1e9af1 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -87,3 +87,127 @@ def test_create_zone_wait_handler_waits(zone_id: str, project_id: str, api_respo api_client.get_zone.side_effect = api_responses assert wait_for_create_zone(api_client, project_id, zone_id) == api_responses[-1] + + +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("UPDATING", "incorrect_zone_id"))] +) +def test_wait_for_partial_update_zone_fails_for_wrong_id(zone_id: str, project_id: str, api_response: ZoneResponse): + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(ValueError, match="ID of zone in return not equal to ID of requested zone."): + wait_for_partial_update_zone(api_client, project_id, zone_id) + + +@pytest.mark.parametrize( + "zone_id,project_id,expected_api_response", + [("zone_id", "project_id", zone_response("UPDATE_SUCCEEDED", "zone_id"))], +) +def test_wait_for_partial_update_zone_handler_retuns_response( + zone_id: str, project_id: str, expected_api_response: ZoneResponse +): + api_client = Mock() + api_client.get_zone.return_value = expected_api_response + + response = wait_for_partial_update_zone(api_client, project_id, zone_id) + + assert response == expected_api_response + + +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [ + ("zone_id", "project_id", zone_response("UPDATE_FAILED", "zone_id"))] +) +def test_wait_for_partial_update_zone_handler_fails_for_failure( + zone_id: str, project_id: str, api_response: ZoneResponse +): + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(Exception, match=f"Update failed for zone with id {zone_id}"): + wait_for_partial_update_zone(api_client, project_id, zone_id) + + +@pytest.mark.parametrize( + "zone_id,project_id,api_responses", + [ + ( + "zone_id", + "project_id", + [ + zone_response("UPDATING", "zone_id"), + zone_response("UPDATING", "zone_id"), + zone_response("UPDATE_SUCCEEDED", "zone_id"), + ], + ) + ], +) +def test_wait_for_partial_update_zone_waits(zone_id: str, project_id: str, api_responses: List[ZoneResponse]): + api_client = Mock() + api_client.get_zone.side_effect = api_responses + + assert wait_for_partial_update_zone(api_client, project_id, zone_id) == api_responses[-1] + + +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [ + ("zone_id", "project_id", zone_response("DELETING", "incorrect_zone_id"))] +) +def test_wait_for_delete_zone_fails_for_wrong_id(zone_id: str, project_id: str, api_response: ZoneResponse): + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(ValueError, match="ID of zone in return not equal to ID of requested zone."): + wait_for_delete_zone(api_client, project_id, zone_id) + + +@pytest.mark.parametrize( + "zone_id,project_id,expected_api_response", + [("zone_id", "project_id", zone_response("DELETE_SUCCEEDED", "zone_id"))], +) +def test_wait_for_delete_zone_handler_retuns_response( + zone_id: str, project_id: str, expected_api_response: ZoneResponse +): + api_client = Mock() + api_client.get_zone.return_value = expected_api_response + + response = wait_for_delete_zone(api_client, project_id, zone_id) + + assert response == expected_api_response + + +@pytest.mark.parametrize( + "zone_id,project_id,api_response", [ + ("zone_id", "project_id", zone_response("DELETE_FAILED", "zone_id"))] +) +def test_wait_for_delete_zone_handler_fails_for_failure( + zone_id: str, project_id: str, api_response: ZoneResponse +): + api_client = Mock() + api_client.get_zone.return_value = api_response + + with pytest.raises(Exception, match=f"Delete failed for zone with id {zone_id}"): + wait_for_delete_zone(api_client, project_id, zone_id) + + +@pytest.mark.parametrize( + "zone_id,project_id,api_responses", + [ + ( + "zone_id", + "project_id", + [ + zone_response("DELETING", "zone_id"), + zone_response("DELETING", "zone_id"), + zone_response("DELETE_SUCCEEDED", "zone_id"), + ], + ) + ], +) +def test_wait_for_delete_zone_zone_waits(zone_id: str, project_id: str, api_responses: List[ZoneResponse]): + api_client = Mock() + api_client.get_zone.side_effect = api_responses + + assert wait_for_delete_zone( + api_client, project_id, zone_id) == api_responses[-1] From 19567b4efde5e11f912951c62a99b42f9e09ff13 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 09:24:43 +0000 Subject: [PATCH 06/11] wip --- services/dns/tests/test_wait.py | 197 ++++++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 11 deletions(-) diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index 9eb1e9af1..41d9922d6 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -5,6 +5,9 @@ from stackit.dns.models.zone import Zone from stackit.dns.models.zone_response import ZoneResponse +from stackit.dns.models.record import Record +from stackit.dns.models.record_set_response import RecordSetResponse +from stackit.dns.models.record_set import RecordSet from stackit.dns.wait import * @@ -33,6 +36,23 @@ def zone_response(state: str, zone_id: str) -> ZoneResponse: ) +def rr_set_response(state: str, rr_set_id: str) -> ZoneResponse: + return RecordSetResponse( + rrset=RecordSet( + creationFinished="creationFinished", + creationStarted="creationStarted", + id=rr_set_id, + name="name", + records=[Record(id="id", content="content")], + state=state, + ttl=60, + type="A", + updateFinished="updateFinished", + updateStarted="updateStarted", + ) + ) + + @pytest.mark.parametrize( "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("CREATING", "incorrect_zone_id"))] ) @@ -116,8 +136,7 @@ def test_wait_for_partial_update_zone_handler_retuns_response( @pytest.mark.parametrize( - "zone_id,project_id,api_response", [ - ("zone_id", "project_id", zone_response("UPDATE_FAILED", "zone_id"))] + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("UPDATE_FAILED", "zone_id"))] ) def test_wait_for_partial_update_zone_handler_fails_for_failure( zone_id: str, project_id: str, api_response: ZoneResponse @@ -151,8 +170,7 @@ def test_wait_for_partial_update_zone_waits(zone_id: str, project_id: str, api_r @pytest.mark.parametrize( - "zone_id,project_id,api_response", [ - ("zone_id", "project_id", zone_response("DELETING", "incorrect_zone_id"))] + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("DELETING", "incorrect_zone_id"))] ) def test_wait_for_delete_zone_fails_for_wrong_id(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() @@ -178,12 +196,9 @@ def test_wait_for_delete_zone_handler_retuns_response( @pytest.mark.parametrize( - "zone_id,project_id,api_response", [ - ("zone_id", "project_id", zone_response("DELETE_FAILED", "zone_id"))] + "zone_id,project_id,api_response", [("zone_id", "project_id", zone_response("DELETE_FAILED", "zone_id"))] ) -def test_wait_for_delete_zone_handler_fails_for_failure( - zone_id: str, project_id: str, api_response: ZoneResponse -): +def test_wait_for_delete_zone_handler_fails_for_failure(zone_id: str, project_id: str, api_response: ZoneResponse): api_client = Mock() api_client.get_zone.return_value = api_response @@ -209,5 +224,165 @@ def test_wait_for_delete_zone_zone_waits(zone_id: str, project_id: str, api_resp api_client = Mock() api_client.get_zone.side_effect = api_responses - assert wait_for_delete_zone( - api_client, project_id, zone_id) == api_responses[-1] + assert wait_for_delete_zone(api_client, project_id, zone_id) == api_responses[-1] + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", rr_set_response("CREATING", "incorrect_rr_set_id"))], +) +def test_wait_for_create_recordset_fails_for_wrong_id( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(ValueError, match="ID of rrset in return not equal to ID of requested rrset."): + wait_for_create_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", rr_set_response("CREATE_FAILED", "rr_set_id"))], +) +def test_wait_for_create_recordset_fails_for_failure( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(Exception, match=f"Create failed for rrset with ID {rr_set_id}"): + wait_for_create_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_responses", + [ + ( + "rr_set_id", + "zone_id", + "project_id", + [ + rr_set_response("CREATING", "rr_set_id"), + rr_set_response("CREATING", "rr_set_id"), + rr_set_response("CREATE_SUCCEEDED", "rr_set_id"), + ], + ) + ], +) +def test_wait_for_create_recordset_waits( + rr_set_id: str, zone_id: str, project_id: str, api_responses: List[RecordSetResponse] +): + api_client = Mock() + api_client.get_record_set.side_effect = api_responses + + assert wait_for_create_recordset(api_client, project_id, zone_id, rr_set_id) == api_responses[-1] + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", rr_set_response("UPDATING", "rr_set_id"))], +) +def test_wait_for_partial_update_recordset_fails_for_wrong_id( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(ValueError, match="ID of rrset in return not equal to ID of requested rrset."): + wait_for_partial_update_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", + rr_set_response("UPDATE_FAILED", "rr_set_id"))], +) +def test_wait_for_partial_update_recordset_fails_for_failure( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(Exception, match=f"Update failed for rrset with id {zone_id}"): + wait_for_partial_update_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_responses", + [ + ( + "rr_set_id", + "zone_id", + "project_id", + [ + rr_set_response("UPDATING", "rr_set_id"), + rr_set_response("UPDATING", "rr_set_id"), + rr_set_response("UPDATE_SUCCEEDED", "rr_set_id"), + ], + ) + ], +) +def test_wait_for_partial_update_recordset_waits( + rr_set_id: str, zone_id: str, project_id: str, api_responses: List[RecordSetResponse] +): + api_client = Mock() + api_client.get_record_set.side_effect = api_responses + + assert wait_for_partial_update_recordset( + api_client, project_id, zone_id, rr_set_id) == api_responses[-1] + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", rr_set_response( + "DELETING", "incorrect_rr_set_id"))], +) +def test_wait_for_delete_recordset_fails_for_wrong_id( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(ValueError, match="ID of rrset in return not equal to ID of requested rrset."): + wait_for_delete_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_response", + [("rr_set_id", "zone_id", "project_id", + rr_set_response("DELETE_FAILED", "rr_set_id"))], +) +def test_wait_for_delete_recordset_fails_for_failure( + rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse +): + api_client = Mock() + api_client.get_record_set.return_value = api_response + + with pytest.raises(Exception, match=f"Delete failed for rrset with id {rr_set_id}"): + wait_for_delete_recordset(api_client, project_id, zone_id, rr_set_id) + + +@pytest.mark.parametrize( + "rr_set_id,zone_id,project_id,api_responses", + [ + ( + "rr_set_id", + "zone_id", + "project_id", + [ + rr_set_response("DELETING", "rr_set_id"), + rr_set_response("DELETING", "rr_set_id"), + rr_set_response("DELETE_SUCCEEDED", "rr_set_id"), + ], + ) + ], +) +def test_wait_for_delete_recordset_waits( + rr_set_id: str, zone_id: str, project_id: str, api_responses: List[RecordSetResponse] +): + api_client = Mock() + api_client.get_record_set.side_effect = api_responses + + assert wait_for_delete_recordset( + api_client, project_id, zone_id, rr_set_id) == api_responses[-1] From fa81d1836384c50834ea49212257525cd3b1615d Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 12:55:26 +0000 Subject: [PATCH 07/11] adds full test for dns wait --- services/dns/pyproject.toml | 2 +- services/dns/src/stackit/dns/wait.py | 18 +++++++-------- services/dns/tests/test_wait.py | 33 ++++++++++++---------------- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/services/dns/pyproject.toml b/services/dns/pyproject.toml index 8a0cd6c60..87548a875 100644 --- a/services/dns/pyproject.toml +++ b/services/dns/pyproject.toml @@ -18,7 +18,7 @@ packages = [ [tool.poetry.dependencies] python = ">=3.8,<4.0" -stackit-core = "^0.0.1a" +stackit-core = "0.0.1a" requests = "^2.32.3" pydantic = "^2.9.2" python-dateutil = "^2.9.0.post0" diff --git a/services/dns/src/stackit/dns/wait.py b/services/dns/src/stackit/dns/wait.py index 5e1c09883..5538b1bf1 100644 --- a/services/dns/src/stackit/dns/wait.py +++ b/services/dns/src/stackit/dns/wait.py @@ -39,7 +39,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N elif response.zone.state == _States.CreateSuccess: return True, None, None, response elif response.zone.state == _States.CreateFail: - return True, Exception("Create failed for zone with id %s" % zone_id), None, response + return True, Exception("Create failed for zone with ID %s" % zone_id), None, response else: return False, None, None, None except ApiException as e: @@ -78,7 +78,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N elif response.zone.state == _States.UpdateSuccess: return True, None, None, response elif response.zone.state == _States.UpdateFail: - return True, Exception("Update failed for zone with id %s" % zone_id), None, response + return True, Exception("Update failed for zone with ID %s" % zone_id), None, response else: return False, None, None, None except ApiException as e: @@ -117,7 +117,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N elif response.zone.state == _States.DeleteSuccess: return True, None, None, response elif response.zone.state == _States.DeleteFail: - return True, Exception("Delete failed for zone with id %s" % zone_id), None, response + return True, Exception("Delete failed for zone with ID %s" % zone_id), None, response else: return False, None, None, None except ApiException as e: @@ -152,12 +152,12 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, try: response = api_client.get_record_set(project_id, zone_id, rr_set_id) - if response.rrset.id != zone_id: + if response.rrset.id != rr_set_id: return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None elif response.rrset.state == _States.CreateSuccess: return True, None, None, response elif response.rrset.state == _States.CreateFail: - return True, Exception("Create failed for rrset with id %s" % rr_set_id), None, response + return True, Exception("Create failed for rrset with ID %s" % rr_set_id), None, response else: return False, None, None, None except ApiException as e: @@ -192,12 +192,12 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, try: response = api_client.get_record_set(project_id, zone_id, rr_set_id) - if response.rrset.id != zone_id: + if response.rrset.id != rr_set_id: return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None elif response.rrset.state == _States.UpdateSuccess: return True, None, None, response elif response.rrset.state == _States.UpdateFail: - return True, Exception("Update failed for rrset with id %s" % rr_set_id), None, response + return True, Exception("Update failed for rrset with ID %s" % rr_set_id), None, response else: return False, None, None, None except ApiException as e: @@ -232,12 +232,12 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, try: response = api_client.get_record_set(project_id, zone_id, rr_set_id) - if response.rrset.id != zone_id: + if response.rrset.id != rr_set_id: return False, ValueError("ID of rrset in return not equal to ID of requested rrset."), None, None elif response.rrset.state == _States.DeleteSuccess: return True, None, None, response elif response.rrset.state == _States.DeleteFail: - return True, Exception("Delete failed for rrset with id %s" % rr_set_id), None, response + return True, Exception("Delete failed for rrset with ID %s" % rr_set_id), None, response else: return False, None, None, None except ApiException as e: diff --git a/services/dns/tests/test_wait.py b/services/dns/tests/test_wait.py index 41d9922d6..8cfc6cac0 100644 --- a/services/dns/tests/test_wait.py +++ b/services/dns/tests/test_wait.py @@ -3,11 +3,11 @@ import pytest -from stackit.dns.models.zone import Zone -from stackit.dns.models.zone_response import ZoneResponse from stackit.dns.models.record import Record -from stackit.dns.models.record_set_response import RecordSetResponse from stackit.dns.models.record_set import RecordSet +from stackit.dns.models.record_set_response import RecordSetResponse +from stackit.dns.models.zone import Zone +from stackit.dns.models.zone_response import ZoneResponse from stackit.dns.wait import * @@ -84,7 +84,7 @@ def test_create_zone_wait_handler_fails_for_failure(zone_id: str, project_id: st api_client = Mock() api_client.get_zone.return_value = api_response - with pytest.raises(Exception, match=f"Create failed for zone with id {zone_id}"): + with pytest.raises(Exception, match=f"Create failed for zone with ID {zone_id}"): wait_for_create_zone(api_client, project_id, zone_id) @@ -144,7 +144,7 @@ def test_wait_for_partial_update_zone_handler_fails_for_failure( api_client = Mock() api_client.get_zone.return_value = api_response - with pytest.raises(Exception, match=f"Update failed for zone with id {zone_id}"): + with pytest.raises(Exception, match=f"Update failed for zone with ID {zone_id}"): wait_for_partial_update_zone(api_client, project_id, zone_id) @@ -202,7 +202,7 @@ def test_wait_for_delete_zone_handler_fails_for_failure(zone_id: str, project_id api_client = Mock() api_client.get_zone.return_value = api_response - with pytest.raises(Exception, match=f"Delete failed for zone with id {zone_id}"): + with pytest.raises(Exception, match=f"Delete failed for zone with ID {zone_id}"): wait_for_delete_zone(api_client, project_id, zone_id) @@ -281,7 +281,7 @@ def test_wait_for_create_recordset_waits( @pytest.mark.parametrize( "rr_set_id,zone_id,project_id,api_response", - [("rr_set_id", "zone_id", "project_id", rr_set_response("UPDATING", "rr_set_id"))], + [("rr_set_id", "zone_id", "project_id", rr_set_response("UPDATING", "incorrect_rr_set_id"))], ) def test_wait_for_partial_update_recordset_fails_for_wrong_id( rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse @@ -295,8 +295,7 @@ def test_wait_for_partial_update_recordset_fails_for_wrong_id( @pytest.mark.parametrize( "rr_set_id,zone_id,project_id,api_response", - [("rr_set_id", "zone_id", "project_id", - rr_set_response("UPDATE_FAILED", "rr_set_id"))], + [("rr_set_id", "zone_id", "project_id", rr_set_response("UPDATE_FAILED", "rr_set_id"))], ) def test_wait_for_partial_update_recordset_fails_for_failure( rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse @@ -304,7 +303,7 @@ def test_wait_for_partial_update_recordset_fails_for_failure( api_client = Mock() api_client.get_record_set.return_value = api_response - with pytest.raises(Exception, match=f"Update failed for rrset with id {zone_id}"): + with pytest.raises(Exception, match=f"Update failed for rrset with ID {rr_set_id}"): wait_for_partial_update_recordset(api_client, project_id, zone_id, rr_set_id) @@ -329,14 +328,12 @@ def test_wait_for_partial_update_recordset_waits( api_client = Mock() api_client.get_record_set.side_effect = api_responses - assert wait_for_partial_update_recordset( - api_client, project_id, zone_id, rr_set_id) == api_responses[-1] + assert wait_for_partial_update_recordset(api_client, project_id, zone_id, rr_set_id) == api_responses[-1] @pytest.mark.parametrize( "rr_set_id,zone_id,project_id,api_response", - [("rr_set_id", "zone_id", "project_id", rr_set_response( - "DELETING", "incorrect_rr_set_id"))], + [("rr_set_id", "zone_id", "project_id", rr_set_response("DELETING", "incorrect_rr_set_id"))], ) def test_wait_for_delete_recordset_fails_for_wrong_id( rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse @@ -350,8 +347,7 @@ def test_wait_for_delete_recordset_fails_for_wrong_id( @pytest.mark.parametrize( "rr_set_id,zone_id,project_id,api_response", - [("rr_set_id", "zone_id", "project_id", - rr_set_response("DELETE_FAILED", "rr_set_id"))], + [("rr_set_id", "zone_id", "project_id", rr_set_response("DELETE_FAILED", "rr_set_id"))], ) def test_wait_for_delete_recordset_fails_for_failure( rr_set_id: str, zone_id: str, project_id: str, api_response: RecordSetResponse @@ -359,7 +355,7 @@ def test_wait_for_delete_recordset_fails_for_failure( api_client = Mock() api_client.get_record_set.return_value = api_response - with pytest.raises(Exception, match=f"Delete failed for rrset with id {rr_set_id}"): + with pytest.raises(Exception, match=f"Delete failed for rrset with ID {rr_set_id}"): wait_for_delete_recordset(api_client, project_id, zone_id, rr_set_id) @@ -384,5 +380,4 @@ def test_wait_for_delete_recordset_waits( api_client = Mock() api_client.get_record_set.side_effect = api_responses - assert wait_for_delete_recordset( - api_client, project_id, zone_id, rr_set_id) == api_responses[-1] + assert wait_for_delete_recordset(api_client, project_id, zone_id, rr_set_id) == api_responses[-1] From 1ab81cdc7af88264be12cd666e3d02ef6d98c301 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 14:08:26 +0100 Subject: [PATCH 08/11] adds example for waiting --- examples/wait/wait_example.py | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 examples/wait/wait_example.py diff --git a/examples/wait/wait_example.py b/examples/wait/wait_example.py new file mode 100644 index 000000000..81e2fe1e6 --- /dev/null +++ b/examples/wait/wait_example.py @@ -0,0 +1,58 @@ +import os + +from stackit.core.configuration import Configuration +from stackit.dns.api.default_api import DefaultApi +from stackit.dns.models.create_record_set_payload import CreateRecordSetPayload +from stackit.dns.models.create_zone_payload import CreateZonePayload +from stackit.dns.models.record_payload import RecordPayload +from stackit.dns.wait import ( + wait_for_create_recordset, + wait_for_create_zone, + wait_for_delete_recordset, + wait_for_delete_zone, +) + +project_id = os.getenv("PROJECT_ID") + +# Create a new API client, that uses default authentication and configuration +config = Configuration() +client = DefaultApi(config) + + +# Create a new DNS zone +create_zone_response = client.create_zone( + create_zone_payload=CreateZonePayload(name="myZone", dnsName="testZone.com"), project_id=project_id +) +zone_id = create_zone_response.zone.id + +# Wait for the zone to be fully created +wait_for_zone_response = wait_for_create_zone(client, project_id, zone_id) + +# Create a DNS record in the newly created DNS zone +create_record_response = client.create_record_set( + project_id, + zone_id, + CreateRecordSetPayload( + name="a", + records=[ + RecordPayload(content="192.168.0.1"), # Will go nowhere + ], + type="A", + ), +) +rr_set_id = create_record_response.rrset.id + +# Wait for the DNS record to be fully created +wait_for_rr_set_record_response = wait_for_create_recordset(client, project_id, zone_id, rr_set_id) + +# delete newly created recordset +delete_rr_set_message = client.delete_record_set(project_id, zone_id, rr_set_id) + +# Wait for rr_set deletion +wait_for_rr_set_deletion_response = wait_for_delete_recordset(client, project_id, zone_id, rr_set_id) + +# Delete newly created DNS zone +delete_zone_message = client.delete_zone(project_id, zone_id) + +# Wait for deletion of DNS zone +wait_for_zone_deletion_response = wait_for_delete_zone(client, project_id, zone_id) From 560bb869661ad6d58c445b18a8b66bd14313c961 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 14:13:07 +0100 Subject: [PATCH 09/11] adjust core version --- services/dns/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/dns/pyproject.toml b/services/dns/pyproject.toml index 87548a875..d85517951 100644 --- a/services/dns/pyproject.toml +++ b/services/dns/pyproject.toml @@ -18,7 +18,7 @@ packages = [ [tool.poetry.dependencies] python = ">=3.8,<4.0" -stackit-core = "0.0.1a" +stackit-core = "0.0.1a1" requests = "^2.32.3" pydantic = "^2.9.2" python-dateutil = "^2.9.0.post0" From 2de317e77910c8abee9e5dcc5b78dc4d08e4c652 Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 15:05:45 +0000 Subject: [PATCH 10/11] adjusted for new wait config in core --- examples/wait/wait_example.py | 5 ++- services/dns/src/stackit/dns/wait.py | 62 ++++++---------------------- 2 files changed, 16 insertions(+), 51 deletions(-) diff --git a/examples/wait/wait_example.py b/examples/wait/wait_example.py index 81e2fe1e6..1ab7bc622 100644 --- a/examples/wait/wait_example.py +++ b/examples/wait/wait_example.py @@ -1,6 +1,7 @@ import os from stackit.core.configuration import Configuration +from stackit.core.wait import WaitConfig from stackit.dns.api.default_api import DefaultApi from stackit.dns.models.create_record_set_payload import CreateRecordSetPayload from stackit.dns.models.create_zone_payload import CreateZonePayload @@ -25,8 +26,8 @@ ) zone_id = create_zone_response.zone.id -# Wait for the zone to be fully created -wait_for_zone_response = wait_for_create_zone(client, project_id, zone_id) +# Wait for the zone to be fully created. You can also adjust the wait configuration parameters +wait_for_zone_response = wait_for_create_zone(client, project_id, zone_id, WaitConfig(sleep_before_wait=5)) # Create a DNS record in the newly created DNS zone create_record_response = client.create_record_set( diff --git a/services/dns/src/stackit/dns/wait.py b/services/dns/src/stackit/dns/wait.py index 5538b1bf1..e44baba7c 100644 --- a/services/dns/src/stackit/dns/wait.py +++ b/services/dns/src/stackit/dns/wait.py @@ -1,7 +1,7 @@ from enum import Enum from typing import Any, Tuple, Union -from stackit.core.wait import Wait +from stackit.core.wait import Wait, WaitConfig from stackit.dns.api.default_api import DefaultApi from stackit.dns.exceptions import ApiException @@ -22,10 +22,7 @@ def wait_for_create_zone( api_client: DefaultApi, project_id: str, zone_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> ZoneResponse: def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -49,10 +46,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N wait = Wait( get_zone_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() @@ -61,10 +55,7 @@ def wait_for_partial_update_zone( api_client: DefaultApi, project_id: str, zone_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> ZoneResponse: def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -88,10 +79,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N wait = Wait( get_zone_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() @@ -100,10 +88,7 @@ def wait_for_delete_zone( api_client: DefaultApi, project_id: str, zone_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> ZoneResponse: def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -127,10 +112,7 @@ def get_zone_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, N wait = Wait( get_zone_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() @@ -140,10 +122,7 @@ def wait_for_create_recordset( project_id: str, zone_id: str, rr_set_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> RecordSetResponse: def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -167,10 +146,7 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, wait = Wait( get_rr_set_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() @@ -180,10 +156,7 @@ def wait_for_partial_update_recordset( project_id: str, zone_id: str, rr_set_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> RecordSetResponse: def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -207,10 +180,7 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, wait = Wait( get_rr_set_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() @@ -220,10 +190,7 @@ def wait_for_delete_recordset( project_id: str, zone_id: str, rr_set_id: str, - sleep_before_wait: int = 0, - throttle: int = 5, - timeout: int = 30, - temp_error_retry_limit: int = 5, + wait_config: Union[WaitConfig, None] = None, ) -> RecordSetResponse: def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, None], Any]: @@ -247,9 +214,6 @@ def get_rr_set_execute_state() -> Tuple[bool, Union[Exception, None], Union[int, wait = Wait( get_rr_set_execute_state, - sleep_before_wait=sleep_before_wait, - throttle=throttle, - timeout=timeout, - temp_error_retry_limit=temp_error_retry_limit, + config=wait_config, ) return wait.wait() From 997f1ddea2de80cb67b764f99ce4d62aa72e9e5d Mon Sep 17 00:00:00 2001 From: Melvin Klein Date: Thu, 31 Oct 2024 15:28:35 +0000 Subject: [PATCH 11/11] adjust example --- examples/wait/wait_example.py | 67 ++++++++++++++++------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/examples/wait/wait_example.py b/examples/wait/wait_example.py index 1ab7bc622..bc7b10988 100644 --- a/examples/wait/wait_example.py +++ b/examples/wait/wait_example.py @@ -1,17 +1,11 @@ import os +from http import HTTPStatus from stackit.core.configuration import Configuration from stackit.core.wait import WaitConfig from stackit.dns.api.default_api import DefaultApi -from stackit.dns.models.create_record_set_payload import CreateRecordSetPayload from stackit.dns.models.create_zone_payload import CreateZonePayload -from stackit.dns.models.record_payload import RecordPayload -from stackit.dns.wait import ( - wait_for_create_recordset, - wait_for_create_zone, - wait_for_delete_recordset, - wait_for_delete_zone, -) +from stackit.dns.wait import wait_for_create_zone project_id = os.getenv("PROJECT_ID") @@ -24,36 +18,35 @@ create_zone_response = client.create_zone( create_zone_payload=CreateZonePayload(name="myZone", dnsName="testZone.com"), project_id=project_id ) -zone_id = create_zone_response.zone.id - -# Wait for the zone to be fully created. You can also adjust the wait configuration parameters -wait_for_zone_response = wait_for_create_zone(client, project_id, zone_id, WaitConfig(sleep_before_wait=5)) - -# Create a DNS record in the newly created DNS zone -create_record_response = client.create_record_set( +zone1_id = create_zone_response.zone.id +zone2_id = client.create_zone( + create_zone_payload=CreateZonePayload(name="myZone2", dnsName="testZone2.com"), project_id=project_id +).zone.id +zone3_id = client.create_zone( + create_zone_payload=CreateZonePayload(name="myZone3", dnsName="testZone3.com"), project_id=project_id +).zone.id + +# Wait for the zone to be fully created. +wait_for_zone_response = wait_for_create_zone(client, project_id, zone1_id) + +# Optionally the wait configuration can be adjusted. It's possible to adjust just one of the parameters.... +wait_for_zone_response = wait_for_create_zone(client, project_id, zone2_id, WaitConfig(sleep_before_wait=5)) + +# ... or all of them +wait_for_zone_response = wait_for_create_zone( + client, project_id, - zone_id, - CreateRecordSetPayload( - name="a", - records=[ - RecordPayload(content="192.168.0.1"), # Will go nowhere - ], - type="A", + zone3_id, + WaitConfig( + sleep_before_wait=6, + throttle=10, + timeout=10, + temp_error_retry_limit=10, + retry_http_error_status_codes=[HTTPStatus.BAD_GATEWAY, HTTPStatus.GATEWAY_TIMEOUT], ), ) -rr_set_id = create_record_response.rrset.id - -# Wait for the DNS record to be fully created -wait_for_rr_set_record_response = wait_for_create_recordset(client, project_id, zone_id, rr_set_id) - -# delete newly created recordset -delete_rr_set_message = client.delete_record_set(project_id, zone_id, rr_set_id) - -# Wait for rr_set deletion -wait_for_rr_set_deletion_response = wait_for_delete_recordset(client, project_id, zone_id, rr_set_id) - -# Delete newly created DNS zone -delete_zone_message = client.delete_zone(project_id, zone_id) -# Wait for deletion of DNS zone -wait_for_zone_deletion_response = wait_for_delete_zone(client, project_id, zone_id) +# Delete all of the zones again +delete_zone_message = client.delete_zone(project_id, zone1_id) +delete_zone_message = client.delete_zone(project_id, zone2_id) +delete_zone_message = client.delete_zone(project_id, zone3_id)