diff --git a/hcloud/zones/client.py b/hcloud/zones/client.py index 832d76f7..b3346042 100644 --- a/hcloud/zones/client.py +++ b/hcloud/zones/client.py @@ -359,6 +359,21 @@ def add_rrset_records( """ return self._client.add_rrset_records(rrset=rrset, records=records, ttl=ttl) + def update_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Updates records in a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-update-records-to-an-rrset + + :param rrset: RRSet to update. + :param records: Records to update in the RRSet. + """ + return self._client.update_rrset_records(rrset=rrset, records=records) + def remove_rrset_records( self, rrset: ZoneRRSet | BoundZoneRRSet, @@ -479,6 +494,19 @@ def add_rrset_records( """ return self._client.add_rrset_records(self, records=records, ttl=ttl) + def update_rrset_records( + self, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Updates records in a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-update-records-to-an-rrset + + :param records: Records to update in the RRSet. + """ + return self._client.update_rrset_records(self, records=records) + def remove_rrset_records( self, records: list[ZoneRecord], @@ -1172,6 +1200,33 @@ def add_rrset_records( ) return BoundAction(self._parent.actions, response["action"]) + def update_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Updates records in a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-update-records-to-an-rrset + + :param rrset: RRSet to update. + :param records: Records to update in the RRSet. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = { + "records": [o.to_payload() for o in records], + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/update_records", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + def remove_rrset_records( self, rrset: ZoneRRSet | BoundZoneRRSet, diff --git a/tests/unit/zones/test_client.py b/tests/unit/zones/test_client.py index 2e966032..a2f7d7c7 100644 --- a/tests/unit/zones/test_client.py +++ b/tests/unit/zones/test_client.py @@ -752,6 +752,55 @@ def test_add_rrset_records( assert_bound_action1(action, resource_client._parent.actions) + @pytest.mark.parametrize( + "zone", + [ + Zone(name="example.com"), + BoundZone(client=mock.MagicMock(), data={"id": 42}), + ], + ) + @pytest.mark.parametrize( + "rrset", + [ + ZoneRRSet(name="www", type="A"), + BoundZoneRRSet(client=mock.MagicMock(), data={"id": "www/A"}), + ], + ) + def test_update_rrset_records( + self, + request_mock: mock.MagicMock, + resource_client: ZonesClient, + zone: Zone, + rrset: ZoneRRSet, + action_response, + ): + rrset.zone = zone + + request_mock.return_value = action_response + + action = resource_client.update_rrset_records( + rrset, + records=[ + ZoneRecord("198.51.100.1", "web server"), + ZoneRecord("198.51.100.2", ""), + ZoneRecord("127.0.0.1"), + ], + ) + + request_mock.assert_called_with( + method="POST", + url=f"/zones/{zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/update_records", + json={ + "records": [ + {"value": "198.51.100.1", "comment": "web server"}, + {"value": "198.51.100.2", "comment": ""}, + {"value": "127.0.0.1"}, + ], + }, + ) + + assert_bound_action1(action, resource_client._parent.actions) + @pytest.mark.parametrize( "zone", [ @@ -866,6 +915,7 @@ class TestBoundZone(BoundModelTestCase): (BoundZone.change_rrset_protection, {"sub_resource": True}), (BoundZone.change_rrset_ttl, {"sub_resource": True}), (BoundZone.add_rrset_records, {"sub_resource": True}), + (BoundZone.update_rrset_records, {"sub_resource": True}), (BoundZone.remove_rrset_records, {"sub_resource": True}), (BoundZone.set_rrset_records, {"sub_resource": True}), ] @@ -927,6 +977,7 @@ class TestBoundZoneRRSet(BoundModelTestCase): BoundZoneRRSet.change_rrset_protection, BoundZoneRRSet.change_rrset_ttl, BoundZoneRRSet.add_rrset_records, + BoundZoneRRSet.update_rrset_records, BoundZoneRRSet.remove_rrset_records, BoundZoneRRSet.set_rrset_records, ]