diff --git a/octodns_scaleway/__init__.py b/octodns_scaleway/__init__.py index d85aa3a..60b6abf 100644 --- a/octodns_scaleway/__init__.py +++ b/octodns_scaleway/__init__.py @@ -123,6 +123,7 @@ def dnssec_disable(self, domain): class ScalewayProvider(BaseProvider): SUPPORTS_GEO = False SUPPORTS_DYNAMIC = True + SUPPORTS_ROOT_NS = True SUPPORTS_POOL_VALUE_STATUS = False SUPPORTS = set((['A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'DNAME', 'DS', 'LOC', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF', @@ -695,7 +696,7 @@ def _params_dynamic(self, record): pools = record.dynamic.pools rules = record.dynamic.rules - healthcheck = record._octodns.get('healthcheck', {}) + healthcheck = record.octodns.get('healthcheck', {}) n = 0 for pool in pools: diff --git a/tests/fixtures/scaleway-domain-ok.json b/tests/fixtures/scaleway-domain-ok.json new file mode 100644 index 0000000..4501dc6 --- /dev/null +++ b/tests/fixtures/scaleway-domain-ok.json @@ -0,0 +1,166 @@ +{ + "domain": "unit.tests", + "organization_id": "", + "project_id": "", + "auto_renew_status": "enabled", + "dnssec": { + "status": "disabled", + "ds_records": [] + }, + "epp_code": [ + "clientTransferProhibited" + ], + "expired_at": "2025-07-24T22:16:38Z", + "updated_at": "2024-09-04T14:42:50Z", + "registrar": "SCALEWAY", + "is_external": false, + "status": "active", + "dns_zones": [ + { + "domain": "unit.tests", + "subdomain": "", + "ns": [ + "ns0.dom.scw.cloud.", + "ns1.dom.scw.cloud." + ], + "ns_default": [ + "ns0.dom.scw.cloud", + "ns1.dom.scw.cloud" + ], + "ns_master": [], + "status": "active", + "message": null, + "updated_at": "2024-04-15T22:13:34Z", + "project_id": "", + "linked_products": [] + } + ], + "owner_contact": { + "id": "", + "legal_form": "individual", + "firstname": "Test", + "lastname": "Test", + "company_name": "", + "email": "localhost@domain", + "email_alt": "", + "phone_number": "+33.000000000", + "fax_number": "", + "address_line_1": "", + "address_line_2": "", + "zip": "", + "city": "", + "state": "", + "country": "", + "vat_identification_code": "", + "company_identification_code": "", + "lang": "", + "resale": false, + "questions": [], + "extension_fr": { + "mode": "individual", + "individual_info": { + "whois_opt_in": false + } + }, + "extension_eu": null, + "extension_nl": null, + "whois_opt_in": false, + "email_status": "validated", + "status": "status_unknown" + }, + "technical_contact": { + "id": "", + "legal_form": "legal_form_unknown", + "firstname": "", + "lastname": "", + "company_name": "", + "email": "", + "email_alt": "", + "phone_number": "", + "fax_number": "", + "address_line_1": "", + "address_line_2": "", + "zip": "", + "city": "", + "state": "", + "country": "", + "vat_identification_code": "", + "company_identification_code": "", + "lang": "unknown_language_code", + "resale": false, + "questions": [], + "extension_fr": { + "mode": "mode_unknown" + }, + "extension_eu": null, + "extension_nl": null, + "whois_opt_in": false, + "email_status": "email_status_unknown", + "status": "status_unknown" + }, + "administrative_contact": { + "id": "", + "legal_form": "legal_form_unknown", + "firstname": "", + "lastname": "", + "company_name": "", + "email": "", + "email_alt": "", + "phone_number": "", + "fax_number": "", + "address_line_1": "", + "address_line_2": "", + "zip": "", + "city": "", + "state": "", + "country": "", + "vat_identification_code": "", + "company_identification_code": "", + "lang": "unknown_language_code", + "resale": false, + "questions": [], + "extension_fr": { + "mode": "mode_unknown" + }, + "extension_eu": null, + "extension_nl": null, + "whois_opt_in": false, + "email_status": "email_status_unknown", + "status": "status_unknown" + }, + "tld": { + "name": "tests", + "dnssec_support": true, + "duration_in_years_min": 1, + "duration_in_years_max": 9, + "idn_support": false, + "offers": { + "renew": { + "action": "renew", + "operation_path": "/network/domain/domains/tests/renew", + "price": { + "currency_code": "EUR", + "units": 6, + "nanos": 590000000 + } + }, + "trade": { + "action": "trade", + "operation_path": "/network/domain/domains/tests/trade", + "price": { + "currency_code": "EUR", + "units": 20, + "nanos": 0 + } + } + }, + "specifications": { + "afnic": "1", + "grace_period": "1", + "owner_infos_fr": "1", + "transfer_without_contact": "1" + } + }, + "linked_products": [], + "pending_trade": false +} \ No newline at end of file diff --git a/tests/fixtures/scaleway-ok.json b/tests/fixtures/scaleway-ok.json index bb3d77e..322ce20 100644 --- a/tests/fixtures/scaleway-ok.json +++ b/tests/fixtures/scaleway-ok.json @@ -214,7 +214,7 @@ "data": "3-scaleway.com." } ], - "default": "" + "default": "1-scaleway.com." } }, { @@ -254,7 +254,7 @@ ], "must_contain": null, "url": "HTTPS://scaleway.com:443/check", - "user_agent": "scaleway-octodns/0.0.4", + "user_agent": "scaleway-octodns/0.1.0", "strategy": "all" } } diff --git a/tests/test_provider_octodns_scaleway.py b/tests/test_provider_octodns_scaleway.py index 86e4c52..f71f629 100644 --- a/tests/test_provider_octodns_scaleway.py +++ b/tests/test_provider_octodns_scaleway.py @@ -94,6 +94,11 @@ class TestScalewayProvider(TestCase): 'type': 'ALIAS', 'value': 'alias.unit.tests.' }), + ('', { + 'ttl': 600, + 'type': 'NS', + 'value': ['ns0.dom.scw.cloud.', 'ns1.dom.scw.cloud.'] + }), ('_srv._tcp2', { 'ttl': 1800, 'type': 'SRV', @@ -179,7 +184,8 @@ class TestScalewayProvider(TestCase): { 'pool': 'pool-0', 'geos': ['EU'] - } + }, + {'pool': 'pool-0'}, ] } }), @@ -303,6 +309,10 @@ def test_populate(self): mock.get('/domain/v2beta1/dns-zones/' 'unit.tests/records?page_size=1000', text=fh.read()) + with open('tests/fixtures/scaleway-domain-ok.json') as fh: + mock.get('/domain/v2beta1/domains/' + 'unit.tests', text=fh.read()) + zone = Zone('unit.tests.', []) provider.populate(zone) @@ -325,6 +335,10 @@ def test_populate(self): with open('tests/fixtures/scaleway-nok.json') as fh: mock.get(ANY, text=fh.read()) + with open('tests/fixtures/scaleway-domain-ok.json') as fh: + mock.get('/domain/v2beta1/domains/' + 'unit.tests', text=fh.read()) + zone = Zone('unit.tests.', []) provider.populate(zone, lenient=True) self.assertEqual(set([ @@ -367,6 +381,8 @@ def test_apply(self): mock.get('/domain/v2beta1/dns-zones/unit.not-exists' '/records?page_size=1000', status_code=403) + mock.get('/domain/v2beta1/domains/unit.not-exists', + status_code=403) mock.patch('/domain/v2beta1/dns-zones/' 'unit.not-exists/records', status_code=403, text='{"message": "domain not found"}') @@ -390,6 +406,13 @@ def test_apply(self): provider = ScalewayProvider('test', 'token', True) zone_dynamic = Zone('unit.dynamic.', []) + with open('tests/fixtures/scaleway-nok.json') as fh: + mock.get('/domain/v2beta1/dns-zones/unit.dynamic' + '/records?page_size=1000', text=fh.read()) + with open('tests/fixtures/scaleway-domain-ok.json') as fh: + mock.get('/domain/v2beta1/domains/unit.dynamic', + text=fh.read()) + zone_dynamic.add_record(Record.new(zone_dynamic, 'dynamic', { 'ttl': 300, 'type': 'A', @@ -426,7 +449,7 @@ def test_apply(self): 'rules': [{ 'pool': 'pool-0', 'geos': ['NA-US-KY'] - }] + }, {'pool': 'pool-0'}] } }), replace=True) @@ -454,10 +477,15 @@ def test_apply(self): ], }, }, - 'rules': [{ - 'pool': 'pool-0', - 'geos': ['NA-US'] - }] + 'rules': [ + { + 'pool': 'pool-0', + 'geos': ['NA-US'] + }, + { + 'pool': 'pool-0' + } + ] } }), replace=True) @@ -521,6 +549,7 @@ def test_apply(self): provider._client._request.assert_has_calls([ # created some of the record with expected data call('GET', '/dns-zones/unit.tests/records?page_size=1000'), + call('GET', '/domains/unit.tests'), call('PATCH', '/dns-zones/unit.tests/records', data={ 'return_all_records': False, 'disallow_new_zone_creation': True, @@ -537,6 +566,24 @@ def test_apply(self): ] } }, + { + 'add': { + 'records': [ + { + 'name': '@', + 'ttl': 600, + 'type': 'NS', + 'data': 'ns0.dom.scw.cloud.' + }, + { + 'name': '@', + 'ttl': 600, + 'type': 'NS', + 'data': 'ns1.dom.scw.cloud.' + } + ] + } + }, { 'add': { 'records': [ @@ -601,7 +648,8 @@ def test_apply(self): 'countries': [], 'data': '2.2.2.3' } - ] + ], + 'default': '2.2.2.2' } } ] @@ -643,7 +691,7 @@ def test_apply(self): 'ips': ['2.2.2.2', '2.2.2.3'], 'must_contain': None, 'url': 'HTTPS://127.0.0.1:443/check', - 'user_agent': 'scaleway-octodns/0.0.4', + 'user_agent': 'scaleway-octodns/0.1.0', 'strategy': 'all' } } @@ -754,7 +802,7 @@ def test_apply(self): }), ]) # expected number of total calls - self.assertEqual(2, provider._client._request.call_count) + self.assertEqual(3, provider._client._request.call_count) provider._client._request.reset_mock() @@ -779,6 +827,8 @@ def test_apply(self): 'type': 'A', } ]) + provider._client.zone_ds_records = Mock(return_value=[]) + # Domain exists, we don't care about return resp.json.side_effect = ['{}'] @@ -799,6 +849,14 @@ def test_apply(self): 'return_all_records': False, 'disallow_new_zone_creation': True, 'changes': [ + { + 'delete': { + 'idFields': { + 'type': 'A', + 'name': 'www' + } + } + }, { 'set': { 'idFields': { @@ -814,15 +872,7 @@ def test_apply(self): } ] } - }, - { - 'delete': { - 'idFields': { - 'type': 'A', - 'name': 'www' - } - } } ] }) - ], any_order=True) + ])