diff --git a/libcloud/dns/drivers/linode.py b/libcloud/dns/drivers/linode.py index 5639a14a46..46429fac90 100644 --- a/libcloud/dns/drivers/linode.py +++ b/libcloud/dns/drivers/linode.py @@ -35,6 +35,7 @@ VALID_ZONE_EXTRA_PARAMS_V4 = [ + "axfr_ips", "description", "expire_sec", "master_ips", @@ -100,6 +101,7 @@ class LinodeDNSDriverV4(LinodeDNSDriver): RecordType.A: "A", RecordType.AAAA: "AAAA", RecordType.CNAME: "CNAME", + RecordType.PTR: "PTR", RecordType.TXT: "TXT", RecordType.SRV: "SRV", RecordType.CAA: "CAA", @@ -174,7 +176,7 @@ def create_zone(self, domain, type="master", ttl=None, extra=None): :keyword ttl: TTL for new records. (optional) :type ttl: ``int`` - :keyword extra: Extra attributes.('description', 'expire_sec', \ + :keyword extra: Extra attributes.('axfr_ips', 'description', 'expire_sec', \ 'master_ips','refresh_sec', 'retry_sec', 'soa_email',\ 'status', 'tags'). 'soa_email' required for master zones :type extra: ``dict`` @@ -250,7 +252,7 @@ def update_zone(self, zone, domain, type="master", ttl=None, extra=None): :param ttl: TTL for new records. (optional) :type ttl: ``int`` - :param extra: Extra attributes ('description', 'expire_sec', \ + :param extra: Extra attributes ('axfr_ips', 'description', 'expire_sec', \ 'master_ips','refresh_sec', 'retry_sec', 'soa_email','status', 'tags') :type extra: ``dict`` @@ -367,6 +369,7 @@ def _to_record(self, item, zone=None): "priority": item["priority"], "service": item["service"], "protocol": item["protocol"], + "tag": item["tag"], "created": self._to_datetime(item["created"]), "updated": self._to_datetime(item["updated"]), } diff --git a/libcloud/test/compute/fixtures/linode_v4/get_node_billing_suspension.json b/libcloud/test/compute/fixtures/linode_v4/get_node_billing_suspension.json new file mode 100644 index 0000000000..475287913a --- /dev/null +++ b/libcloud/test/compute/fixtures/linode_v4/get_node_billing_suspension.json @@ -0,0 +1,42 @@ +{ + "id": 22344420, + "label": "test_2", + "group": "", + "status": "billing_suspension", + "created": "2020-12-07T14:58:19", + "updated": "2020-12-07T14:58:19", + "type": "g6-nanode-1", + "ipv4": [ + "212.71.239.24" + ], + "ipv6": "2a01:7e00::f03c:92ff:fe48:dc47/64", + "image": "linode/centos8", + "region": "eu-west", + "specs": { + "disk": 25600, + "memory": 1024, + "vcpus": 1, + "gpus": 0, + "transfer": 1000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "testing" + ] +} diff --git a/libcloud/test/compute/fixtures/linode_v4/list_nodes_extra_fields.json b/libcloud/test/compute/fixtures/linode_v4/list_nodes_extra_fields.json new file mode 100644 index 0000000000..5f65ce362f --- /dev/null +++ b/libcloud/test/compute/fixtures/linode_v4/list_nodes_extra_fields.json @@ -0,0 +1,49 @@ +{ + "data": [ + { + "id": 22344420, + "label": "test_2", + "group": "", + "status": "busy", + "created": "2020-10-08T18:51:29", + "updated": "2020-10-08T18:51:29", + "type": "g6-nanode-1", + "ipv4": ["138.89.34.81", "192.168.1.230"], + "ipv6": "2a01:7e00::f03c:92ff:fe48:dc47/64", + "image": "linode/centos7", + "region": "eu-west", + "specs": { + "disk": 25600, + "memory": 1024, + "vcpus": 1, + "gpus": 0, + "transfer": 1000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": {"day": null, "window": null}, + "last_successful": null + }, + "capabilities": ["Block Storage Encryption"], + "disk_encryption": "enabled", + "has_user_data": true, + "hypervisor": "kvm", + "host_uuid": "3a3ddd59d9a78bb8de041391075df44de62bfec8", + "interface_generation": "linode", + "maintenance_policy": "linode/migrate", + "placement_group": {"id": 528, "label": "pg-1"}, + "watchdog_enabled": true, + "tags": ["testing"] + } + ], + "page": 1, + "pages": 1, + "results": 1 +} diff --git a/libcloud/test/dns/fixtures/linode_v4/create_record_ptr.json b/libcloud/test/dns/fixtures/linode_v4/create_record_ptr.json new file mode 100644 index 0000000000..23f63d2905 --- /dev/null +++ b/libcloud/test/dns/fixtures/linode_v4/create_record_ptr.json @@ -0,0 +1,15 @@ +{ + "id": 123, + "type": "PTR", + "name": "10", + "target": "host.example.com", + "priority": 0, + "weight": 0, + "port": 0, + "service": null, + "protocol": null, + "ttl_sec": 300, + "tag": null, + "created": "2020-10-16T07:57:37", + "updated": "2020-10-16T07:57:37" +} diff --git a/libcloud/test/dns/fixtures/linode_v4/create_zone_axfr_ips.json b/libcloud/test/dns/fixtures/linode_v4/create_zone_axfr_ips.json new file mode 100644 index 0000000000..8e55554cdc --- /dev/null +++ b/libcloud/test/dns/fixtures/linode_v4/create_zone_axfr_ips.json @@ -0,0 +1,21 @@ +{ + "id": 123, + "type": "master", + "domain": "example.com", + "tags": [], + "group": "", + "status": "active", + "description": "", + "soa_email": "admin@example.com", + "retry_sec": 0, + "master_ips": [], + "axfr_ips": [ + "192.0.2.10", + "198.51.100.11" + ], + "expire_sec": 0, + "refresh_sec": 0, + "ttl_sec": 300, + "created": "2020-10-16T09:08:50", + "updated": "2020-10-16T09:08:50" +} diff --git a/libcloud/test/dns/test_linode_v4.py b/libcloud/test/dns/test_linode_v4.py index df20b360ae..476c876cfa 100644 --- a/libcloud/test/dns/test_linode_v4.py +++ b/libcloud/test/dns/test_linode_v4.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and import sys +import json import unittest from libcloud.test import MockHttp @@ -81,6 +82,12 @@ def test_get_record_MX_RECORD(self): self.assertEqual(record.data, "mail.example.com") self.assertEqual(record.type, "MX") + def test_list_records_preserves_CAA_tag(self): + zone = self.driver.list_zones()[0] + records = self.driver.list_records(zone) + caa_record = next(record for record in records if record.type == RecordType.CAA) + self.assertEqual(caa_record.extra["tag"], "issue") + def test_create_zone(self): domain = "example.com" ttl = 300 @@ -90,6 +97,17 @@ def test_create_zone(self): self.assertEqual(zone.domain, "example.com") self.assertEqual(zone.extra["soa_email"], "admin@example.com") + def test_create_zone_accepts_axfr_ips(self): + LinodeMockHttpV4.type = "CREATE_ZONE_AXFR_IPS" + domain = "example.com" + ttl = 300 + extra = { + "soa_email": "admin@example.com", + "axfr_ips": ["192.0.2.10", "198.51.100.11"], + } + zone = self.driver.create_zone(domain=domain, ttl=ttl, extra=extra) + self.assertEqual(zone.extra["axfr_ips"], extra["axfr_ips"]) + def test_create_record(self): zone = self.driver.list_zones()[0] name = "test" @@ -101,6 +119,13 @@ def test_create_record(self): self.assertEqual(record.type, "A") self.assertEqual(record.data, data) + def test_create_record_PTR_RECORD(self): + zone = self.driver.list_zones()[0] + LinodeMockHttpV4.type = "PTR_RECORD" + record = self.driver.create_record("10", zone, RecordType.PTR, "host.example.com") + self.assertEqual(record.type, "PTR") + self.assertEqual(record.data, "host.example.com") + def test_update_zone(self): zone = self.driver.list_zones()[0] domain = "example.com" @@ -144,6 +169,12 @@ def _v4_domains(self, method, url, body, headers): body = self.fixtures.load("create_zone.json") return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v4_domains_CREATE_ZONE_AXFR_IPS(self, method, url, body, headers): + payload = json.loads(body) + self.assertEqual(payload["axfr_ips"], ["192.0.2.10", "198.51.100.11"]) + body = self.fixtures.load("create_zone_axfr_ips.json") + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v4_domains_123_records(self, method, url, body, headers): if method == "GET": body = self.fixtures.load("list_records.json") @@ -152,6 +183,13 @@ def _v4_domains_123_records(self, method, url, body, headers): body = self.fixtures.load("create_record.json") return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v4_domains_123_records_PTR_RECORD(self, method, url, body, headers): + payload = json.loads(body) + self.assertEqual(payload["type"], "PTR") + self.assertEqual(payload["target"], "host.example.com") + body = self.fixtures.load("create_record_ptr.json") + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v4_domains_123(self, method, url, body, headers): if method == "GET": body = self.fixtures.load("get_zone.json")