diff --git a/CHANGES.rst b/CHANGES.rst index bb97fad82f..fc0f067174 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -115,6 +115,13 @@ Storage ``2012-02-12`` to ``2014-02-14'``. (LIBCLOUD-851, GITHUB-1202, GITHUB-1294) [Clemens Wolff - @c-w, Davis Kirkendall - @daviskirk] +DNS +~~~ + +- [Cloudflare] Re-write the Cloudflare DNS driver to use Cloudflare API v4. + (LIBCLOUD-1001, LIBCLOUD-994, GITHUB-1292) + [Clemens Wolff - @c-w] + Changes in Apache Libcloud 2.5.0 -------------------------------- diff --git a/docs/dns/_supported_methods.rst b/docs/dns/_supported_methods.rst index 8f2bbe10d1..76d7e7fc3b 100644 --- a/docs/dns/_supported_methods.rst +++ b/docs/dns/_supported_methods.rst @@ -5,7 +5,7 @@ Provider list zones list records create zone update zone create recor =================== ========== ============ =========== =========== ============= ============= =========== ============= `AuroraDNS`_ yes yes yes no yes yes yes yes `BuddyNS DNS`_ yes no yes no no no yes no -`CloudFlare DNS`_ yes yes no no yes yes no yes +`CloudFlare DNS`_ yes yes yes yes yes yes yes yes `DigitalOcean`_ yes yes yes no yes yes yes yes `DNSimple`_ yes yes yes no yes yes yes yes `DurableDNS`_ yes yes yes yes yes yes yes yes diff --git a/docs/dns/drivers/cloudflare.rst b/docs/dns/drivers/cloudflare.rst index f62c72d64e..b55951e6eb 100644 --- a/docs/dns/drivers/cloudflare.rst +++ b/docs/dns/drivers/cloudflare.rst @@ -27,4 +27,4 @@ API Docs :inherited-members: .. _`CloudFlare`: https://www.cloudflare.com/ -.. _`account page`: https://www.cloudflare.com/my-account.html +.. _`account page`: https://dash.cloudflare.com/profile diff --git a/libcloud/dns/drivers/cloudflare.py b/libcloud/dns/drivers/cloudflare.py index 7d1e03549d..b10d3e6026 100644 --- a/libcloud/dns/drivers/cloudflare.py +++ b/libcloud/dns/drivers/cloudflare.py @@ -17,85 +17,112 @@ 'CloudFlareDNSDriver' ] -import copy +import itertools +import json from libcloud.common.base import JsonResponse, ConnectionUserAndKey from libcloud.common.types import InvalidCredsError, LibcloudError -from libcloud.utils.py3 import httplib from libcloud.dns.base import DNSDriver, Zone, Record from libcloud.dns.types import Provider, RecordType -from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError - -API_URL = 'https://www.cloudflare.com/api_json.html' -API_HOST = 'www.cloudflare.com' -API_PATH = '/api_json.html' - -ZONE_EXTRA_ATTRIBUTES = [ - 'display_name', - 'zone_status', - 'zone_type', - 'host_id', - 'host_pubname', - 'host_website', - 'fqdns', - 'vtxt', - 'step', - 'zone_status_class', - 'zone_status_desc', - 'orig_registrar', - 'orig_dnshost', - 'orig_ns_names' -] - -RECORD_EXTRA_ATTRIBUTES = [ - 'rec_tag', - 'display_name', - 'pro', - 'display_content', - 'ttl_ceil', - 'ssl_id', - 'ssl_status', - 'ssl_expires_on', - 'auto_ttl', - 'service_mode' -] +from libcloud.dns.types import RecordAlreadyExistsError, ZoneAlreadyExistsError +from libcloud.dns.types import RecordDoesNotExistError, ZoneDoesNotExistError +from libcloud.utils.misc import merge_valid_keys, reverse_dict + +API_HOST = 'api.cloudflare.com' +API_BASE = '/client/v4' + +CLOUDFLARE_TO_LIBCLOUD_ZONE_TYPE = { + 'full': 'master', + 'partial': 'slave', +} + +LIBCLOUD_TO_CLOUDFLARE_ZONE_TYPE = reverse_dict( + CLOUDFLARE_TO_LIBCLOUD_ZONE_TYPE) + +ZONE_EXTRA_ATTRIBUTES = { + 'development_mode', + 'original_name_servers', + 'original_registrar', + 'original_dnshost', + 'created_on', + 'modified_on', + 'activated_on', + 'owner', + 'account', + 'permissions', + 'plan', + 'plan_pending', + 'status', + 'paused', + 'name_servers', +} + +ZONE_UPDATE_ATTRIBUTES = { + 'paused', + 'vanity_name_servers', + 'plan', +} + +ZONE_CREATE_ATTRIBUTES = { + 'jump_start', +} + +RECORD_EXTRA_ATTRIBUTES = { + 'proxiable', + 'proxied', + 'locked', + 'created_on', + 'modified_on', + 'data', +} + +RECORD_CREATE_ATTRIBUTES = { + 'ttl', + 'priority', + 'proxied', +} + +RECORD_UPDATE_ATTRIBUTES = { + 'ttl', + 'proxied', +} class CloudFlareDNSResponse(JsonResponse): + exceptions = { + 9103: (InvalidCredsError, []), + 1001: (ZoneDoesNotExistError, ['zone_id']), + 1061: (ZoneAlreadyExistsError, ['zone_id']), + 1002: (RecordDoesNotExistError, ['record_id']), + 81053: (RecordAlreadyExistsError, ['record_id']), + } + def success(self): - return self.status in [httplib.OK, httplib.CREATED, httplib.ACCEPTED] + body = self.parse_body() + + is_success = body.get('success', False) + + return is_success - def parse_body(self): - body = super(CloudFlareDNSResponse, self).parse_body() - body = body or {} + def parse_error(self): + body = self.parse_body() - result = body.get('result', None) - error_code = body.get('err_code', None) - msg = body.get('msg', None) - is_error_result = result == 'error' + errors = body.get('errors', []) - context = self.connection.context or {} - context_record_id = context.get('record_id', None) - context_zone_domain = context.get('zone_domain', None) + for error in errors: + try: + exception_class, context = self.exceptions[error['code']] + except KeyError: + exception_class, context = LibcloudError, [] - if (is_error_result and 'invalid record id' in msg.lower() and - context_record_id): - raise RecordDoesNotExistError(value=msg, - driver=self.connection.driver, - record_id=context_record_id) - elif (is_error_result and 'invalid zone' in msg.lower() and - context_zone_domain): - raise ZoneDoesNotExistError(value=msg, - driver=self.connection.driver, - zone_id=context_zone_domain) + kwargs = { + 'value': '{}: {}'.format(error['code'], error['message']), + 'driver': self.connection.driver, + } - if error_code == 'E_UNAUTH': - raise InvalidCredsError(msg) - elif result == 'error' or error_code is not None: - msg = 'Request failed: %s' % (self.body) - raise LibcloudError(value=msg, driver=self.connection.driver) + merge_valid_keys(kwargs, context, self.connection.context) - return body + raise exception_class(**kwargs) class CloudFlareDNSConnection(ConnectionUserAndKey): @@ -103,24 +130,15 @@ class CloudFlareDNSConnection(ConnectionUserAndKey): secure = True responseCls = CloudFlareDNSResponse - def request(self, action, params=None, data=None, headers=None, - method='GET'): - params = params or {} - data = data or {} + def add_default_headers(self, headers): + headers['Content-Type'] = 'application/json' + headers['X-Auth-Email'] = self.user_id + headers['X-Auth-Key'] = self.key - base_params = { - 'email': self.user_id, - 'tkn': self.key, - 'a': action - } - params = copy.deepcopy(params) - params.update(base_params) + return headers - return super(CloudFlareDNSConnection, self).request(action=API_PATH, - params=params, - data=None, - method=method, - headers=headers) + def encode_data(self, data): + return json.dumps(data) class CloudFlareDNSDriver(DNSDriver): @@ -141,290 +159,313 @@ class CloudFlareDNSDriver(DNSDriver): RecordType.URL: 'LOC' } + ZONES_PAGE_SIZE = 50 + RECORDS_PAGE_SIZE = 100 + MEMBERSHIPS_PAGE_SIZE = 50 + def iterate_zones(self): - # TODO: Support pagination - result = self.connection.request(action='zone_load_multi').object - zones = self._to_zones(data=result['response']['zones']['objs']) + def _iterate_zones(params): + url = '{}/zones'.format(API_BASE) + + response = self.connection.request(url, params=params) + + items = response.object['result'] + zones = [self._to_zone(item) for item in items] - return zones + return response, zones + + return self._paginate(_iterate_zones, self.ZONES_PAGE_SIZE) def iterate_records(self, zone): - # TODO: Support pagination - params = {'z': zone.domain} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='rec_load_all', params=params) - data = resp.object['response']['recs']['objs'] - records = self._to_records(zone=zone, data=data) - return records + def _iterate_records(params): + url = '{}/zones/{}/dns_records'.format(API_BASE, zone.id) + + self.connection.set_context({'zone_id': zone.id}) + response = self.connection.request(url, params=params) + + items = response.object['result'] + records = [self._to_record(zone, item) for item in items] + + return response, records + + return self._paginate(_iterate_records, self.RECORDS_PAGE_SIZE) def get_zone(self, zone_id): - # TODO: This is not efficient - zones = self.list_zones() + url = '{}/zones/{}'.format(API_BASE, zone_id) - try: - zone = [z for z in zones if z.id == zone_id][0] - except IndexError: - raise ZoneDoesNotExistError(value='', driver=self, zone_id=zone_id) + self.connection.set_context({'zone_id': zone_id}) + response = self.connection.request(url) + + item = response.object['result'] + zone = self._to_zone(item) return zone - def create_record(self, name, zone, type, data, extra=None): + def create_zone(self, domain, type='master', ttl=None, extra=None): + """ + @inherits: :class:`DNSDriver.create_zone` + + Note that for users who have more than one account membership, + the id of the account in which to create the zone must be + specified via the ``extra`` key ``account``. + + Note that for ``extra`` zone properties, only the ones specified in + ``ZONE_CREATE_ATTRIBUTES`` can be set at creation time. Additionally, + setting the ``ttl` property is not supported. + """ extra = extra or {} - params = {'name': name, 'z': zone.domain, 'type': type, - 'content': data} - params['ttl'] = extra.get('ttl', 120) + account = extra.get('account') + if account is None: + memberships = self.ex_get_user_account_memberships() + memberships = list(itertools.islice(memberships, 2)) + + if len(memberships) != 1: + raise ValueError('must specify account for zone') + + account = memberships[0]['account']['id'] + + url = '{}/zones'.format(API_BASE) + + body = { + 'name': domain, + 'account': { + 'id': account + }, + 'type': LIBCLOUD_TO_CLOUDFLARE_ZONE_TYPE[type] + } + + merge_valid_keys(body, ZONE_CREATE_ATTRIBUTES, extra) + + response = self.connection.request(url, data=body, method='POST') + + item = response.object['result'] + zone = self._to_zone(item) + + return zone + + def update_zone(self, zone, domain, type='master', ttl=None, extra=None): + """ + @inherits: :class:`DNSDriver.update_zone` + + Note that the ``zone``, ``type`` and ``ttl`` properties can't be + updated. The only updatable properties are the ``extra`` zone + properties specified in ``ZONE_UPDATE_ATTRIBUTES``. Only one property + may be updated at a time. Any non-updatable properties are ignored. + """ + body = merge_valid_keys({}, ZONE_UPDATE_ATTRIBUTES, extra) + if len(body) != 1: + return zone + + url = '{}/zones/{}'.format(API_BASE, zone.id) + + self.connection.set_context({'zone_id': zone.id}) + response = self.connection.request(url, data=body, method='PATCH') + + item = response.object['result'] + zone = self._to_zone(item) + + return zone + + def delete_zone(self, zone): + url = '{}/zones/{}'.format(API_BASE, zone.id) + + self.connection.set_context({'zone_id': zone.id}) + response = self.connection.request(url, method='DELETE') + + item = response.object.get('result', {}).get('id') + is_deleted = item == zone.id + + return is_deleted + + def get_record(self, zone_id, record_id): + zone = self.get_zone(zone_id) + + url = '{}/zones/{}/dns_records/{}'.format(API_BASE, zone.id, + record_id) + + self.connection.set_context({'record_id': record_id}) + response = self.connection.request(url) + + item = response.object['result'] + record = self._to_record(zone, item) + + return record + + def create_record(self, name, zone, type, data, extra=None): + """ + @inherits: :class:`DNSDriver.create_record` + + Note that for ``extra`` record properties, only the ones specified in + ``RECORD_CREATE_ATTRIBUTES`` can be set at creation time. Any + non-settable properties are ignored. + """ + url = '{}/zones/{}/dns_records'.format(API_BASE, zone.id) + + body = { + 'type': type, + 'name': name, + 'content': data, + } + + merge_valid_keys(body, RECORD_CREATE_ATTRIBUTES, extra) - if 'priority' in extra: - # For MX and SRV records - params['prio'] = extra['priority'] + self.connection.set_context({'zone_id': zone.id}) + response = self.connection.request(url, data=body, method='POST') + + item = response.object['result'] + record = self._to_record(zone, item) - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='rec_new', params=params) - item = resp.object['response']['rec']['obj'] - record = self._to_record(zone=zone, item=item) return record def update_record(self, record, name=None, type=None, data=None, extra=None): - extra = extra or {} - params = {'z': record.zone.domain, 'id': record.id} + """ + @inherits: :class:`DNSDriver.update_record` - params['name'] = name or record.name - params['type'] = type or record.type - params['content'] = data or record.data - params['ttl'] = extra.get('ttl', None) or record.extra['ttl'] + Note that for ``extra`` record properties, only the ones specified in + ``RECORD_UPDATE_ATTRIBUTES`` can be updated. Any non-updatable + properties are ignored. + """ + url = '{}/zones/{}/dns_records/{}'.format(API_BASE, record.zone.id, + record.id) + + body = { + 'type': record.type if type is None else type, + 'name': record.name if name is None else name, + 'content': record.data if data is None else data, + 'extra': record.extra or {}, + } + + merge_valid_keys(body['extra'], RECORD_UPDATE_ATTRIBUTES, extra) - self.connection.set_context({'zone_domain': record.zone.domain}) self.connection.set_context({'record_id': record.id}) - resp = self.connection.request(action='rec_edit', params=params) - item = resp.object['response']['rec']['obj'] - record = self._to_record(zone=record.zone, item=item) + response = self.connection.request(url, data=body, method='PUT') + + item = response.object['result'] + record = self._to_record(record.zone, item) + return record def delete_record(self, record): - params = {'z': record.zone.domain, 'id': record.id} - self.connection.set_context({'zone_domain': record.zone.domain}) + url = '{}/zones/{}/dns_records/{}'.format(API_BASE, record.zone.id, + record.id) + self.connection.set_context({'record_id': record.id}) - resp = self.connection.request(action='rec_delete', params=params) - result = resp.object - return result.get('result', None) == 'success' + response = self.connection.request(url, method='DELETE') + + item = response.object.get('result', {}).get('id') + is_deleted = item == record.id + + return is_deleted + + def ex_get_user_account_memberships(self): + def _ex_get_user_account_memberships(params): + url = '{}/memberships'.format(API_BASE) + + response = self.connection.request(url, params=params) + return response, response.object['result'] + + return self._paginate(_ex_get_user_account_memberships, + self.MEMBERSHIPS_PAGE_SIZE) def ex_get_zone_stats(self, zone, interval=30): - params = {'z': zone.domain, 'interval': interval} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='stats', params=params) - result = resp.object['response']['result']['objs'][0] - return result + raise NotImplementedError('not yet implemented in v4 driver') def ex_zone_check(self, zones): - zone_domains = [zone.domain for zone in zones] - zone_domains = ','.join(zone_domains) - params = {'zones': zone_domains} - resp = self.connection.request(action='zone_check', params=params) - result = resp.object['response']['zones'] - return result + raise NotImplementedError('not yet implemented in v4 driver') def ex_get_ip_threat_score(self, ip): - """ - Retrieve current threat score for a given IP. Note that scores are on - a logarithmic scale, where a higher score indicates a higher threat. - """ - params = {'ip': ip} - resp = self.connection.request(action='ip_lkup', params=params) - result = resp.object['response'] - return result + raise NotImplementedError('not yet implemented in v4 driver') def ex_get_zone_settings(self, zone): - """ - Retrieve all current settings for a given zone. - """ - params = {'z': zone.domain} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='zone_settings', params=params) - result = resp.object['response']['result']['objs'][0] - return result + raise NotImplementedError('not yet implemented in v4 driver') def ex_set_zone_security_level(self, zone, level): - """ - Set the zone Basic Security Level to I'M UNDER ATTACK! / HIGH / - MEDIUM / LOW / ESSENTIALLY OFF. - - :param level: Security level. Valid values are: help, high, med, low, - eoff. - :type level: ``str`` - """ - params = {'z': zone.domain, 'v': level} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='sec_lvl', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_set_zone_cache_level(self, zone, level): - """ - Set the zone caching level. - - :param level: Caching level. Valid values are: agg (aggresive), basic. - :type level: ``str`` - """ - params = {'z': zone.domain, 'v': level} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='cache_lvl', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_enable_development_mode(self, zone): - """ - Enable development mode. When Development Mode is on the cache is - bypassed. Development mode remains on for 3 hours or until when it is - toggled back off. - """ - params = {'z': zone.domain, 'v': 1} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='devmode', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_disable_development_mode(self, zone): - """ - Disable development mode. - """ - params = {'z': zone.domain, 'v': 0} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='devmode', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_purge_cached_files(self, zone): - """ - Purge CloudFlare of any cached files. - """ - params = {'z': zone.domain, 'v': 1} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='fpurge_ts', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_purge_cached_file(self, zone, url): - """ - Purge single file from CloudFlare's cache. - - :param url: URL to the file to purge from cache. - :type url: ``str`` - """ - params = {'z': zone.domain, 'url': url} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='zone_file_purge', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_whitelist_ip(self, zone, ip): - """ - Whitelist the provided IP. - """ - params = {'z': zone.domain, 'key': ip} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='wl', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_blacklist_ip(self, zone, ip): - """ - Blacklist the provided IP. - """ - params = {'z': zone.domain, 'key': ip} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='ban', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_unlist_ip(self, zone, ip): - """ - Remove provided ip from the whitelist and blacklist. - """ - params = {'z': zone.domain, 'key': ip} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='nul', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_enable_ipv6_support(self, zone): - """ - Enable IPv6 support for the provided zone. - """ - params = {'z': zone.domain, 'v': 3} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='ipv46', params=params) - result = resp.object - return result.get('result', None) == 'success' + raise NotImplementedError('not yet implemented in v4 driver') def ex_disable_ipv6_support(self, zone): - """ - Disable IPv6 support for the provided zone. - """ - params = {'z': zone.domain, 'v': 0} - self.connection.set_context({'zone_domain': zone.domain}) - resp = self.connection.request(action='ipv46', params=params) - result = resp.object - return result.get('result', None) == 'success' - - def _to_zones(self, data): - zones = [] - - for item in data: - zone = self._to_zone(item=item) - zones.append(zone) - - return zones + raise NotImplementedError('not yet implemented in v4 driver') def _to_zone(self, item): - type = 'master' - - extra = {} - extra['props'] = item.get('props', {}) - extra['confirm_code'] = item.get('confirm_code', {}) - extra['allow'] = item.get('allow', {}) - for attribute in ZONE_EXTRA_ATTRIBUTES: - value = item.get(attribute, None) - extra[attribute] = value - - zone = Zone(id=str(item['zone_id']), domain=item['zone_name'], - type=type, ttl=None, driver=self, extra=extra) - return zone - - def _to_records(self, zone, data): - records = [] - - for item in data: - record = self._to_record(zone=zone, item=item) - records.append(record) - - return records + return Zone( + id=item['id'], + domain=item['name'], + type=CLOUDFLARE_TO_LIBCLOUD_ZONE_TYPE[item['type']], + ttl=None, + driver=self, + extra={key: item.get(key) for key in ZONE_EXTRA_ATTRIBUTES}, + ) def _to_record(self, zone, item): - name = self._get_record_name(item=item) - type = item['type'] - data = item['content'] - - if item.get('ttl', None): - ttl = int(item['ttl']) - else: - ttl = None - - extra = {} - extra['ttl'] = ttl - extra['props'] = item.get('props', {}) - for attribute in RECORD_EXTRA_ATTRIBUTES: - value = item.get(attribute, None) - extra[attribute] = value - - record = Record(id=str(item['rec_id']), name=name, type=type, - data=data, zone=zone, driver=self, ttl=ttl, - extra=extra) - return record + name = item['name'] + name = name.replace('.' + item['zone_name'], '') + name = name.replace(item['zone_name'], '') + name = name or None + + ttl = item.get('ttl') + if ttl is not None: + ttl = int(ttl) + + return Record( + id=item['id'], + name=name, + type=item['type'], + data=item['content'], + zone=zone, + driver=self, + ttl=ttl, + extra={key: item.get(key) for key in RECORD_EXTRA_ATTRIBUTES}, + ) + + def _paginate(self, get_page, page_size): + for page in itertools.count(start=1): + params = {'page': page, 'per_page': page_size} + + response, items = get_page(params) + + for item in items: + yield item + + if self._is_last_page(response): + break + + if len(items) < page_size: + break + + def _is_last_page(self, response): + try: + result_info = response.object['result_info'] + last_page = result_info['total_pages'] + current_page = result_info['page'] + except KeyError: + return False - def _get_record_name(self, item): - name = item['name'].replace('.' + item['zone_name'], '') or None - if name: - name = name.replace(item['zone_name'], '') or None - return name + return current_page == last_page diff --git a/libcloud/test/dns/fixtures/cloudflare/ban.json b/libcloud/test/dns/fixtures/cloudflare/ban.json deleted file mode 100644 index 1dbf1bf0dd..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/ban.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "response": { - "result": { - "ip": "127.0.0.1", - "action": "BAN" - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/cache_lvl.json b/libcloud/test/dns/fixtures/cloudflare/cache_lvl.json deleted file mode 100644 index 15abe82527..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/cache_lvl.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/devmode.json b/libcloud/test/dns/fixtures/cloudflare/devmode.json deleted file mode 100644 index 15abe82527..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/devmode.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/fpurge_ts.json b/libcloud/test/dns/fixtures/cloudflare/fpurge_ts.json deleted file mode 100644 index e88b55ce89..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/fpurge_ts.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "response": { - "fpurge_ts": 1449381662 - }, - "result": "success", - "msg": null, - "attributes": { - "cooldown": 20 - } -} diff --git a/libcloud/test/dns/fixtures/cloudflare/ip_lkup.json b/libcloud/test/dns/fixtures/cloudflare/ip_lkup.json deleted file mode 100644 index d0118a1cda..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/ip_lkup.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "response": { - "127.0.0.1": false - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/ipv46.json b/libcloud/test/dns/fixtures/cloudflare/ipv46.json deleted file mode 100644 index 15abe82527..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/ipv46.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/memberships_GET.json b/libcloud/test/dns/fixtures/cloudflare/memberships_GET.json new file mode 100644 index 0000000000..0e9b82fd65 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/memberships_GET.json @@ -0,0 +1,110 @@ +{ + "result": [ + { + "id": "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", + "status": "accepted", + "permissions": { + "access": { + "read": true, + "edit": true + }, + "analytics": { + "read": true, + "edit": false + }, + "app": { + "read": false, + "edit": true + }, + "auditlogs": { + "read": true, + "edit": false + }, + "billing": { + "read": true, + "edit": true + }, + "cache_purge": { + "read": false, + "edit": true + }, + "dns_records": { + "read": true, + "edit": true + }, + "lb": { + "read": true, + "edit": true + }, + "legal": { + "read": true, + "edit": true + }, + "logs": { + "read": true, + "edit": true + }, + "member": { + "read": true, + "edit": true + }, + "organization": { + "read": true, + "edit": true + }, + "ssl": { + "read": true, + "edit": true + }, + "stream": { + "read": true, + "edit": true + }, + "subscription": { + "read": true, + "edit": true + }, + "waf": { + "read": true, + "edit": true + }, + "webhooks": { + "read": true, + "edit": true + }, + "worker": { + "read": true, + "edit": true + }, + "zone": { + "read": true, + "edit": true + }, + "zone_settings": { + "read": true, + "edit": true + } + }, + "roles": [ + "Super Administrator - All Privileges" + ], + "account": { + "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "cloudflare@test.com's Account", + "settings": { + "enforce_twofactor": false + } + } + } + ], + "result_info": { + "page": 1, + "per_page": 20, + "total_pages": 1, + "count": 1, + "total_count": 1 + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/nul_.json b/libcloud/test/dns/fixtures/cloudflare/nul_.json deleted file mode 100644 index 6762b7ce9f..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/nul_.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "response": { - "result": { - "ip": "127.0.0.1", - "action": "NUL" - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/rec_delete.json b/libcloud/test/dns/fixtures/cloudflare/rec_delete.json deleted file mode 100644 index 0ffee1caad..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/rec_delete.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "request": { - "act": "rec_delete", - "tkn": "maybeno", - "a": "rec_delete", - "z": "example.com", - "id": "412563484", - "email": "example@example.com" - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/rec_edit.json b/libcloud/test/dns/fixtures/cloudflare/rec_edit.json deleted file mode 100644 index 68128e84f2..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/rec_edit.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "request": { - "act": "rec_edit", - "a": "rec_edit", - "name": "test6", - "tkn": "maybeno", - "id": "412564825", - "content": "127.0.0.4", - "ttl": "120", - "z": "example.com", - "type": "A", - "email": "example@example.com" - }, - "response": { - "rec": { - "obj": { - "rec_id": "412564825", - "rec_hash": "0cb296652af55023e5bf5ee6c9ad9974", - "zone_name": "example.com", - "name": "test6.example.com", - "display_name": "test6", - "type": "A", - "prio": null, - "content": "127.0.0.4", - "display_content": "127.0.0.4", - "ttl": "120", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 0, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - } - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/rec_load_all.json b/libcloud/test/dns/fixtures/cloudflare/rec_load_all.json deleted file mode 100644 index dde804e267..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/rec_load_all.json +++ /dev/null @@ -1,525 +0,0 @@ -{ - "request": { - "act": "rec_load_all", - "tkn": "maybeno", - "a": "rec_load_all", - "z": "example.com", - "email": "example@example.com" - }, - "response": { - "recs": { - "has_more": false, - "count": 18, - "objs": [{ - "rec_id": "364797364", - "rec_hash": "479a684c73e0e75c433675e86957660a", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "A", - "prio": null, - "content": "192.30.252.153", - "display_content": "192.30.252.153", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "1", - "props": { - "proxiable": 1, - "cloud_on": 1, - "cf_open": 0, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797367", - "rec_hash": "acaee7d8c6e256f7bcc5dab4410489cf", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "A", - "prio": null, - "content": "192.30.252.154", - "display_content": "192.30.252.154", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "1", - "props": { - "proxiable": 1, - "cloud_on": 1, - "cf_open": 0, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "403456915", - "rec_hash": "77cabc2ba4a75814eeda78daabce0859", - "zone_name": "example.com", - "name": "test2.example.com", - "display_name": "test2", - "type": "A", - "prio": null, - "content": "127.0.0.2", - "display_content": "127.0.0.2", - "ttl": "120", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 0, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "403456984", - "rec_hash": "edd95959936d20583e38352831d1978b", - "zone_name": "example.com", - "name": "test3.example.com", - "display_name": "test3", - "type": "A", - "prio": null, - "content": "127.0.0.1", - "display_content": "127.0.0.1", - "ttl": "120", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 0, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364982413", - "rec_hash": "fa43ee2e176f9be7b8e464167bdff440", - "zone_name": "example.com", - "name": "yesyes.example.com", - "display_name": "yesyes", - "type": "CNAME", - "prio": null, - "content": "verify.bing.com", - "display_content": "verify.bing.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 1, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364982461", - "rec_hash": "4dfb7dd8d8a895174600fe9fb0f48380", - "zone_name": "example.com", - "name": "google.example.com", - "display_name": "google", - "type": "CNAME", - "prio": null, - "content": "google.com", - "display_content": "google.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 1, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797370", - "rec_hash": "537311442890afedc06e5febf7171023", - "zone_name": "example.com", - "name": "www.example.com", - "display_name": "www", - "type": "CNAME", - "prio": null, - "content": "kami.github.io", - "display_content": "kami.github.io", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "1", - "props": { - "proxiable": 1, - "cloud_on": 1, - "cf_open": 0, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797388", - "rec_hash": "a55e09423fa23c33906131aa678e86ba", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "20", - "content": "alt1.aspmx.l.google.com", - "display_content": "alt1.aspmx.l.google.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797382", - "rec_hash": "c1bc38b678f1c07af3d506a0b4f57da4", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "20", - "content": "alt2.aspmx.l.google.com", - "display_content": "alt2.aspmx.l.google.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797391", - "rec_hash": "90b3f10c8cbe2164b87302de99cf7760", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "30", - "content": "aspmx2.googlemail.com", - "display_content": "aspmx2.googlemail.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797385", - "rec_hash": "99cad8b4ae97d559716c838276d1bf43", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "30", - "content": "aspmx3.googlemail.com", - "display_content": "aspmx3.googlemail.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797379", - "rec_hash": "79e354b6d036b5eec0fe75974e0ffa98", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "30", - "content": "aspmx4.googlemail.com", - "display_content": "aspmx4.googlemail.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797376", - "rec_hash": "ad08cc1813d4061763aecfe0d984bea3", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "30", - "content": "aspmx5.googlemail.com", - "display_content": "aspmx5.googlemail.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364797373", - "rec_hash": "b38ed0e1e250e12f2c1b3a4a163e5526", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "MX", - "prio": "10", - "content": "aspmx.l.google.com", - "display_content": "aspmx.l.google.com", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - }, - "mx": { - "auto": false - } - }, { - "rec_id": "364982359", - "rec_hash": "2f4037b298fb88b77a901725824287c0", - "zone_name": "example.com", - "name": "google._domainkey.example.com", - "display_name": "google._domainkey", - "type": "TXT", - "prio": null, - "content": "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNCHa8VeffMv+X\/fRkPgHC9MN2Eh5vQqMkWy4e\/YnFbWgF1JilL1Yn9nN54A5WV7lZpCTIvuOC2CrQrIcaBpfr+8SjYsjGO91dz8cwgqZkl7mAjKs7nz8U0PsstuI9i4V3LsHC4NVGOirAgnKA4HXVhxGRuyE94+tuNJ6XDLJoNQIDAQAB", - "display_content": "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNCHa8VeffMv+X\/fRkPgHC9MN2Eh5vQqMkWy4e\/YnFbWgF1JilL1Yn9nN54A5WV7lZpCTIvuOC2CrQrIcaBpfr+8SjYsjGO91dz8cwgqZkl7mAjKs7nz8U0PsstuI9i4V3LsHC4NVGOirAgnKA4HXVhxGRuyE94+tuNJ6XDLJoNQIDAQAB", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797400", - "rec_hash": "75788bfdfe314c339e444bfc1c6cfd2e", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "TXT", - "prio": null, - "content": "google-site-verification=Rgex8ShgIRWUlb9j0Ivw5uHllb0p9skEdJqkSMqvX_o", - "display_content": "google-site-verification=Rgex8ShgIRWUlb9j0Ivw5uHllb0p9skEdJqkSMqvX_o", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797394", - "rec_hash": "c588426dbf098b57cfcee86815b482d0", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "TXT", - "prio": null, - "content": "keybase-site-verification=L_shC4yrIjo-yM4qBDKmro9kOH8devqvHrlQtgFa2Us", - "display_content": "keybase-site-verification=L_shC4yrIjo-yM4qBDKmro9kOH8devqvHrlQtgFa2Us", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }, { - "rec_id": "364797397", - "rec_hash": "e20556627e805701c5d0a383458201ae", - "zone_name": "example.com", - "name": "example.com", - "display_name": "example.com", - "type": "TXT", - "prio": null, - "content": "v=spf1 include:_spf.google.com ~all", - "display_content": "v=spf1 include:_spf.google.com ~all", - "ttl": "1", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 1, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - }] - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/rec_new.json b/libcloud/test/dns/fixtures/cloudflare/rec_new.json deleted file mode 100644 index 3ea4dfc203..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/rec_new.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "request": { - "act": "rec_new", - "a": "rec_new", - "name": "test5", - "tkn": "maybeno", - "content": "127.0.0.3", - "ttl": "120", - "z": "example.com", - "type": "A", - "email": "example@example.com" - }, - "response": { - "rec": { - "obj": { - "rec_id": "412561327", - "rec_hash": "ed23e38bca17007e026d2da517adf10a", - "zone_name": "example.com", - "name": "test5.example.com", - "display_name": "test5", - "type": "A", - "prio": null, - "content": "127.0.0.3", - "display_content": "127.0.0.3", - "ttl": "120", - "ttl_ceil": 86400, - "ssl_id": "2245194", - "ssl_status": "V", - "ssl_expires_on": null, - "auto_ttl": 0, - "service_mode": "0", - "props": { - "proxiable": 0, - "cloud_on": 0, - "cf_open": 1, - "vanity_lock": 0, - "ssl": 1, - "expired_ssl": 0, - "expiring_ssl": 0, - "pending_ssl": 0 - } - } - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/record_DELETE.json b/libcloud/test/dns/fixtures/cloudflare/record_DELETE.json new file mode 100644 index 0000000000..fd43e90a29 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/record_DELETE.json @@ -0,0 +1,8 @@ +{ + "result": { + "id": "364797364" + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/record_GET.json b/libcloud/test/dns/fixtures/cloudflare/record_GET.json new file mode 100644 index 0000000000..fbaba69c7b --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/record_GET.json @@ -0,0 +1,24 @@ +{ + "result": { + "id": "364797364", + "type": "A", + "name": "example.com", + "content": "192.30.252.153", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:28:00.801892Z", + "created_on": "2018-12-22T21:28:00.801892Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/record_GET_400.json b/libcloud/test/dns/fixtures/cloudflare/record_GET_400.json new file mode 100644 index 0000000000..a58e830ee6 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/record_GET_400.json @@ -0,0 +1,15 @@ +{ + "success": false, + "errors": [ + { + "code": 7003, + "message": "Could not route to /zones/1234/dns_records/invalid, perhaps your object identifier is invalid?" + }, + { + "code": 7000, + "message": "No route for that URI" + } + ], + "messages": [], + "result": null +} diff --git a/libcloud/test/dns/fixtures/cloudflare/record_GET_404.json b/libcloud/test/dns/fixtures/cloudflare/record_GET_404.json new file mode 100644 index 0000000000..1917889d06 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/record_GET_404.json @@ -0,0 +1,11 @@ +{ + "success": false, + "errors": [ + { + "code": 1002, + "message": "Invalid dns record identifier" + } + ], + "messages": [], + "result": null +} diff --git a/libcloud/test/dns/fixtures/cloudflare/record_PUT.json b/libcloud/test/dns/fixtures/cloudflare/record_PUT.json new file mode 100644 index 0000000000..f5eeb61a44 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/record_PUT.json @@ -0,0 +1,24 @@ +{ + "result": { + "id": "412561327", + "type": "A", + "name": "test6.example.com", + "content": "127.0.0.4", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:28:00.801892Z", + "created_on": "2018-12-22T21:28:00.801892Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/records_GET_1.json b/libcloud/test/dns/fixtures/cloudflare/records_GET_1.json new file mode 100644 index 0000000000..0b24590f20 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/records_GET_1.json @@ -0,0 +1,109 @@ +{ + "result": [ + { + "id": "364797364", + "type": "A", + "name": "example.com", + "content": "192.30.252.153", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:28:00.801892Z", + "created_on": "2018-12-22T21:28:00.801892Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r1r1r1r1r1r1r1r1r1r1r1r1r1r1r1r1", + "type": "A", + "name": "example.com", + "content": "192.30.252.154", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:28:03.346998Z", + "created_on": "2018-12-22T21:28:03.346998Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r2r2r2r2r2r2r2r2r2r2r2r2r2r2r2r2", + "type": "CNAME", + "name": "email.example.com", + "content": "mailgun.org", + "proxiable": true, + "proxied": false, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T20:29:48.453923Z", + "created_on": "2018-12-22T20:29:48.453923Z", + "meta": { + "auto_added": true, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r3r3r3r3r3r3r3r3r3r3r3r3r3r3r3r3", + "type": "CNAME", + "name": "foo.example.com", + "content": "foo.com", + "proxiable": true, + "proxied": false, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2019-05-30T01:43:01.509188Z", + "created_on": "2019-05-30T01:43:01.509188Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "364982413", + "type": "CNAME", + "name": "yesyes", + "content": "verify.bing.com", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:29:46.874918Z", + "created_on": "2018-12-22T21:29:46.874918Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + } + ], + "result_info": { + "page": 1, + "per_page": 5, + "total_pages": 2, + "count": 5, + "total_count": 9 + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/records_GET_2.json b/libcloud/test/dns/fixtures/cloudflare/records_GET_2.json new file mode 100644 index 0000000000..14a93a8d31 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/records_GET_2.json @@ -0,0 +1,92 @@ +{ + "result": [ + { + "id": "r4r4r4r4r4r4r4r4r4r4r4r4r4r4r4r4", + "type": "MX", + "name": "example.com", + "content": "mxa.mailgun.org", + "proxiable": false, + "proxied": false, + "ttl": 1, + "priority": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T20:29:48.532399Z", + "created_on": "2018-12-22T20:29:48.532399Z", + "meta": { + "auto_added": true, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r5r5r5r5r5r5r5r5r5r5r5r5r5r5r5r5", + "type": "MX", + "name": "example.com", + "content": "mxb.mailgun.org", + "proxiable": false, + "proxied": false, + "ttl": 1, + "priority": 2, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T20:29:48.540671Z", + "created_on": "2018-12-22T20:29:48.540671Z", + "meta": { + "auto_added": true, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r6r6r6r6r6r6r6r6r6r6r6r6r6r6r6r6", + "type": "TXT", + "name": "example.com", + "content": "v=spf1 include:mailgun.org ~all", + "proxiable": false, + "proxied": false, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T20:29:48.512931Z", + "created_on": "2018-12-22T20:29:48.512931Z", + "meta": { + "auto_added": true, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + { + "id": "r7r7r7r7r7r7r7r7r7r7r7r7r7r7r7r7", + "type": "TXT", + "name": "pic._domainkey.example.com", + "content": "k=rsa; ...", + "proxiable": false, + "proxied": false, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T20:29:48.523230Z", + "created_on": "2018-12-22T20:29:48.523230Z", + "meta": { + "auto_added": true, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + } + ], + "result_info": { + "page": 2, + "per_page": 5, + "total_pages": 2, + "count": 4, + "total_count": 9 + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/records_POST.json b/libcloud/test/dns/fixtures/cloudflare/records_POST.json new file mode 100644 index 0000000000..2384c83491 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/records_POST.json @@ -0,0 +1,24 @@ +{ + "result": { + "id": "412561327", + "type": "A", + "name": "test5.example.com", + "content": "127.0.0.3", + "proxiable": true, + "proxied": true, + "ttl": 1, + "locked": false, + "zone_id": "1234", + "zone_name": "example.com", + "modified_on": "2018-12-22T21:28:00.801892Z", + "created_on": "2018-12-22T21:28:00.801892Z", + "meta": { + "auto_added": false, + "managed_by_apps": false, + "managed_by_argo_tunnel": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/sec_lvl.json b/libcloud/test/dns/fixtures/cloudflare/sec_lvl.json deleted file mode 100644 index 15abe82527..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/sec_lvl.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/stats.json b/libcloud/test/dns/fixtures/cloudflare/stats.json deleted file mode 100644 index b45884bdd9..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/stats.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "response": { - "result": { - "timeZero": 1448773672000, - "timeEnd": 1449378472000, - "count": 1, - "has_more": false, - "objs": [{ - "cachedServerTime": 1449378474000, - "cachedExpryTime": 1449379074000, - "trafficBreakdown": { - "pageviews": { - "regular": 1804, - "threat": 80, - "crawler": 438 - }, - "uniques": { - "regular": 1914, - "threat": 80, - "crawler": 438 - } - }, - "bandwidthServed": { - "cloudflare": 422053.22949219, - "user": 408767.30664062 - }, - "requestsServed": { - "cloudflare": 29333, - "user": 13367 - }, - "pro_zone": false, - "pageLoadTime": null, - "currentServerTime": 1449378474000, - "interval": 30, - "zoneCDate": 1373665252000, - "userSecuritySetting": "Medium", - "dev_mode": 0, - "ipv46": 3, - "ob": 1, - "cache_lvl": "agg", - "outboundLinks": "disabled" - }] - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/wl.json b/libcloud/test/dns/fixtures/cloudflare/wl.json deleted file mode 100644 index 777b39218d..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/wl.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "response": { - "result": { - "ip": "127.0.0.1", - "action": "WL" - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_DELETE.json b/libcloud/test/dns/fixtures/cloudflare/zone_DELETE.json new file mode 100644 index 0000000000..a0732bc6f5 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zone_DELETE.json @@ -0,0 +1,8 @@ +{ + "result": { + "id": "1234" + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_GET.json b/libcloud/test/dns/fixtures/cloudflare/zone_GET.json new file mode 100644 index 0000000000..0e914a7e5f --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zone_GET.json @@ -0,0 +1,93 @@ +{ + "result": { + "id": "1234", + "name": "example.com", + "status": "active", + "paused": false, + "type": "full", + "development_mode": 0, + "name_servers": [ + "anna.ns.cloudflare.com", + "john.ns.cloudflare.com" + ], + "original_name_servers": [ + "amir.ns.cloudflare.com", + "dee.ns.cloudflare.com" + ], + "original_registrar": null, + "original_dnshost": null, + "modified_on": "2019-05-30T01:43:01.509188Z", + "created_on": "2018-12-22T20:29:41.313041Z", + "activated_on": "2018-12-22T21:14:27.799913Z", + "meta": { + "step": 3, + "wildcard_proxiable": false, + "custom_certificate_quota": 0, + "page_rule_quota": 3, + "phishing_detected": false, + "multiple_railguns_allowed": false + }, + "owner": { + "id": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", + "type": "user", + "email": "cloudflare@test.com" + }, + "account": { + "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "cloudflare@test.com" + }, + "permissions": [ + "#access:edit", + "#access:read", + "#analytics:read", + "#app:edit", + "#auditlogs:read", + "#billing:edit", + "#billing:read", + "#cache_purge:edit", + "#dns_records:edit", + "#dns_records:read", + "#lb:edit", + "#lb:read", + "#legal:edit", + "#legal:read", + "#logs:edit", + "#logs:read", + "#member:edit", + "#member:read", + "#organization:edit", + "#organization:read", + "#ssl:edit", + "#ssl:read", + "#stream:edit", + "#stream:read", + "#subscription:edit", + "#subscription:read", + "#waf:edit", + "#waf:read", + "#webhooks:edit", + "#webhooks:read", + "#worker:edit", + "#worker:read", + "#zone:edit", + "#zone:read", + "#zone_settings:edit", + "#zone_settings:read" + ], + "plan": { + "id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "name": "Free Website", + "price": 0, + "currency": "USD", + "frequency": "", + "is_subscribed": true, + "can_subscribe": false, + "legacy_id": "free", + "legacy_discount": false, + "externally_managed": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_GET_400.json b/libcloud/test/dns/fixtures/cloudflare/zone_GET_400.json new file mode 100644 index 0000000000..2660e93573 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zone_GET_400.json @@ -0,0 +1,15 @@ +{ + "success": false, + "errors": [ + { + "code": 7003, + "message": "Could not route to /zones/invalid, perhaps your object identifier is invalid?" + }, + { + "code": 7000, + "message": "No route for that URI" + } + ], + "messages": [], + "result": null +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_GET_404.json b/libcloud/test/dns/fixtures/cloudflare/zone_GET_404.json new file mode 100644 index 0000000000..7fe3f0023c --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zone_GET_404.json @@ -0,0 +1,11 @@ +{ + "success": false, + "errors": [ + { + "code": 1001, + "message": "Invalid zone identifier" + } + ], + "messages": [], + "result": null +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_PATCH.json b/libcloud/test/dns/fixtures/cloudflare/zone_PATCH.json new file mode 100644 index 0000000000..ae641c9a23 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zone_PATCH.json @@ -0,0 +1,93 @@ +{ + "result": { + "id": "1234", + "name": "example.com", + "status": "active", + "paused": true, + "type": "full", + "development_mode": 0, + "name_servers": [ + "anna.ns.cloudflare.com", + "john.ns.cloudflare.com" + ], + "original_name_servers": [ + "amir.ns.cloudflare.com", + "dee.ns.cloudflare.com" + ], + "original_registrar": null, + "original_dnshost": null, + "modified_on": "2019-05-30T01:43:02.509188Z", + "created_on": "2018-12-22T20:29:41.313041Z", + "activated_on": "2018-12-22T21:14:27.799913Z", + "meta": { + "step": 3, + "wildcard_proxiable": false, + "custom_certificate_quota": 0, + "page_rule_quota": 3, + "phishing_detected": false, + "multiple_railguns_allowed": false + }, + "owner": { + "id": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", + "type": "user", + "email": "cloudflare@test.com" + }, + "account": { + "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "cloudflare@test.com" + }, + "permissions": [ + "#access:edit", + "#access:read", + "#analytics:read", + "#app:edit", + "#auditlogs:read", + "#billing:edit", + "#billing:read", + "#cache_purge:edit", + "#dns_records:edit", + "#dns_records:read", + "#lb:edit", + "#lb:read", + "#legal:edit", + "#legal:read", + "#logs:edit", + "#logs:read", + "#member:edit", + "#member:read", + "#organization:edit", + "#organization:read", + "#ssl:edit", + "#ssl:read", + "#stream:edit", + "#stream:read", + "#subscription:edit", + "#subscription:read", + "#waf:edit", + "#waf:read", + "#webhooks:edit", + "#webhooks:read", + "#worker:edit", + "#worker:read", + "#zone:edit", + "#zone:read", + "#zone_settings:edit", + "#zone_settings:read" + ], + "plan": { + "id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "name": "Free Website", + "price": 0, + "currency": "USD", + "frequency": "", + "is_subscribed": true, + "can_subscribe": false, + "legacy_id": "free", + "legacy_discount": false, + "externally_managed": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_check.json b/libcloud/test/dns/fixtures/cloudflare/zone_check.json deleted file mode 100644 index a6fdf34d55..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/zone_check.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "response": { - "zones": { - "example.com": 4025956 - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_file_purge.json b/libcloud/test/dns/fixtures/cloudflare/zone_file_purge.json deleted file mode 100644 index 086925b72d..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/zone_file_purge.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "act": "zone_file_purge", - "url": "https:\/\/www.example.com\/aaaaa.html", - "tkn": "maybeno", - "z": "example.com", - "a": "zone_file_purge", - "email": "example@example.com" - }, - "response": { - "url": "https:\/\/www.example.com\/test.html" - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_load_multi.json b/libcloud/test/dns/fixtures/cloudflare/zone_load_multi.json deleted file mode 100644 index 8eb2ee5475..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/zone_load_multi.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "request": { - "act": "zone_load_multi", - "tkn": "maybeno", - "a": "zone_load_multi", - "email": "example@example.com" - }, - "response": { - "zones": { - "has_more": false, - "count": 1, - "objs": [{ - "zone_id": "1234", - "user_id": "54321", - "zone_name": "example.com", - "display_name": "example.com", - "zone_status": "V", - "zone_mode": "1", - "host_id": null, - "zone_type": "F", - "host_pubname": null, - "host_website": null, - "vtxt": null, - "fqdns": ["kara.ns.cloudflare.com", "noah.ns.cloudflare.com"], - "step": "4", - "zone_status_class": "status-ac_api_json_html_zone_load_multitive", - "zone_status_desc": "CloudFlare powered, this website will be accelerated and protected (info<\/a>)", - "ns_vanity_map": [], - "orig_registrar": "godaddy", - "orig_dnshost": null, - "orig_ns_names": "{dns1.stabletransit.com,dns2.stabletransit.com}", - "props": { - "dns_cname": 0, - "dns_partner": 0, - "dns_anon_partner": 0, - "plan": "FREE_ZONE", - "pro": 0, - "expired_pro": 0, - "pro_sub": 0, - "plan_sub": 0, - "ssl": 1, - "expired_ssl": 0, - "expired_rs_pro": 0, - "reseller_pro": 0, - "reseller_plans": [], - "force_interal": 0, - "ssl_needed": 0, - "alexa_rank": 1307220, - "has_vanity": 0 - }, - "confirm_code": { - "zone_delete": "maybeno", - "zone_deactivate": "maybeno", - "zone_dev_mode1": "maybeno" - }, - "allow": ["analytics", "threat_control", "zone_delete", "cf_apps", "dns_editor", "cf_settings", "page_rules", "zone_deactivate", "zone_dev_mode1"] - }] - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/zone_settings.json b/libcloud/test/dns/fixtures/cloudflare/zone_settings.json deleted file mode 100644 index a6a4834a84..0000000000 --- a/libcloud/test/dns/fixtures/cloudflare/zone_settings.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "request": { - "act": "zone_settings", - "tkn": "maybeno", - "a": "zone_settings", - "z": "example.com", - "email": "example@example.com" - }, - "response": { - "result": { - "objs": [{ - "userSecuritySetting": "Medium", - "dev_mode": 0, - "ipv46": 3, - "ob": 1, - "cache_lvl": "agg", - "outboundLinks": "disabled", - "bic": "1", - "chl_ttl": "3600", - "comodo_vc": "a.b", - "dnssec": "", - "exp_ttl": "86400", - "fpurge_ts": "1448144070", - "minify": "7", - "preload": "0", - "sec_lvl": "med", - "secureheader_settings": "{\"*\":{\"strict_transport_security\":{\"enable\":1,\"max_age\":2592000},\"content_type_options\":\"nosniff\"}}", - "ssl": "1", - "outlink": "0", - "geoloc": "1", - "host_spf": "0", - "waf_profile": "off", - "email_filter": "1", - "sse": "1", - "cache_ttl": "14400", - "lazy": "0", - "async": "0", - "ddos": "Off" - }] - } - }, - "result": "success", - "msg": null -} diff --git a/libcloud/test/dns/fixtures/cloudflare/zones_GET.json b/libcloud/test/dns/fixtures/cloudflare/zones_GET.json new file mode 100644 index 0000000000..da6e442091 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zones_GET.json @@ -0,0 +1,102 @@ +{ + "result": [ + { + "id": "1234", + "name": "example.com", + "status": "active", + "paused": false, + "type": "full", + "development_mode": 0, + "name_servers": [ + "anna.ns.cloudflare.com", + "john.ns.cloudflare.com" + ], + "original_name_servers": [ + "amir.ns.cloudflare.com", + "dee.ns.cloudflare.com" + ], + "original_registrar": null, + "original_dnshost": null, + "modified_on": "2019-05-30T01:43:01.509188Z", + "created_on": "2018-12-22T20:29:41.313041Z", + "activated_on": "2018-12-22T21:14:27.799913Z", + "meta": { + "step": 3, + "wildcard_proxiable": false, + "custom_certificate_quota": 0, + "page_rule_quota": 3, + "phishing_detected": false, + "multiple_railguns_allowed": false + }, + "owner": { + "id": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", + "type": "user", + "email": "cloudflare@test.com" + }, + "account": { + "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "cloudflare@test.com" + }, + "permissions": [ + "#access:edit", + "#access:read", + "#analytics:read", + "#app:edit", + "#auditlogs:read", + "#billing:edit", + "#billing:read", + "#cache_purge:edit", + "#dns_records:edit", + "#dns_records:read", + "#lb:edit", + "#lb:read", + "#legal:edit", + "#legal:read", + "#logs:edit", + "#logs:read", + "#member:edit", + "#member:read", + "#organization:edit", + "#organization:read", + "#ssl:edit", + "#ssl:read", + "#stream:edit", + "#stream:read", + "#subscription:edit", + "#subscription:read", + "#waf:edit", + "#waf:read", + "#webhooks:edit", + "#webhooks:read", + "#worker:edit", + "#worker:read", + "#zone:edit", + "#zone:read", + "#zone_settings:edit", + "#zone_settings:read" + ], + "plan": { + "id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "name": "Free Website", + "price": 0, + "currency": "USD", + "frequency": "", + "is_subscribed": true, + "can_subscribe": false, + "legacy_id": "free", + "legacy_discount": false, + "externally_managed": false + } + } + ], + "result_info": { + "page": 1, + "per_page": 20, + "total_pages": 1, + "count": 1, + "total_count": 1 + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/fixtures/cloudflare/zones_POST.json b/libcloud/test/dns/fixtures/cloudflare/zones_POST.json new file mode 100644 index 0000000000..80435f6234 --- /dev/null +++ b/libcloud/test/dns/fixtures/cloudflare/zones_POST.json @@ -0,0 +1,93 @@ +{ + "result": { + "id": "6789", + "name": "example2.com", + "status": "pending", + "paused": false, + "type": "full", + "development_mode": 0, + "name_servers": [ + "anna.ns.cloudflare.com", + "john.ns.cloudflare.com" + ], + "original_name_servers": [ + "amir.ns.cloudflare.com", + "dee.ns.cloudflare.com" + ], + "original_registrar": null, + "original_dnshost": null, + "modified_on": "2019-05-30T02:09:25.975712Z", + "created_on": "2019-05-30T02:09:25.975712Z", + "activated_on": null, + "meta": { + "step": 4, + "wildcard_proxiable": false, + "custom_certificate_quota": 0, + "page_rule_quota": 3, + "phishing_detected": false, + "multiple_railguns_allowed": false + }, + "owner": { + "id": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", + "type": "user", + "email": "cloudflare@test.com" + }, + "account": { + "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "cloudflare@test.com" + }, + "permissions": [ + "#access:edit", + "#access:read", + "#analytics:read", + "#app:edit", + "#auditlogs:read", + "#billing:edit", + "#billing:read", + "#cache_purge:edit", + "#dns_records:edit", + "#dns_records:read", + "#lb:edit", + "#lb:read", + "#legal:edit", + "#legal:read", + "#logs:edit", + "#logs:read", + "#member:edit", + "#member:read", + "#organization:edit", + "#organization:read", + "#ssl:edit", + "#ssl:read", + "#stream:edit", + "#stream:read", + "#subscription:edit", + "#subscription:read", + "#waf:edit", + "#waf:read", + "#webhooks:edit", + "#webhooks:read", + "#worker:edit", + "#worker:read", + "#zone:edit", + "#zone:read", + "#zone_settings:edit", + "#zone_settings:read" + ], + "plan": { + "id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "name": "Free Website", + "price": 0, + "currency": "USD", + "frequency": "", + "is_subscribed": true, + "can_subscribe": false, + "legacy_id": "free", + "legacy_discount": false, + "externally_managed": false + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/libcloud/test/dns/test_cloudflare.py b/libcloud/test/dns/test_cloudflare.py index 3a17fc867e..d886857a76 100644 --- a/libcloud/test/dns/test_cloudflare.py +++ b/libcloud/test/dns/test_cloudflare.py @@ -15,13 +15,15 @@ import sys +from libcloud.common.types import LibcloudError from libcloud.test import unittest from libcloud.dns.drivers.cloudflare import CloudFlareDNSDriver from libcloud.dns.drivers.cloudflare import ZONE_EXTRA_ATTRIBUTES from libcloud.dns.drivers.cloudflare import RECORD_EXTRA_ATTRIBUTES -from libcloud.dns.types import RecordType, ZoneDoesNotExistError -from libcloud.utils.py3 import httplib +from libcloud.dns.types import RecordType +from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError +from libcloud.utils.py3 import httplib, urlparse from libcloud.test.secrets import DNS_PARAMS_CLOUDFLARE from libcloud.test.file_fixtures import DNSFileFixtures from libcloud.test import MockHttp @@ -31,6 +33,9 @@ class CloudFlareDNSDriverTestCase(unittest.TestCase): def setUp(self): CloudFlareDNSDriver.connectionCls.conn_class = CloudFlareMockHttp + CloudFlareDNSDriver.ZONES_PAGE_SIZE = 5 + CloudFlareDNSDriver.RECORDS_PAGE_SIZE = 5 + CloudFlareDNSDriver.MEMBERSHIPS_PAGE_SIZE = 5 CloudFlareMockHttp.type = None CloudFlareMockHttp.use_param = 'a' self.driver = CloudFlareDNSDriver(*DNS_PARAMS_CLOUDFLARE) @@ -52,10 +57,26 @@ def test_list_zones(self): for attribute_name in ZONE_EXTRA_ATTRIBUTES: self.assertTrue(attribute_name in zone.extra) + def test_get_record(self): + record = self.driver.get_record('1234', '364797364') + + self.assertEqual(record.id, '364797364') + self.assertIsNone(record.name) + self.assertEqual(record.type, 'A') + self.assertEqual(record.data, '192.30.252.153') + + def test_get_record_record_doesnt_exist(self): + with self.assertRaises(RecordDoesNotExistError): + self.driver.get_record('1234', '0000') + + def test_get_record_record_is_invalid(self): + with self.assertRaises(LibcloudError): + self.driver.get_record('1234', 'invalid') + def test_list_records(self): zone = self.driver.list_zones()[0] records = self.driver.list_records(zone=zone) - self.assertEqual(len(records), 18) + self.assertEqual(len(records), 9) record = records[0] self.assertEqual(record.id, '364797364') @@ -82,28 +103,57 @@ def test_get_zone(self): self.assertEqual(zone.type, 'master') def test_get_zone_zone_doesnt_exist(self): - self.assertRaises(ZoneDoesNotExistError, self.driver.get_zone, - zone_id='doenstexist') + with self.assertRaises(ZoneDoesNotExistError): + self.driver.get_zone('0000') + + def test_get_zone_zone_is_invalid(self): + with self.assertRaises(LibcloudError): + self.driver.get_zone('invalid') def test_create_record(self): zone = self.driver.list_zones()[0] - record = self.driver.create_record(name='test5', zone=zone, type='A', - data='127.0.0.3') + record = self.driver.create_record(name='test5', zone=zone, + type=RecordType.A, + data='127.0.0.3', + extra={'proxied': True}) self.assertEqual(record.id, '412561327') self.assertEqual(record.name, 'test5') self.assertEqual(record.type, 'A') self.assertEqual(record.data, '127.0.0.3') - def test_update_records(self): + def test_create_record_with_property_that_cant_be_set(self): + zone = self.driver.list_zones()[0] + + record = self.driver.create_record(name='test5', zone=zone, + type=RecordType.A, + data='127.0.0.3', + extra={'locked': True}) + + self.assertNotEqual(record.extra['locked'], True) + + def test_update_record(self): zone = self.driver.list_zones()[0] record = zone.list_records()[0] updated_record = self.driver.update_record(record=record, - data='127.0.0.4') + name='test6', + type=RecordType.A, + data='127.0.0.4', + extra={'proxied': True}) self.assertEqual(updated_record.name, 'test6') self.assertEqual(updated_record.type, 'A') self.assertEqual(updated_record.data, '127.0.0.4') - self.assertEqual(updated_record.ttl, 120) + self.assertEqual(updated_record.extra['proxied'], True) + + def test_update_record_with_property_that_cant_be_updated(self): + zone = self.driver.list_zones()[0] + record = zone.list_records()[0] + + updated_record = self.driver.update_record(record=record, + data='127.0.0.4', + extra={'locked': True}) + + self.assertNotEqual(updated_record.extra['locked'], True) def test_delete_record(self): zone = self.driver.list_zones()[0] @@ -113,241 +163,143 @@ def test_delete_record(self): def test_delete_zone(self): zone = self.driver.list_zones()[0] - self.assertRaises(NotImplementedError, self.driver.delete_zone, - zone=zone) + result = self.driver.delete_zone(zone=zone) + self.assertTrue(result) - def test_ex_get_zone_stats(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_get_zone_stats(zone=zone) - self.assertTrue('trafficBreakdown' in result) - self.assertTrue('bandwidthServed' in result) - self.assertTrue('requestsServed' in result) - self.assertTrue('pro_zone' in result) - self.assertTrue('userSecuritySetting' in result) - - def test_ex_zone_check(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_zone_check(zones=[zone]) - self.assertEqual(result, {'example.com': 4025956}) + def test_create_zone(self): + zone = self.driver.create_zone(domain='example2.com', + extra={'jump_start': False}) + self.assertEqual(zone.id, '6789') + self.assertEqual(zone.domain, 'example2.com') - def test_ex_get_ip_threat_score(self): - result = self.driver.ex_get_ip_threat_score(ip='127.0.0.1') - self.assertEqual(result, {'127.0.0.1': False}) + def test_create_zone_with_explicit_account(self): + zone = self.driver.create_zone( + domain='example2.com', + extra={'account': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}) + self.assertEqual(zone.id, '6789') + self.assertEqual(zone.domain, 'example2.com') - def test_get_ex_zone_settings(self): + def test_update_zone(self): zone = self.driver.list_zones()[0] - result = self.driver.ex_get_zone_settings(zone=zone) - self.assertTrue('dnssec' in result) - self.assertTrue('ddos' in result) - self.assertTrue('email_filter' in result) - self.assertTrue('secureheader_settings' in result) - def test_ex_set_one_security_level(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_set_zone_security_level(zone=zone, level='med') - self.assertTrue(result) + updated_zone = self.driver.update_zone(zone=zone, + domain='', + extra={'paused': True}) - def test_ex_set_zone_cache_level(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_set_zone_cache_level(zone=zone, level='agg') - self.assertTrue(result) + self.assertEqual(zone.id, updated_zone.id) + self.assertEqual(zone.domain, updated_zone.domain) + self.assertEqual(zone.type, updated_zone.type) + self.assertEqual(zone.ttl, updated_zone.ttl) - def test_ex_enable_development_mode(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_enable_development_mode(zone=zone) - self.assertTrue(result) + for key in set(zone.extra) | set(updated_zone.extra): + if key in ('paused', 'modified_on'): + self.assertNotEqual(zone.extra[key], updated_zone.extra[key]) + else: + self.assertEqual(zone.extra[key], updated_zone.extra[key]) - def test_ex_disable_development_mode(self): + def test_update_zone_with_property_that_cant_be_updated(self): zone = self.driver.list_zones()[0] - result = self.driver.ex_disable_development_mode(zone=zone) - self.assertTrue(result) - def test_ex_purge_cached_files(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_purge_cached_files(zone=zone) - self.assertTrue(result) + updated_zone = self.driver.update_zone(zone, domain='', + extra={'owner': 'owner'}) - def test_ex_purge_cached_file(self): - zone = self.driver.list_zones()[0] - url = 'https://www.example.com/test.html' - result = self.driver.ex_purge_cached_file(zone=zone, url=url) - self.assertTrue(result) + self.assertEqual(zone, updated_zone) - def test_ex_whitelist_ip(self): + def test_update_zone_with_no_property(self): zone = self.driver.list_zones()[0] - ip = '127.0.0.1' - result = self.driver.ex_whitelist_ip(zone=zone, ip=ip) - self.assertTrue(result) - def test_ex_blacklist_ip(self): - zone = self.driver.list_zones()[0] - ip = '127.0.0.1' - result = self.driver.ex_blacklist_ip(zone=zone, ip=ip) - self.assertTrue(result) + updated_zone = self.driver.update_zone(zone, domain='', extra=None) - def test_ex_unlist_ip(self): - zone = self.driver.list_zones()[0] - ip = '127.0.0.1' - result = self.driver.ex_unlist_ip(zone=zone, ip=ip) - self.assertTrue(result) + self.assertEqual(zone, updated_zone) - def test_enable_ipv6_support(self): + def test_update_zone_with_more_than_one_property(self): zone = self.driver.list_zones()[0] - result = self.driver.ex_enable_development_mode(zone=zone) - self.assertTrue(result) - def test_ex_disable_ipv6_support(self): - zone = self.driver.list_zones()[0] - result = self.driver.ex_disable_development_mode(zone=zone) - self.assertTrue(result) + updated_zone = self.driver.update_zone( + zone, domain='', extra={'paused': True, 'plan': None}) + + self.assertEqual(zone, updated_zone) class CloudFlareMockHttp(MockHttp): fixtures = DNSFileFixtures('cloudflare') - def _api_json_html_zone_load_multi( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('zone_load_multi.json') - else: + def _client_v4_memberships(self, method, url, body, headers): + if method not in {'GET'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_rec_load_all( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('rec_load_all.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load('memberships_{}.json'.format(method)) - def _api_json_html_rec_new( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('rec_new.json') - else: - raise AssertionError('Unsupported method') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_rec_delete( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('rec_delete.json') - else: + def _client_v4_zones(self, method, url, body, headers): + if method not in {'GET', 'POST'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_rec_edit( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('rec_edit.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load('zones_{}.json'.format(method)) - def _api_json_html_stats( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('stats.json') - else: - raise AssertionError('Unsupported method') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_zone_check( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('zone_check.json') - else: + def _client_v4_zones_1234(self, method, url, body, headers): + if method not in {'GET', 'PATCH', 'DELETE'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_ip_lkup( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('ip_lkup.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load('zone_{}.json'.format(method)) - def _api_json_html_zone_settings( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('zone_settings.json') - else: - raise AssertionError('Unsupported method') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_sec_lvl( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('sec_lvl.json') - else: + def _client_v4_zones_0000(self, method, url, body, headers): + if method not in {'GET'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_cache_lvl( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('cache_lvl.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load('zone_{}_404.json'.format(method)) - def _api_json_html_devmode( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('devmode.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + return (httplib.NOT_FOUND, body, {}, httplib.responses[httplib.NOT_FOUND]) - def _api_json_html_fpurge_ts( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('fpurge_ts.json') - else: + def _client_v4_zones_invalid(self, method, url, body, headers): + if method not in {'GET'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_zone_file_purge( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('zone_file_purge.json') - else: + body = self.fixtures.load('zone_{}_400.json'.format(method)) + + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.BAD_REQUEST]) + + def _client_v4_zones_1234_dns_records(self, method, url, body, headers): + if method not in {'GET', 'POST'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_wl( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('wl.json') + url = urlparse.urlparse(url) + if method == 'GET' and url.query: + query = urlparse.parse_qs(url.query) + page = query['page'][0] + body = self.fixtures.load('records_{}_{}.json'.format(method, page)) else: - raise AssertionError('Unsupported method') + body = self.fixtures.load('records_{}.json'.format(method)) + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_ban( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('ban.json') - else: + def _client_v4_zones_1234_dns_records_0000(self, method, url, body, headers): + if method not in {'GET'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_nul( - self, method, url, body, headers): - if method == 'GET': - # Note: "nul" is a reserved filename on Window - body = self.fixtures.load('nul_.json') - else: + body = self.fixtures.load('record_{}_404.json'.format(method)) + + return (httplib.NOT_FOUND, body, {}, httplib.responses[httplib.NOT_FOUND]) + + def _client_v4_zones_1234_dns_records_invalid(self, method, url, body, headers): + if method not in {'GET'}: raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - def _api_json_html_ipv46( - self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('ipv46.json') - else: + body = self.fixtures.load('record_{}_400.json'.format(method)) + + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.BAD_REQUEST]) + + def _client_v4_zones_1234_dns_records_364797364(self, method, url, body, headers): + if method not in {'GET', 'PUT', 'DELETE'}: raise AssertionError('Unsupported method') + + body = self.fixtures.load('record_{}.json'.format(method)) + return (httplib.OK, body, {}, httplib.responses[httplib.OK])