http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/cloudflare.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/cloudflare.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/cloudflare.py deleted file mode 100644 index ee2d8eb..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/cloudflare.py +++ /dev/null @@ -1,429 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -__all__ = [ - 'CloudFlareDNSDriver' -] - -import copy - -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' -] - - -class CloudFlareDNSResponse(JsonResponse): - def success(self): - return self.status in [httplib.OK, httplib.CREATED, httplib.ACCEPTED] - - def parse_body(self): - body = super(CloudFlareDNSResponse, 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' - - context = self.connection.context or {} - context_record_id = context.get('record_id', None) - context_zone_domain = context.get('zone_domain', None) - - 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) - - 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) - - return body - - -class CloudFlareDNSConnection(ConnectionUserAndKey): - host = API_HOST - secure = True - responseCls = CloudFlareDNSResponse - - def request(self, action, params=None, data=None, headers=None, - method='GET'): - params = params or {} - data = data or {} - - base_params = { - 'email': self.user_id, - 'tkn': self.key, - 'a': action - } - params = copy.deepcopy(params) - params.update(base_params) - - return super(CloudFlareDNSConnection, self).request(action=API_PATH, - params=params, - data=None, - method=method, - headers=headers) - - -class CloudFlareDNSDriver(DNSDriver): - type = Provider.CLOUDFLARE - name = 'CloudFlare DNS' - website = 'https://www.cloudflare.com' - connectionCls = CloudFlareDNSConnection - - RECORD_TYPE_MAP = { - RecordType.A: 'A', - RecordType.AAAA: 'AAAA', - RecordType.CNAME: 'CNAME', - RecordType.MX: 'MX', - RecordType.TXT: 'TXT', - RecordType.SPF: 'SPF', - RecordType.NS: 'NS', - RecordType.SRV: 'SRV', - RecordType.URL: 'LOC' - } - - 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']) - - return zones - - 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 get_zone(self, zone_id): - # TODO: This is not efficient - zones = self.list_zones() - - try: - zone = [z for z in zones if z.id == zone_id][0] - except IndexError: - raise ZoneDoesNotExistError(value='', driver=self, zone_id=zone_id) - - return zone - - def create_record(self, name, zone, type, data, extra=None): - extra = extra or {} - params = {'name': name, 'z': zone.domain, 'type': type, - 'content': data} - - params['ttl'] = extra.get('ttl', 120) - - if 'priority' in extra: - # For MX and SRV records - params['prio'] = extra['priority'] - - 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} - - 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'] - - 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) - return record - - def delete_record(self, record): - params = {'z': record.zone.domain, 'id': record.id} - self.connection.set_context({'zone_domain': record.zone.domain}) - 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' - - 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 - - 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 - - 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 - - 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 - - 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' - - 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' - - 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' - - 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' - - 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' - - 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' - - 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' - - 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' - - 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' - - 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' - - 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 - - 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 - - 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 - - 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
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/digitalocean.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/digitalocean.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/digitalocean.py deleted file mode 100644 index ad8a297..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/digitalocean.py +++ /dev/null @@ -1,292 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Digital Ocean DNS Driver -""" - -__all__ = [ - 'DigitalOceanDNSDriver' -] - -from libcloud.utils.py3 import httplib - -from libcloud.common.digitalocean import DigitalOcean_v2_BaseDriver -from libcloud.common.digitalocean import DigitalOcean_v2_Connection -from libcloud.dns.types import Provider, RecordType -from libcloud.dns.base import DNSDriver, Zone, Record - - -class DigitalOceanDNSDriver(DigitalOcean_v2_BaseDriver, DNSDriver): - connectionCls = DigitalOcean_v2_Connection - type = Provider.DIGITAL_OCEAN - name = "DigitalOcean" - website = 'https://www.digitalocean.com' - - RECORD_TYPE_MAP = { - RecordType.NS: 'NS', - RecordType.A: 'A', - RecordType.AAAA: 'AAAA', - RecordType.CNAME: 'CNAME', - RecordType.MX: 'MX', - RecordType.TXT: 'TXT', - RecordType.SRV: 'SRV', - } - - def list_zones(self): - """ - Return a list of zones. - - :return: ``list`` of :class:`Zone` - """ - data = self._paginated_request('/v2/domains', 'domains') - return list(map(self._to_zone, data)) - - def list_records(self, zone): - """ - Return a list of records for the provided zone. - - :param zone: Zone to list records for. - :type zone: :class:`Zone` - - :return: ``list`` of :class:`Record` - """ - data = self._paginated_request('/v2/domains/%s/records' % (zone.id), - 'domain_records') -# TODO: Not use list comprehension to add zone to record for proper data map -# functionality? This passes a reference to zone for each data currently -# to _to_record which returns a Record. map() does not take keywords - return list(map(self._to_record, data, [zone for z in data])) - - def get_zone(self, zone_id): - """ - Return a Zone instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :rtype: :class:`Zone` - """ - data = self.connection.request('/v2/domains/%s' % - (zone_id)).object['domain'] - - return self._to_zone(data) - - def get_record(self, zone_id, record_id): - """ - Return a Record instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :param record_id: ID of the required record - :type record_id: ``str`` - - :rtype: :class:`Record` - """ - data = self.connection.request('/v2/domains/%s/records/%s' % (zone_id, - record_id)).object['domain_record'] - -# TODO: Any way of not using get_zone which polls the API again -# without breaking the DNSDriver.get_record parameters? - return self._to_record(data, self.get_zone(zone_id)) - - def create_zone(self, domain, type='master', ttl=None, extra=None): - """ - Create a new zone. - - :param domain: Zone domain name (e.g. example.com) - :type domain: ``str`` - - :param type: Zone type (master / slave) (does nothing). - :type type: ``str`` - - :param ttl: TTL for new records. (does nothing) - :type ttl: ``int`` - - :param extra: Extra attributes (to set ip). (optional) - Note: This can be used to set the default A record with - {"ip" : "IP.AD.DR.ESS"} otherwise 127.0.0.1 is used - :type extra: ``dict`` - - :rtype: :class:`Zone` - """ - params = {'name': domain} - try: - params['ip_address'] = extra['ip'] - except: - params['ip_address'] = '127.0.0.1' - - res = self.connection.request('/v2/domains', params=params, - method='POST') - - return Zone(id=res.object['domain']['name'], - domain=res.object['domain']['name'], - type='master', ttl=1800, driver=self, extra={}) - - def create_record(self, name, zone, type, data, extra=None): - """ - Create a new record. - - :param name: Record name without the domain name (e.g. www). - Note: If you want to create a record for a base domain - name, you should specify empty string ('') for this - argument. - :type name: ``str`` - - :param zone: Zone where the requested record is created. - :type zone: :class:`Zone` - - :param type: DNS record type (A, AAAA, ...). - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: Extra attributes for MX and SRV. (Depends on record) - {"priority" : 0, "port" : 443, "weight" : 100} - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - params = { - "type": self.RECORD_TYPE_MAP[type], - "name": name, - "data": data - } - if extra: - try: - params['priority'] = extra['priority'] - except KeyError: - params['priority'] = 'null' - try: - params['port'] = extra['port'] - except KeyError: - params['port'] = 'null' - try: - params['weight'] = extra['weight'] - except KeyError: - params['weight'] = 'null' - - res = self.connection.request('/v2/domains/%s/records' % zone.id, - params=params, - method='POST') - - return Record(id=res.object['domain_record']['id'], - name=res.object['domain_record']['name'], - type=type, data=data, zone=zone, - driver=self, extra=extra) - - def update_record(self, record, name=None, type=None, - data=None, extra=None): - """ - Update an existing record. - - :param record: Record to update. - :type record: :class:`Record` - - :param name: Record name without the domain name (e.g. www). (Ignored) - Note: The value is pulled from the record being updated - :type name: ``str`` - - :param type: DNS record type (A, AAAA, ...). (Ignored) - Note: Updating records does not support changing type - so this value is ignored - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - params = { - "type": record.type, - "name": record.name, - "data": data - } - if data is None: - params['data'] = record.data - if extra: - try: - params['priority'] = extra['priority'] - except KeyError: - params['priority'] = 'null' - try: - params['port'] = extra['port'] - except KeyError: - params['port'] = 'null' - try: - params['weight'] = extra['weight'] - except KeyError: - params['weight'] = 'null' - - res = self.connection.request('/v2/domains/%s/records/%s' % - (record.zone.id, record.id), - params=params, - method='PUT') - - return Record(id=res.object['domain_record']['id'], - name=res.object['domain_record']['name'], - type=record.type, data=data, zone=record.zone, - driver=self, extra=extra) - - def delete_zone(self, zone): - """ - Delete a zone. - - Note: This will delete all the records belonging to this zone. - - :param zone: Zone to delete. - :type zone: :class:`Zone` - - :rtype: ``bool`` - """ - params = {} - - res = self.connection.request('/v2/domains/%s' % zone.id, - params=params, method='DELETE') - - return res.status == httplib.NO_CONTENT - - def delete_record(self, record): - """ - Delete a record. - - :param record: Record to delete. - :type record: :class:`Record` - - :rtype: ``bool`` - """ - params = {} - - res = self.connection.request('/v2/domains/%s/records/%s' % ( - record.zone.id, record.id), - params=params, - method='DELETE') - return res.status == httplib.NO_CONTENT - - def _to_record(self, data, zone=None): - extra = {'port': data['port'], 'priority': data['priority'], - 'weight': data['weight']} - return Record(id=data['id'], name=data['name'], - type=self._string_to_record_type(data['type']), - data=data['data'], zone=zone, driver=self, extra=extra) - - def _to_zone(self, data): - extra = {'zone_file': data['zone_file']} - return Zone(id=data['name'], domain=data['name'], type='master', - ttl=data['ttl'], driver=self, extra=extra) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dnsimple.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dnsimple.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dnsimple.py deleted file mode 100644 index 7edbdfe..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dnsimple.py +++ /dev/null @@ -1,294 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -DNSimple DNS Driver -""" - -__all__ = [ - 'DNSimpleDNSDriver' -] - -try: - import simplejson as json -except ImportError: - import json - -from libcloud.common.dnsimple import DNSimpleDNSConnection -from libcloud.dns.types import Provider, RecordType -from libcloud.dns.base import DNSDriver, Zone, Record - - -DEFAULT_ZONE_TTL = 3600 - - -class DNSimpleDNSDriver(DNSDriver): - type = Provider.DNSIMPLE - name = 'DNSimple' - website = 'https://dnsimple.com/' - connectionCls = DNSimpleDNSConnection - - RECORD_TYPE_MAP = { - RecordType.A: 'A', - RecordType.AAAA: 'AAAA', - RecordType.ALIAS: 'ALIAS', - RecordType.CNAME: 'CNAME', - RecordType.HINFO: 'HINFO', - RecordType.MX: 'MX', - RecordType.NAPTR: 'NAPTR', - RecordType.NS: 'NS', - 'POOL': 'POOL', - RecordType.SOA: 'SOA', - RecordType.SPF: 'SPF', - RecordType.SRV: 'SRV', - RecordType.SSHFP: 'SSHFP', - RecordType.TXT: 'TXT', - RecordType.URL: 'URL' - } - - def list_zones(self): - """ - Return a list of zones. - - :return: ``list`` of :class:`Zone` - """ - response = self.connection.request('/v1/domains') - - zones = self._to_zones(response.object) - return zones - - def list_records(self, zone): - """ - Return a list of records for the provided zone. - - :param zone: Zone to list records for. - :type zone: :class:`Zone` - - :return: ``list`` of :class:`Record` - """ - response = self.connection.request('/v1/domains/%s/records' % zone.id) - records = self._to_records(response.object, zone) - return records - - def get_zone(self, zone_id): - """ - Return a Zone instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :rtype: :class:`Zone` - """ - response = self.connection.request('/v1/domains/%s' % zone_id) - zone = self._to_zone(response.object) - return zone - - def get_record(self, zone_id, record_id): - """ - Return a Record instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :param record_id: ID of the required record - :type record_id: ``str`` - - :rtype: :class:`Record` - """ - response = self.connection.request('/v1/domains/%s/records/%s' % - (zone_id, record_id)) - record = self._to_record(response.object, zone_id=zone_id) - return record - - def create_zone(self, domain, type='master', ttl=None, extra=None): - """ - Create a new zone. - - :param domain: Zone domain name (e.g. example.com) - :type domain: ``str`` - - :param type: Zone type (All zones are master by design). - :type type: ``str`` - - :param ttl: TTL for new records. (This is not really used) - :type ttl: ``int`` - - :param extra: Extra attributes (driver specific). (optional) - :type extra: ``dict`` - - :rtype: :class:`Zone` - - For more info, please see: - http://developer.dnsimple.com/v1/domains/ - """ - r_json = {'name': domain} - if extra is not None: - r_json.update(extra) - r_data = json.dumps({'domain': r_json}) - response = self.connection.request( - '/v1/domains', method='POST', data=r_data) - zone = self._to_zone(response.object) - return zone - - def create_record(self, name, zone, type, data, extra=None): - """ - Create a new record. - - :param name: Record name without the domain name (e.g. www). - Note: If you want to create a record for a base domain - name, you should specify empty string ('') for this - argument. - :type name: ``str`` - - :param zone: Zone where the requested record is created. - :type zone: :class:`Zone` - - :param type: DNS record type (A, AAAA, ...). - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: Extra attributes (driver specific). (optional) - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - r_json = {'name': name, 'record_type': type, 'content': data} - if extra is not None: - r_json.update(extra) - r_data = json.dumps({'record': r_json}) - response = self.connection.request('/v1/domains/%s/records' % zone.id, - method='POST', data=r_data) - record = self._to_record(response.object, zone=zone) - return record - - def update_record(self, record, name, type, data, extra=None): - """ - Update an existing record. - - :param record: Record to update. - :type record: :class:`Record` - - :param name: Record name without the domain name (e.g. www). - Note: If you want to create a record for a base domain - name, you should specify empty string ('') for this - argument. - :type name: ``str`` - - :param type: DNS record type (A, AAAA, ...). - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - zone = record.zone - r_json = {'name': name, 'content': data} - if extra is not None: - r_json.update(extra) - r_data = json.dumps({'record': r_json}) - response = self.connection.request('/v1/domains/%s/records/%s' % - (zone.id, record.id), - method='PUT', data=r_data) - record = self._to_record(response.object, zone=zone) - return record - - def delete_zone(self, zone): - """ - Delete a zone. - - Note: This will delete all the records belonging to this zone. - - :param zone: Zone to delete. - :type zone: :class:`Zone` - - :rtype: ``bool`` - """ - self.connection.request('/v1/domains/%s' % zone.id, method='DELETE') - return True - - def delete_record(self, record): - """ - Delete a record. - - :param record: Record to delete. - :type record: :class:`Record` - - :rtype: ``bool`` - """ - zone_id = record.zone.id - self.connection.request('/v1/domains/%s/records/%s' % (zone_id, - record.id), method='DELETE') - return True - - def _to_zones(self, data): - zones = [] - for zone in data: - _zone = self._to_zone(zone) - zones.append(_zone) - - return zones - - def _to_zone(self, data): - domain = data.get('domain') - id = domain.get('id') - name = domain.get('name') - extra = {'registrant_id': domain.get('registrant_id'), - 'user_id': domain.get('user_id'), - 'unicode_name': domain.get('unicode_name'), - 'token': domain.get('token'), - 'state': domain.get('state'), - 'language': domain.get('language'), - 'lockable': domain.get('lockable'), - 'auto_renew': domain.get('auto_renew'), - 'whois_protected': domain.get('whois_protected'), - 'record_count': domain.get('record_count'), - 'service_count': domain.get('service_count'), - 'expires_on': domain.get('expires_on'), - 'created_at': domain.get('created_at'), - 'updated_at': domain.get('updated_at')} - - # All zones are primary by design - type = 'master' - - return Zone(id=id, domain=name, type=type, ttl=DEFAULT_ZONE_TTL, - driver=self, extra=extra) - - def _to_records(self, data, zone): - records = [] - for item in data: - record = self._to_record(item, zone=zone) - records.append(record) - return records - - def _to_record(self, data, zone_id=None, zone=None): - if not zone: # We need zone_id or zone - zone = self.get_zone(zone_id) - record = data.get('record') - id = record.get('id') - name = record.get('name') - type = record.get('record_type') - data = record.get('content') - extra = {'ttl': record.get('ttl'), - 'created_at': record.get('created_at'), - 'updated_at': record.get('updated_at'), - 'domain_id': record.get('domain_id'), - 'priority': record.get('prio')} - return Record(id=id, name=name, type=type, data=data, zone=zone, - driver=self, ttl=record.get('ttl', None), extra=extra) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dummy.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dummy.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dummy.py deleted file mode 100644 index 5a1f4da..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/dummy.py +++ /dev/null @@ -1,218 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from libcloud.dns.base import DNSDriver, Zone, Record -from libcloud.dns.types import RecordType -from libcloud.dns.types import ZoneDoesNotExistError, ZoneAlreadyExistsError -from libcloud.dns.types import RecordDoesNotExistError -from libcloud.dns.types import RecordAlreadyExistsError - - -class DummyDNSDriver(DNSDriver): - """ - Dummy DNS driver. - - >>> from libcloud.dns.drivers.dummy import DummyDNSDriver - >>> driver = DummyDNSDriver('key', 'secret') - >>> driver.name - 'Dummy DNS Provider' - """ - - name = 'Dummy DNS Provider' - website = 'http://example.com' - - def __init__(self, api_key, api_secret): - """ - :param api_key: API key or username to used (required) - :type api_key: ``str`` - - :param api_secret: Secret password to be used (required) - :type api_secret: ``str`` - - :rtype: ``None`` - """ - self._zones = {} - - def list_record_types(self): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> driver.list_record_types() - ['A'] - - @inherits: :class:`DNSDriver.list_record_types` - """ - return [RecordType.A] - - def list_zones(self): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> driver.list_zones() - [] - - @inherits: :class:`DNSDriver.list_zones` - """ - - return [zone['zone'] for zone in list(self._zones.values())] - - def list_records(self, zone): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - >>> list(zone.list_records()) - [] - >>> record = driver.create_record(name='libcloud', zone=zone, - ... type=RecordType.A, data='127.0.0.1') - >>> list(zone.list_records()) #doctest: +ELLIPSIS - [<Record: zone=apache.org, name=libcloud, type=A...>] - """ - return self._zones[zone.id]['records'].values() - - def get_zone(self, zone_id): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> driver.get_zone(zone_id='foobar') - ... #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ZoneDoesNotExistError: - - @inherits: :class:`DNSDriver.get_zone` - """ - - if zone_id not in self._zones: - raise ZoneDoesNotExistError(driver=self, value=None, - zone_id=zone_id) - - return self._zones[zone_id]['zone'] - - def get_record(self, zone_id, record_id): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> driver.get_record(zone_id='doesnotexist', record_id='exists') - ... #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ZoneDoesNotExistError: - - @inherits: :class:`DNSDriver.get_record` - """ - - self.get_zone(zone_id=zone_id) - zone_records = self._zones[zone_id]['records'] - - if record_id not in zone_records: - raise RecordDoesNotExistError(record_id=record_id, value=None, - driver=self) - - return zone_records[record_id] - - def create_zone(self, domain, type='master', ttl=None, extra=None): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - >>> zone - <Zone: domain=apache.org, ttl=100, provider=Dummy DNS Provider ...> - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - ... #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ZoneAlreadyExistsError: - - @inherits: :class:`DNSDriver.create_zone` - """ - - id = 'id-%s' % (domain) - - if id in self._zones: - raise ZoneAlreadyExistsError(zone_id=id, value=None, driver=self) - - zone = Zone(id=id, domain=domain, type=type, ttl=ttl, extra={}, - driver=self) - self._zones[id] = {'zone': zone, - 'records': {}} - return zone - - def create_record(self, name, zone, type, data, extra=None): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - >>> record = driver.create_record(name='libcloud', zone=zone, - ... type=RecordType.A, data='127.0.0.1') - >>> record #doctest: +ELLIPSIS - <Record: zone=apache.org, name=libcloud, type=A, data=127.0.0.1...> - >>> record = driver.create_record(name='libcloud', zone=zone, - ... type=RecordType.A, data='127.0.0.1') - ... #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - RecordAlreadyExistsError: - - @inherits: :class:`DNSDriver.create_record` - """ - id = 'id-%s' % (name) - - zone = self.get_zone(zone_id=zone.id) - - if id in self._zones[zone.id]['records']: - raise RecordAlreadyExistsError(record_id=id, value=None, - driver=self) - - record = Record(id=id, name=name, type=type, data=data, extra=extra, - zone=zone, driver=self) - self._zones[zone.id]['records'][id] = record - return record - - def delete_zone(self, zone): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - >>> driver.delete_zone(zone) - True - >>> driver.delete_zone(zone) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ZoneDoesNotExistError: - - @inherits: :class:`DNSDriver.delete_zone` - """ - self.get_zone(zone_id=zone.id) - - del self._zones[zone.id] - return True - - def delete_record(self, record): - """ - >>> driver = DummyDNSDriver('key', 'secret') - >>> zone = driver.create_zone(domain='apache.org', type='master', - ... ttl=100) - >>> record = driver.create_record(name='libcloud', zone=zone, - ... type=RecordType.A, data='127.0.0.1') - >>> driver.delete_record(record) - True - >>> driver.delete_record(record) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - RecordDoesNotExistError: - - @inherits: :class:`DNSDriver.delete_record` - """ - self.get_record(zone_id=record.zone.id, record_id=record.id) - - del self._zones[record.zone.id]['records'][record.id] - return True - - -if __name__ == "__main__": - import doctest - doctest.testmod() http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/durabledns.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/durabledns.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/durabledns.py deleted file mode 100644 index 5d2fbe8..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/durabledns.py +++ /dev/null @@ -1,660 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -DurableDNS Driver -""" -import sys - -from libcloud.utils.py3 import httplib -from libcloud.utils.py3 import ensure_string -from libcloud.dns.types import Provider, RecordType -from libcloud.dns.base import Record, Zone -from libcloud.dns.base import DNSDriver -from libcloud.dns.types import ZoneDoesNotExistError, ZoneAlreadyExistsError -from libcloud.dns.types import RecordDoesNotExistError -from xml.etree.ElementTree import tostring -from libcloud.common.durabledns import DurableConnection, DurableResponse -from libcloud.common.durabledns import DurableDNSException -from libcloud.common.durabledns import _schema_builder as api_schema_builder -from libcloud.common.durabledns import SCHEMA_BUILDER_MAP - - -__all__ = [ - 'ZONE_EXTRA_PARAMS_DEFAULT_VALUES', - 'RECORD_EXTRA_PARAMS_DEFAULT_VALUES', - 'DEFAULT_TTL', - 'DurableDNSResponse', - 'DurableDNSConnection', - 'DurableDNSDriver' -] - -# This will be the default values for each extra attributes when are not -# specified in the 'extra' parameter -ZONE_EXTRA_PARAMS_DEFAULT_VALUES = { - 'ns': 'ns1.durabledns.com.', 'mbox': 'support.durabledns.com', - 'refresh': '28800', 'retry': 7200, 'expire': 604800, 'minimum': 82000, - 'xfer': '', 'update_acl': '' -} - -RECORD_EXTRA_PARAMS_DEFAULT_VALUES = {'aux': 0, 'ttl': 3600} - -DEFAULT_TTL = 3600 - - -class DurableDNSResponse(DurableResponse): - pass - - -class DurableDNSConnection(DurableConnection): - responseCls = DurableDNSResponse - - -class DurableDNSDriver(DNSDriver): - type = Provider.DURABLEDNS - name = 'DurableDNS' - website = 'https://durabledns.com' - connectionCls = DurableDNSConnection - - RECORD_TYPE_MAP = { - RecordType.A: 'A', - RecordType.AAAA: 'AAAA', - RecordType.CNAME: 'CNAME', - RecordType.HINFO: 'HINFO', - RecordType.MX: 'MX', - RecordType.NS: 'NS', - RecordType.PTR: 'PTR', - RecordType.RP: 'RP', - RecordType.SRV: 'SRV', - RecordType.TXT: 'TXT' - } - - def list_zones(self): - """ - Return a list of zones. - - :return: ``list`` of :class:`Zone` - """ - schema_params = SCHEMA_BUILDER_MAP.get('list_zones') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/listZones.php' - params = {} - headers = {"SOAPAction": "urn:listZoneswsdl#listZones"} - response = self.connection.request(action=action, params=params, - data=req_data, method="POST", - headers=headers) - # listZones method doens't return full data in zones as getZone - # method does. - zones = [] - for data in response.objects: - zone = self.get_zone(data.get('id')) - zones.append(zone) - return zones - - def list_records(self, zone): - """ - Return a list of records for the provided zone. - - :param zone: Zone to list records for. - :type zone: :class:`Zone` - - :return: ``list`` of :class:`Record` - """ - schema_params = SCHEMA_BUILDER_MAP.get('list_records') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone.id} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/listRecords.php?' - params = {} - headers = {"SOAPAction": "urn:listRecordswsdl#listRecords"} - try: - response = self.connection.request(action=action, params=params, - data=req_data, method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone.id, driver=self, - value=e.message) - raise e - - # listRecords method doens't return full data in records as getRecord - # method does. - records = [] - for data in response.objects: - record = self.get_record(zone.id, data.get('id')) - records.append(record) - - return records - - def get_zone(self, zone_id): - """ - Return a Zone instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :rtype: :class:`Zone` - """ - schema_params = SCHEMA_BUILDER_MAP.get('get_zone') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone_id} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/getZone.php?' - params = {} - headers = {"SOAPAction": "urn:getZonewsdl#getZone"} - try: - response = self.connection.request(action=action, params=params, - data=req_data, method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone_id, driver=self, - value=e.message) - raise e - - zones = self._to_zones(response.objects) - - return zones[0] - - def get_record(self, zone_id, record_id): - """ - Return a Record instance. - - :param zone_id: ID of the required zone - :type zone_id: ``str`` - - :param record_id: ID of the required record - :type record_id: ``str`` - - :rtype: :class:`Record` - """ - schema_params = SCHEMA_BUILDER_MAP.get('get_record') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone_id, 'recordid': record_id} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/getRecord.php?' - params = {} - headers = {"SOAPAction": "urn:getRecordwsdl#getRecord"} - try: - response = self.connection.request(action=action, params=params, - data=req_data, method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone_id, driver=self, - value=e.message) - if 'Record does not exist' in e.message: - raise RecordDoesNotExistError(record_id=record_id, driver=self, - value=e.message) - raise e - - zone = self.get_zone(zone_id) - record = self._to_record(response.objects[0], zone) - return record - - def create_zone(self, domain, type='master', ttl=None, extra=None): - """ - Create a new zone. - - :param domain: Name of zone, followed by a dot (.) (e.g. example.com.) - :type domain: ``str`` - - :param type: Zone type (Only master available). (optional) - :type type: ``str`` - - :param ttl: TTL for new records. (optional) - :type ttl: ``int`` - - :param extra: Extra attributes ('mbox', 'ns', 'minimum', 'refresh', - 'expire', 'update_acl', 'xfer'). - (optional) - :type extra: ``dict`` - - :rtype: :class:`Zone` - """ - if extra is None: - extra = ZONE_EXTRA_PARAMS_DEFAULT_VALUES - else: - extra_fields = ZONE_EXTRA_PARAMS_DEFAULT_VALUES.keys() - missing = set(extra_fields).difference(set(extra.keys())) - for field in missing: - extra[field] = ZONE_EXTRA_PARAMS_DEFAULT_VALUES.get(field) - schema_params = SCHEMA_BUILDER_MAP.get('create_zone') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': domain, 'ttl': ttl or DEFAULT_TTL} - params.update(extra) - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - if isinstance(params.get(key), int): - child.text = "%d" - else: - child.text = "%s" - # We can't insert values directly in child.text because API raises - # and exception for values that need to be integers. And tostring - # method from ElementTree can't handle int values. - skel = ensure_string(tostring(schema)) # Deal with PY3 - req_data = skel % (self.key, self.secret, domain, extra.get('ns'), - extra.get('mbox'), extra.get('refresh'), - extra.get('retry'), extra.get('expire'), - extra.get('minimum'), ttl or DEFAULT_TTL, - extra.get('xfer'), extra.get('update_acl')) - action = '/services/dns/createZone.php?' - params = {} - headers = {"SOAPAction": "urn:createZonewsdl#createZone"} - try: - self.connection.request(action=action, params=params, - data=req_data, method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone Already Exist' in e.message: - raise ZoneAlreadyExistsError(zone_id=domain, driver=self, - value=e.message) - raise e - - zone = self.get_zone(domain) - return zone - - def create_record(self, name, zone, type, data, extra=None): - """ - Create a new record. - - :param name: Record name without the domain name (e.g. www). - Note: If you want to create a record for a base domain - name, you should specify empty string ('') for this - argument. - :type name: ``str`` - - :param zone: Zone where the requested record is created. - :type zone: :class:`Zone` - - :param type: DNS record type (A, AAAA, ...). - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: Extra attributes (e.g. 'aux', 'ttl'). (optional) - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - if extra is None: - extra = RECORD_EXTRA_PARAMS_DEFAULT_VALUES - else: - if 'aux' not in extra: - extra['aux'] = RECORD_EXTRA_PARAMS_DEFAULT_VALUES.get('aux') - if 'ttl' not in extra: - extra['ttl'] = RECORD_EXTRA_PARAMS_DEFAULT_VALUES.get('ttl') - extra['ddns_enabled'] = 'N' - schema_params = SCHEMA_BUILDER_MAP.get('create_record') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone.id, 'name': name, 'type': type, - 'data': data} - params.update(extra) - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - if isinstance(params.get(key), int): - child.text = "%d" - else: - child.text = "%s" - # We can't insert values directly in child.text because API raises - # and exception for values that need to be integers. And tostring - # method from ElementTree can't handle int values. - skel = ensure_string(tostring(schema)) # Deal with PY3 - req_data = skel % (self.key, self.secret, zone.id, name, type, data, - extra.get('aux'), extra.get('ttl'), - extra.get('ddns_enabled')) - action = '/services/dns/createRecord.php?' - headers = {"SOAPAction": "urn:createRecordwsdl#createRecord"} - try: - response = self.connection.request(action=action, data=req_data, - method="POST", headers=headers) - objects = response.objects - except DurableDNSException: - e = sys.exc_info()[1] - # In DurableDNS is possible to create records with same data. - # Their ID's will be different but the API does not implement - # the RecordAlreadyExist exception. Only ZoneDoesNotExist will - # be handled. - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone.id, driver=self, - value=e.message) - raise e - - record_item = objects[0] - record_item['name'] = name - record_item['type'] = type - record_item['data'] = data - record_item['ttl'] = extra.get('ttl') - record_item['aux'] = extra.get('aux') - - record = self._to_record(record_item, zone) - return record - - def update_zone(self, zone, domain, type='master', ttl=None, extra=None): - """ - Update en existing zone. - - :param zone: Zone to update. - :type zone: :class:`Zone` - - :param domain: Name of zone, followed by a dot (.) (e.g. example.com.) - :type domain: ``str`` - - :param type: Zone type (master / slave). - :type type: ``str`` - - :param ttl: TTL for new records. (optional) - :type ttl: ``int`` - - :param extra: Extra attributes ('ns', 'mbox', 'refresh', 'retry', - 'expire', 'minimum', 'xfer', 'update_acl'). (optional) - :type extra: ``dict`` - - :rtype: :class:`Zone` - """ - if ttl is None: - ttl = zone.ttl - if extra is None: - extra = zone.extra - else: - extra_fields = ZONE_EXTRA_PARAMS_DEFAULT_VALUES.keys() - missing = set(extra_fields).difference(set(extra.keys())) - for field in missing: - extra[field] = zone.extra.get(field) - schema_params = SCHEMA_BUILDER_MAP.get('update_zone') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': domain, 'ttl': ttl} - params.update(extra) - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - if isinstance(params.get(key), int): - child.text = "%d" - else: - child.text = "%s" - # We can't insert values directly in child.text because API raises - # and exception for values that need to be integers. And tostring - # method from ElementTree can't handle int values. - skel = ensure_string(tostring(schema)) # Deal with PY3 - req_data = skel % (self.key, self.secret, domain, extra['ns'], - extra['mbox'], extra['refresh'], extra['retry'], - extra['expire'], extra['minimum'], ttl, - extra['xfer'], extra['update_acl']) - action = '/services/dns/updateZone.php?' - headers = {"SOAPAction": "urn:updateZonewsdl#updateZone"} - try: - self.connection.request(action=action, - data=req_data, - method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone.id, driver=self, - value=e.message) - raise e - - # After update the zone, serial number change. In order to have it - # updated, we need to get again the zone data. - zone = self.get_zone(zone.id) - return zone - - def update_record(self, record, name, type, data, extra=None): - """ - Update an existing record. - - :param record: Record to update. - :type record: :class:`Record` - - :param name: Record name without the domain name (e.g. www). - Note: If you want to create a record for a base domain - name, you should specify empty string ('') for this - argument. - :type name: ``str`` - - :param type: DNS record type (A, AAAA, ...). - :type type: :class:`RecordType` - - :param data: Data for the record (depends on the record type). - :type data: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: :class:`Record` - """ - zone = record.zone - if extra is None: - extra = record.extra - else: - extra_fields = ['aux', 'ttl'] - missing = set(extra_fields).difference(set(extra.keys())) - for field in missing: - extra[field] = record.extra.get(field) - extra['ddns_enabled'] = 'N' - schema_params = SCHEMA_BUILDER_MAP.get('update_record') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone.id, 'id': record.id, 'name': name, - 'data': data} - params.update(extra) - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - if isinstance(params.get(key), int): - child.text = "%d" - else: - child.text = "%s" - # We can't insert values directly in child.text because API raises - # and exception for values that need to be integers. And tostring - # method from ElementTree can't handle int values. - skel = ensure_string(tostring(schema)) # Deal with PY3 - req_data = skel % (self.key, self.secret, zone.id, record.id, name, - extra.get('aux'), data, extra.get('ttl'), - extra.get('ddns_enabled')) - action = '/services/dns/updateRecord.php?' - headers = {"SOAPAction": "urn:updateRecordwsdl#updateRecord"} - try: - self.connection.request(action=action, - data=req_data, - method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone.id, driver=self, - value=e.message) - raise e - - record_item = {} - record_item['id'] = record.id - record_item['name'] = name - record_item['type'] = type - record_item['data'] = data - record_item['ttl'] = extra.get('ttl') - record_item['aux'] = extra.get('aux') - record = self._to_record(record_item, zone) - return record - - def delete_zone(self, zone): - """ - Delete a zone. - - Note: This will delete all the records belonging to this zone. - - :param zone: Zone to delete. - :type zone: :class:`Zone` - - :rtype: ``bool`` - """ - schema_params = SCHEMA_BUILDER_MAP.get('delete_zone') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': zone.id} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/deleteZone.php?' - headers = {"SOAPAction": "urn:deleteZonewsdl#deleteZone"} - try: - response = self.connection.request(action=action, - data=req_data, method="POST", - headers=headers) - except DurableDNSException: - e = sys.exc_info()[1] - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=zone.id, driver=self, - value=e.message) - raise e - - return response.status in [httplib.OK] - - def delete_record(self, record): - """ - Delete a record. - - :param record: Record to delete. - :type record: :class:`Record` - - :rtype: ``bool`` - """ - schema_params = SCHEMA_BUILDER_MAP.get('delete_record') - attributes = schema_params.get('attributes') - schema = api_schema_builder(schema_params.get('urn_nid'), - schema_params.get('method'), - attributes) - params = {'apiuser': self.key, 'apikey': self.secret, - 'zonename': record.zone.id, 'id': record.id} - urn = schema.getchildren()[0] - for child in urn: - key = child.tag.split(':')[2] - if key in attributes: - child.text = str(params.get(key)) - req_data = tostring(schema) - action = '/services/dns/deleteRecord.php?' - headers = {"SOAPAction": "urn:deleteRecordwsdl#deleteRecord"} - try: - response = self.connection.request(action=action, data=req_data, - headers=headers, method="POST") - except DurableDNSException: - e = sys.exc_info()[1] - if 'Record does not exists' in e.message: - raise RecordDoesNotExistError(record_id=record.id, driver=self, - value=e.message) - if 'Zone does not exist' in e.message: - raise ZoneDoesNotExistError(zone_id=record.zone.id, - driver=self, value=e.message) - raise e - - return response.status in [httplib.OK] - - def _to_zone(self, item): - extra = item.get('extra') - # DurableDNS does not return information about zone type. This will be - # set as master by default. - zone = Zone(id=item.get('id'), type='master', domain=item.get('id'), - ttl=item.get('ttl'), driver=self, extra=extra) - - return zone - - def _to_zones(self, items): - zones = [] - for item in items: - zones.append(self._to_zone(item)) - - return zones - - def _to_record(self, item, zone=None): - extra = {'aux': int(item.get('aux')), 'ttl': int(item.get('ttl'))} - record = Record(id=item.get('id'), type=item.get('type'), zone=zone, - name=item.get('name'), data=item.get('data'), - driver=self, ttl=item.get('ttl', None), extra=extra) - - return record - - def _to_records(self, items, zone=None): - records = [] - for item in items: - records.append(self._to_record(item, zone)) - - return records http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/gandi.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/gandi.py b/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/gandi.py deleted file mode 100644 index 2014034..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/dns/drivers/gandi.py +++ /dev/null @@ -1,279 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import with_statement - -__all__ = [ - 'GandiDNSDriver' -] - -from libcloud.common.gandi import BaseGandiDriver, GandiConnection -from libcloud.common.gandi import GandiResponse -from libcloud.dns.types import Provider, RecordType -from libcloud.dns.types import RecordError -from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError -from libcloud.dns.base import DNSDriver, Zone, Record - - -TTL_MIN = 30 -TTL_MAX = 2592000 # 30 days - - -class NewZoneVersion(object): - """ - Changes to a zone in the Gandi DNS service need to be wrapped in a new - version object. The changes are made to the new version, then that - version is made active. - - In effect, this is a transaction. - - Any calls made inside this context manager will be applied to a new version - id. If your changes are successful (and only if they are successful) they - are activated. - """ - - def __init__(self, driver, zone): - self.driver = driver - self.connection = driver.connection - self.zone = zone - - def __enter__(self): - zid = int(self.zone.id) - self.connection.set_context({'zone_id': self.zone.id}) - vid = self.connection.request('domain.zone.version.new', zid).object - self.vid = vid - return vid - - def __exit__(self, type, value, traceback): - if not traceback: - zid = int(self.zone.id) - con = self.connection - con.set_context({'zone_id': self.zone.id}) - con.request('domain.zone.version.set', zid, self.vid).object - - -class GandiDNSResponse(GandiResponse): - exceptions = { - 581042: ZoneDoesNotExistError, - } - - -class GandiDNSConnection(GandiConnection): - responseCls = GandiDNSResponse - - -class GandiDNSDriver(BaseGandiDriver, DNSDriver): - """ - API reference can be found at: - - http://doc.rpc.gandi.net/domain/reference.html - """ - - type = Provider.GANDI - name = 'Gandi DNS' - website = 'http://www.gandi.net/domain' - - connectionCls = GandiDNSConnection - - RECORD_TYPE_MAP = { - RecordType.A: 'A', - RecordType.AAAA: 'AAAA', - RecordType.CNAME: 'CNAME', - RecordType.LOC: 'LOC', - RecordType.MX: 'MX', - RecordType.NS: 'NS', - RecordType.SPF: 'SPF', - RecordType.SRV: 'SRV', - RecordType.TXT: 'TXT', - RecordType.WKS: 'WKS', - } - - def _to_zone(self, zone): - return Zone( - id=str(zone['id']), - domain=zone['name'], - type='master', - ttl=0, - driver=self, - extra={} - ) - - def _to_zones(self, zones): - ret = [] - for z in zones: - ret.append(self._to_zone(z)) - return ret - - def list_zones(self): - zones = self.connection.request('domain.zone.list') - return self._to_zones(zones.object) - - def get_zone(self, zone_id): - zid = int(zone_id) - self.connection.set_context({'zone_id': zone_id}) - zone = self.connection.request('domain.zone.info', zid) - return self._to_zone(zone.object) - - def create_zone(self, domain, type='master', ttl=None, extra=None): - params = { - 'name': domain, - } - info = self.connection.request('domain.zone.create', params) - return self._to_zone(info.object) - - def update_zone(self, zone, domain=None, type=None, ttl=None, extra=None): - zid = int(zone.id) - params = {'name': domain} - self.connection.set_context({'zone_id': zone.id}) - zone = self.connection.request('domain.zone.update', zid, params) - return self._to_zone(zone.object) - - def delete_zone(self, zone): - zid = int(zone.id) - self.connection.set_context({'zone_id': zone.id}) - res = self.connection.request('domain.zone.delete', zid) - return res.object - - def _to_record(self, record, zone): - extra = {'ttl': int(record['ttl'])} - value = record['value'] - if record['type'] == 'MX': - # Record is in the following form: - # <priority> <value> - # e.g. 15 aspmx.l.google.com - split = record['value'].split(' ') - extra['priority'] = int(split[0]) - value = split[1] - return Record( - id='%s:%s' % (record['type'], record['name']), - name=record['name'], - type=self._string_to_record_type(record['type']), - data=value, - zone=zone, - driver=self, - ttl=record['ttl'], - extra=extra) - - def _to_records(self, records, zone): - retval = [] - for r in records: - retval.append(self._to_record(r, zone)) - return retval - - def list_records(self, zone): - zid = int(zone.id) - self.connection.set_context({'zone_id': zone.id}) - records = self.connection.request('domain.zone.record.list', zid, 0) - return self._to_records(records.object, zone) - - def get_record(self, zone_id, record_id): - zid = int(zone_id) - record_type, name = record_id.split(':', 1) - filter_opts = { - 'name': name, - 'type': record_type - } - self.connection.set_context({'zone_id': zone_id}) - records = self.connection.request('domain.zone.record.list', - zid, 0, filter_opts).object - - if len(records) == 0: - raise RecordDoesNotExistError(value='', driver=self, - record_id=record_id) - - return self._to_record(records[0], self.get_zone(zone_id)) - - def _validate_record(self, record_id, name, record_type, data, extra): - if len(data) > 1024: - raise RecordError('Record data must be <= 1024 characters', - driver=self, record_id=record_id) - if extra and 'ttl' in extra: - if extra['ttl'] < TTL_MIN: - raise RecordError('TTL must be at least 30 seconds', - driver=self, record_id=record_id) - if extra['ttl'] > TTL_MAX: - raise RecordError('TTL must not excdeed 30 days', - driver=self, record_id=record_id) - - def create_record(self, name, zone, type, data, extra=None): - self._validate_record(None, name, type, data, extra) - - zid = int(zone.id) - - create = { - 'name': name, - 'type': self.RECORD_TYPE_MAP[type], - 'value': data - } - - if 'ttl' in extra: - create['ttl'] = extra['ttl'] - - with NewZoneVersion(self, zone) as vid: - con = self.connection - con.set_context({'zone_id': zone.id}) - rec = con.request('domain.zone.record.add', - zid, vid, create).object - - return self._to_record(rec, zone) - - def update_record(self, record, name, type, data, extra): - self._validate_record(record.id, name, type, data, extra) - - filter_opts = { - 'name': record.name, - 'type': self.RECORD_TYPE_MAP[record.type] - } - - update = { - 'name': name, - 'type': self.RECORD_TYPE_MAP[type], - 'value': data - } - - if 'ttl' in extra: - update['ttl'] = extra['ttl'] - - zid = int(record.zone.id) - - with NewZoneVersion(self, record.zone) as vid: - con = self.connection - con.set_context({'zone_id': record.zone.id}) - con.request('domain.zone.record.delete', - zid, vid, filter_opts) - res = con.request('domain.zone.record.add', - zid, vid, update).object - - return self._to_record(res, record.zone) - - def delete_record(self, record): - zid = int(record.zone.id) - - filter_opts = { - 'name': record.name, - 'type': self.RECORD_TYPE_MAP[record.type] - } - - with NewZoneVersion(self, record.zone) as vid: - con = self.connection - con.set_context({'zone_id': record.zone.id}) - count = con.request('domain.zone.record.delete', - zid, vid, filter_opts).object - - if count == 1: - return True - - raise RecordDoesNotExistError(value='No such record', driver=self, - record_id=record.id)