From b7211349440dcaf1c2cb0e61d07680d14effe76e Mon Sep 17 00:00:00 2001 From: mhowes Date: Thu, 29 Sep 2016 14:51:30 -0400 Subject: [PATCH 01/38] Make sure forked instances have access to Crypto Random. --- dyn/encrypt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dyn/encrypt.py b/dyn/encrypt.py index 55d4130..148f1e1 100644 --- a/dyn/encrypt.py +++ b/dyn/encrypt.py @@ -55,6 +55,7 @@ def encrypt(self, raw): :param raw: The raw password string to encode """ raw = self._pad(raw) + Random.atfork() iv = Random.new().read(AES.block_size) cipher = AES.new(self.key, AES.MODE_CBC, iv) return base64.b64encode(iv + cipher.encrypt(raw)) From cac8c2ae300e0b9c280e3df1049ec99035a2aaef Mon Sep 17 00:00:00 2001 From: mhowes Date: Thu, 29 Sep 2016 16:26:04 -0400 Subject: [PATCH 02/38] version bump --- HISTORY.rst | 6 ++++++ dyn/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index f4a1514..ba37090 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,5 +1,11 @@ Release History --------------- + +1.7.6 (2016-09-29) +++++++++++++++++++ +*Bug fix for DSFNode export +*Internal Improvement for multiprocess applications. + 1.7.5 (2016-09-09) ++++++++++++++++++ *Bug fix for token renewal on connection timeout diff --git a/dyn/__init__.py b/dyn/__init__.py index d547996..ad025c7 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 5) +version_info = (1, 7, 6) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' From e76465946fbd76bc0c8d3ddabf87ff99e735d04e Mon Sep 17 00:00:00 2001 From: rshort Date: Tue, 11 Oct 2016 10:19:26 -0400 Subject: [PATCH 03/38] Add new field to DNSSECKey for multiple DS support --- HISTORY.rst | 4 ++++ dyn/__init__.py | 2 +- dyn/tm/services/dnssec.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index ba37090..5f094e6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,10 @@ Release History --------------- +1.7.7 (2016-10-20) +++++++++++++++++++ +*Add 'all_ds' field to DNSSECKey class for multi-DS support + 1.7.6 (2016-09-29) ++++++++++++++++++ *Bug fix for DSFNode export diff --git a/dyn/__init__.py b/dyn/__init__.py index ad025c7..2ae21ef 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 6) +version_info = (1, 7, 7) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' diff --git a/dyn/tm/services/dnssec.py b/dyn/tm/services/dnssec.py index 3f3dd80..1cffb0d 100644 --- a/dyn/tm/services/dnssec.py +++ b/dyn/tm/services/dnssec.py @@ -48,7 +48,7 @@ def __init__(self, key_type, algorithm, bits, start_ts=None, lifetime=None, self.lifetime = lifetime self.overlap = overlap self.expire_ts = expire_ts - self.dnssec_key_id = self.dnskey = self.ds = None + self.dnssec_key_id = self.dnskey = self.ds = self.all_ds = None for key, val in kwargs.items(): setattr(self, key, val) From 04a01cbe0aabb5b9e7915e4d1e82d1371b809dee Mon Sep 17 00:00:00 2001 From: rshort Date: Tue, 11 Oct 2016 10:29:24 -0400 Subject: [PATCH 04/38] Add param docstrings --- dyn/tm/services/dnssec.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dyn/tm/services/dnssec.py b/dyn/tm/services/dnssec.py index 1cffb0d..23f3e32 100644 --- a/dyn/tm/services/dnssec.py +++ b/dyn/tm/services/dnssec.py @@ -37,6 +37,11 @@ def __init__(self, key_type, algorithm, bits, start_ts=None, lifetime=None, :param overlap: Time before key expiration when a replacement key is prepared, expressed in seconds. Default = 7 days. :param expire_ts: An epoch time when this key is to expire + :param dnskey: The KSK or ZSK record data + :param ds: One of the DS records for the KSK. ZSKs will have this + value intialized, but with null values. + :param all_ds: All the DS records associated with this KSK. Applies + only to KSK, ZSK will have a zero-length list. """ super(DNSSECKey, self).__init__() self.key_type = key_type From 2fb8b33fd8ee3731ccb1e652983ace1af1694105 Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 17 Oct 2016 14:37:57 -0400 Subject: [PATCH 05/38] Adding Functionality for External Namerservers. --- dyn/tm/zones.py | 208 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 1 deletion(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index c824b8f..2a19ba7 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -23,7 +23,8 @@ from dyn.tm.task import Task __author__ = 'jnappi' -__all__ = ['get_all_zones', 'Zone', 'SecondaryZone', 'Node'] +__all__ = ['get_all_zones', 'Zone', 'SecondaryZone', 'Node', + 'ExternalNameserver', 'ExternalNameserverEntry'] RECS = {'A': ARecord, 'AAAA': AAAARecord, 'ALIAS': ALIASRecord, 'CDS': CDSRecord, 'CDNSKEY': CDNSKEYRecord, 'CSYNC': CSYNCRecord, @@ -1192,3 +1193,208 @@ def delete(self): api_args = {} DynectSession.get_session().execute(self.uri, 'DELETE', api_args) + + +class ExternalNameserver(object): + """A class representing DynECT External Nameserver """ + + def __init__(self, zone, *args, **kwargs): + """Create a :class:`ExternalNameserver` object + + :param zone: The name of the zone for this :class:`ExternalNameserver` + :param deny: does this block requests or add them + :param hosts: list of :class:`ExternalNameserverEntry` + :param active: active? Y/N + + """ + self._zone = zone + self.uri = '/ExtNameserver/{}/'.format(self._zone) + self._deny = None + self._hosts = None + self._active = None + + if len(args) == 0 and len(kwargs) == 0: + self._get() + else: + self._post(*args, **kwargs) + + def _get(self): + """Get a :class:`ExternalNameserver` object from the DynECT System""" + api_args = {'zone': self._zone} + response = DynectSession.get_session().execute(self.uri, 'GET', + api_args) + self._build(response['data']) + + def _post(self, *args, **kwargs): + """Create a new :class:`ExternalNameserver` object on the DynECT System""" + api_args = {'zone':self._zone} + self._deny = kwargs.get('deny',None) + if self._deny: api_args['deny'] = self._deny + + self._active = kwargs.get('active',None) + if self._active: api_args['active'] = self._active + + self._hosts = kwargs.get('hosts',None) + if self._hosts: + api_args['hosts'] = list() + for host in self._hosts: + if isinstance(host, ExternalNameserverEntry): + api_args['hosts'].append(host._json) + else: + api_args['hosts'].append(host) + response = DynectSession.get_session().execute(self.uri, 'POST', + api_args) + self._build(response['data']) + + def _update(self, api_args=None): + """Update an existing :class:`AdvancedRedirect` Service + on the DynECT System""" + response = DynectSession.get_session().execute(self.uri, 'PUT', + api_args) + self._build(response['data']) + + def _build(self, data): + self._hosts = [] + for key, val in data.items(): + if key == 'hosts': + for host in val: + host['api'] = 'Y' + self._hosts.append(ExternalNameserverEntry( + host['address'], notifies=host['notifies'])) + continue + setattr(self, '_' + key, val) + + @property + def deny(self): + """Gets deny value :class:`ExternalNameserver` object""" + self._get() + return self._deny + + @deny.setter + def deny(self, deny): + """ + Sets deny value of :class:`ExternalNameserver` object + :param deny: Y/N + """ + api_args = {'zone': self._zone, 'deny': deny} + response = DynectSession.get_session().execute(self.uri, 'PUT', + api_args) + for key, val in response['data'].items(): + setattr(self, '_' + key, val) + + @property + def hosts(self): + """ + :class:`ExternalNameserver` hosts. list of ExternalNameserverEntries + """ + self._get() + return [ExternalNameserverEntry(host['address'], host['notifies']) + for host in self._hosts] + + @hosts.setter + def hosts(self, value): + api_args = dict() + api_args['hosts'] = list() + for host in value: + if isinstance(host, ExternalNameserverEntry): + api_args['hosts'].append(host._json) + else: + api_args['hosts'].append(host) + self._update(api_args) + + + @property + def active(self): + """Gets active status of :class:`ExternalNameserver` object. """ + self._get() + return self._active + + @active.setter + def active(self, active): + """ + Sets active status of :class:`ExternalNameserver` object. + :param active: Y/N + """ + api_args = {'zone': self._zone, 'active': active} + response = DynectSession.get_session().execute(self.uri, 'PUT', + api_args) + for key, val in response['data'].items(): + setattr(self, '_' + key, val) + + @property + def zone(self): + """Gets name of zone in :class:`ExternalNameserver`""" + return self._zone + + def delete(self): + api_args = {} + DynectSession.get_session().execute(self.uri, 'DELETE', + api_args) + + +class ExternalNameserverEntry(object): + """A class representing DynECT :class:`ExternalNameserverEntry`""" + + def __init__(self, address, *args, **kwargs): + """Create a :class:`ExternalNameserverEntry` object + + :param address: address or CIDR of this nameserver Entry + :param notifies: Y/N Do we send notifies to this host? + + """ + self._address = address + self._notifies = kwargs.get('notifies',None) + + + @property + def _json(self): + """Get the JSON representation of this :class:`ExternalNameserverEntry` + object + """ + json_blob = {'address': self._address, + 'notifies': self._notifies, + } + return {x: json_blob[x] for x in json_blob if json_blob[x] is not None} + + + @property + def address(self): + """Gets address value :class:`ExternalNameserverEntry` object""" + return self._address + + + @address.setter + def address(self, address): + """ + Sets address of :class:`ExternalNameserverEntry` object + :param address: address or CIDR + """ + self._address = address + + + @property + def notifies(self): + """Gets address value :class:`ExternalNameserverEntry` object""" + return self._notifies + + + @notifies.setter + def notifies(self, notifies): + """ + Sets notifies of :class:`ExternalNameserverEntry` object + :param notifies: send notifies to this server. Y/N + """ + self._notifies = notifies + + def __str__(self): + """str override""" + return force_unicode( + ': {}, Notifies: {}').format( + self._address, + self._notifies) + + __repr__ = __unicode__ = __str__ + + def __bytes__(self): + """bytes override""" + return bytes(self.__str__()) From 3340248e1174614aab85647a3c1a5980caf8846c Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 17 Oct 2016 14:41:12 -0400 Subject: [PATCH 06/38] flake8 --- dyn/tm/zones.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index 2a19ba7..c3c4c83 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -821,7 +821,8 @@ def _build(self, data): @property def task(self): - """:class:`Task` for most recent system action on this :class:`SecondaryZone`. + """:class:`Task` for most recent system action + on this :class:`SecondaryZone`. """ if self._task_id: self._task_id.refresh() @@ -1226,15 +1227,18 @@ def _get(self): self._build(response['data']) def _post(self, *args, **kwargs): - """Create a new :class:`ExternalNameserver` object on the DynECT System""" - api_args = {'zone':self._zone} - self._deny = kwargs.get('deny',None) - if self._deny: api_args['deny'] = self._deny + """Create a new :class:`ExternalNameserver` + object on the DynECT System""" + api_args = {'zone': self._zone} + self._deny = kwargs.get('deny', None) + if self._deny: + api_args['deny'] = self._deny - self._active = kwargs.get('active',None) - if self._active: api_args['active'] = self._active + self._active = kwargs.get('active', None) + if self._active: + api_args['active'] = self._active - self._hosts = kwargs.get('hosts',None) + self._hosts = kwargs.get('hosts', None) if self._hosts: api_args['hosts'] = list() for host in self._hosts: @@ -1302,7 +1306,6 @@ def hosts(self, value): api_args['hosts'].append(host) self._update(api_args) - @property def active(self): """Gets active status of :class:`ExternalNameserver` object. """ @@ -1343,8 +1346,7 @@ def __init__(self, address, *args, **kwargs): """ self._address = address - self._notifies = kwargs.get('notifies',None) - + self._notifies = kwargs.get('notifies', None) @property def _json(self): @@ -1356,13 +1358,11 @@ def _json(self): } return {x: json_blob[x] for x in json_blob if json_blob[x] is not None} - @property def address(self): """Gets address value :class:`ExternalNameserverEntry` object""" return self._address - @address.setter def address(self, address): """ @@ -1371,13 +1371,11 @@ def address(self, address): """ self._address = address - @property def notifies(self): """Gets address value :class:`ExternalNameserverEntry` object""" return self._notifies - @notifies.setter def notifies(self, notifies): """ From 5a671f23e02e3095b9c9b926a61a47cab3e133ee Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 17 Oct 2016 14:44:40 -0400 Subject: [PATCH 07/38] update History. --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 5f094e6..f2a71e9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,6 +4,7 @@ Release History 1.7.7 (2016-10-20) ++++++++++++++++++ *Add 'all_ds' field to DNSSECKey class for multi-DS support +*Add `dyn.tm.zones.ExternalNamserver` and `dyn.tm.zones.ExternalNameserverEntry` 1.7.6 (2016-09-29) ++++++++++++++++++ From bcddce335f7aff85596058de8c607b96a04d88a9 Mon Sep 17 00:00:00 2001 From: rnorthover Date: Wed, 26 Oct 2016 13:30:38 -0400 Subject: [PATCH 08/38] Fixed a bug with external nameservers being treated as dicts instead of objects --- dyn/tm/zones.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index c3c4c83..30f33de 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -1292,8 +1292,7 @@ def hosts(self): :class:`ExternalNameserver` hosts. list of ExternalNameserverEntries """ self._get() - return [ExternalNameserverEntry(host['address'], host['notifies']) - for host in self._hosts] + return [ExternalNameserverEntry(host.address, host.notifies) for host in self._hosts] @hosts.setter def hosts(self, value): @@ -1346,16 +1345,14 @@ def __init__(self, address, *args, **kwargs): """ self._address = address - self._notifies = kwargs.get('notifies', None) + self._notifies = kwargs.get('notifies', 'N') @property def _json(self): """Get the JSON representation of this :class:`ExternalNameserverEntry` object """ - json_blob = {'address': self._address, - 'notifies': self._notifies, - } + json_blob = {'address': self._address, 'notifies': self._notifies} return {x: json_blob[x] for x in json_blob if json_blob[x] is not None} @property From 62d0971477df5ced2e605517e3aff02f26f93562 Mon Sep 17 00:00:00 2001 From: rnorthover Date: Wed, 26 Oct 2016 17:39:29 -0400 Subject: [PATCH 09/38] Return fresh attributes --- dyn/tm/zones.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index 30f33de..5ac4bae 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -1292,7 +1292,7 @@ def hosts(self): :class:`ExternalNameserver` hosts. list of ExternalNameserverEntries """ self._get() - return [ExternalNameserverEntry(host.address, host.notifies) for host in self._hosts] + return self._hosts @hosts.setter def hosts(self, value): @@ -1345,15 +1345,15 @@ def __init__(self, address, *args, **kwargs): """ self._address = address - self._notifies = kwargs.get('notifies', 'N') + self._notifies = kwargs.get('notifies') @property def _json(self): """Get the JSON representation of this :class:`ExternalNameserverEntry` object """ - json_blob = {'address': self._address, 'notifies': self._notifies} - return {x: json_blob[x] for x in json_blob if json_blob[x] is not None} + json_blob = {'address': self._address, 'notifies': self._notifies } + return {k: v for k, v in json_blob.items() if v is not None} @property def address(self): From 99ed745baffcacfacf7271227f36b88738cfd598 Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 31 Oct 2016 11:39:37 -0400 Subject: [PATCH 10/38] bump version, add History. --- HISTORY.rst | 4 ++++ dyn/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index f2a71e9..ac1d99b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,5 +1,9 @@ Release History --------------- +1.7.8 (2016-10-31) +*Minor Bugfixes to ExtNameServer. +*Advanced Redirect SDK calls (Beta) + 1.7.7 (2016-10-20) ++++++++++++++++++ diff --git a/dyn/__init__.py b/dyn/__init__.py index 2ae21ef..4751051 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 7) +version_info = (1, 7, 8) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' From d16eb664cb664bd3e814bc36cfb19c3b72212090 Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 31 Oct 2016 12:40:41 -0400 Subject: [PATCH 11/38] linter. --- dyn/tm/zones.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index 5ac4bae..398c1b1 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -1352,7 +1352,7 @@ def _json(self): """Get the JSON representation of this :class:`ExternalNameserverEntry` object """ - json_blob = {'address': self._address, 'notifies': self._notifies } + json_blob = {'address': self._address, 'notifies': self._notifies} return {k: v for k, v in json_blob.items() if v is not None} @property From 318c980e0fe072f003d5f6b7c0e9e72edfc5e1f7 Mon Sep 17 00:00:00 2001 From: Nick Sjostrom Date: Mon, 14 Nov 2016 16:58:07 -0500 Subject: [PATCH 12/38] Add publish parameter to delete methods and check implicitPublish. --- dyn/tm/services/dsf.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index df59591..1c5d91a 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -633,11 +633,15 @@ def implicit_publish(self, value): implicitPublish = implicit_publish # NOQA - def delete(self, notes=None): + def delete(self, notes=None, publish=True): """Delete this :class:`DSFRecord` :param notes: Optional zone publish notes + :param publish: Publish at run time. Default is True """ - api_args = {'publish': 'Y'} + api_args = {} + + if publish and self._implicitPublish: + api_args['publish'] = 'Y' if notes: api_args['notes'] = notes uri = '/DSFRecord/{}/{}'.format(self._service_id, self._dsf_record_id) @@ -2048,11 +2052,15 @@ def to_json(self, svc_id=None, skip_svc=False): json_blob['records'] = [] return json_blob - def delete(self, notes=None): + def delete(self, notes=None, publish=True): """Delete this :class:`DSFRecordSet` from the Dynect System :param notes: Optional zone publish notes + :param publish: Publish at run time. Default is True """ - api_args = {'publish': 'Y'} + api_args = {} + + if publish and self._implicitPublish: + api_args['publish'] = 'Y' if notes: api_args['notes'] = notes DynectSession.get_session().execute(self.uri, 'DELETE', api_args) @@ -2651,11 +2659,15 @@ def implicit_publish(self, value): implicitPublish = implicit_publish - def delete(self, notes=None): + def delete(self, notes=None, publish=True): """Delete this :class:`DSFResponsePool` from the DynECT System :param notes: Optional zone publish notes + :param publish: Publish at run time. Default is True """ - api_args = {'publish': 'Y'} + api_args = {} + + if publish and self._implicitPublish: + api_args['publish'] = 'Y' if notes: api_args['notes'] = notes DynectSession.get_session().execute(self.uri, 'DELETE', api_args) @@ -3039,12 +3051,16 @@ def _json(self, svc_id=None, skip_svc=False): return json_blob - def delete(self, notes=None): + def delete(self, notes=None, publish=True): """Remove this :class:`DSFRuleset` from it's associated :class:`TrafficDirector` Service :param notes: Optional zone publish notes + :param publish: Publish at run time. Default is True """ - api_args = {'publish': 'Y'} + api_args = {} + + if publish and self._implicitPublish: + api_args['publish'] = 'Y' if notes: api_args['notes'] = notes DynectSession.get_session().execute(self.uri, 'DELETE', api_args) From b079c88f70b7a8c662e06befebaa6da2f72fc944 Mon Sep 17 00:00:00 2001 From: Nick Sjostrom Date: Thu, 17 Nov 2016 15:16:40 -0500 Subject: [PATCH 13/38] Appease flake8 --- dyn/encrypt.py | 2 ++ dyn/tm/errors.py | 1 + 2 files changed, 3 insertions(+) diff --git a/dyn/encrypt.py b/dyn/encrypt.py index 148f1e1..e0257b2 100644 --- a/dyn/encrypt.py +++ b/dyn/encrypt.py @@ -29,6 +29,8 @@ def generate_key(force=False): key = ''.join([random.SystemRandom().choice(choices) for i in range(50)]) generate_key.secret_key = key return generate_key.secret_key + + generate_key.secret_key = None diff --git a/dyn/tm/errors.py b/dyn/tm/errors.py index cedd392..b434f60 100644 --- a/dyn/tm/errors.py +++ b/dyn/tm/errors.py @@ -142,6 +142,7 @@ def __repr__(self): def __str__(self): return self.message + ACTION_ERRORS = (DynectAuthError, DynectCreateError, DynectUpdateError, DynectGetError, DynectDeleteError) From 106a8ec57658553c09a48fb8b266dcdf4afa971d Mon Sep 17 00:00:00 2001 From: Nick Sjostrom Date: Fri, 18 Nov 2016 16:22:48 -0500 Subject: [PATCH 14/38] Add publish param and publish check to DSFFailoverChain --- dyn/tm/services/dsf.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 1c5d91a..88f307b 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -2350,11 +2350,15 @@ def implicit_publish(self, value): implicitPublish = implicit_publish - def delete(self, notes=None): + def delete(self, notes=None, publish=True): """Delete this :class:`DSFFailoverChain` from the Dynect System :param notes: Optional zone publish notes + :param publish: Publish at run time. Default is True """ - api_args = {'publish': 'Y'} + api_args = {} + + if publish and self._implicitPublish: + api_args['publish'] = 'Y' if notes: api_args['notes'] = notes DynectSession.get_session().execute(self.uri, 'DELETE', api_args) From 5ac936d297e2a3cfe43b5e60a10b0f3645e7e36f Mon Sep 17 00:00:00 2001 From: Nick Sjostrom Date: Wed, 23 Nov 2016 09:26:53 -0500 Subject: [PATCH 15/38] Version bump --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index 4751051..dc2f49d 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 8) +version_info = (1, 7, 9) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' From 48864750abeac10a31d1b5e951be7deace5a9a7e Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 28 Nov 2016 10:54:22 -0500 Subject: [PATCH 16/38] - Adding tsig names. - minor code cleanup --- dyn/tm/zones.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index ff5cf56..fbb39d5 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -1224,6 +1224,8 @@ def __init__(self, zone, *args, **kwargs): :param deny: does this block requests or add them :param hosts: list of :class:`ExternalNameserverEntry` :param active: active? Y/N + :param tsig_key_name: Name of TSIG to associate with this + :class:`ExternalNameserver` """ self._zone = zone @@ -1231,6 +1233,7 @@ def __init__(self, zone, *args, **kwargs): self._deny = None self._hosts = None self._active = None + self._tsig_key_name = None if len(args) == 0 and len(kwargs) == 0: self._get() @@ -1252,6 +1255,10 @@ def _post(self, *args, **kwargs): if self._deny: api_args['deny'] = self._deny + self._tsig_key_name = kwargs.get('tsig_key_name', None) + if self._tsig_key_name: + api_args['tsig_key_name'] = self._tsig_key_name + self._active = kwargs.get('active', None) if self._active: api_args['active'] = self._active @@ -1299,10 +1306,22 @@ def deny(self, deny): :param deny: Y/N """ api_args = {'zone': self._zone, 'deny': deny} - response = DynectSession.get_session().execute(self.uri, 'PUT', - api_args) - for key, val in response['data'].items(): - setattr(self, '_' + key, val) + self._update(api_args=api_args) + + @property + def tsig_key_name(self): + """Gets tsig_key_name value :class:`ExternalNameserver` object""" + self._get() + return self._tsig_key_name + + @tsig_key_name.setter + def tsig_key_name(self, tsig_key_name): + """ + Sets deny value of :class:`ExternalNameserver` object + :param deny: Y/N + """ + api_args = {'zone': self._zone, 'tsig_key_name': tsig_key_name} + self._update(api_args=api_args) @property def hosts(self): @@ -1336,10 +1355,7 @@ def active(self, active): :param active: Y/N """ api_args = {'zone': self._zone, 'active': active} - response = DynectSession.get_session().execute(self.uri, 'PUT', - api_args) - for key, val in response['data'].items(): - setattr(self, '_' + key, val) + self._update(api_args=api_args) @property def zone(self): From 73371460d721cd7b4647fd62fc806e79ebce0672 Mon Sep 17 00:00:00 2001 From: Nick Sjostrom Date: Mon, 28 Nov 2016 10:59:24 -0500 Subject: [PATCH 17/38] Update history with version changes. --- HISTORY.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index ac1d99b..ec5c796 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,14 @@ Release History --------------- + +1.7.9 (2016-11-28) +++++++++++++++++++ +*Add publish parameter to delete methods +*Check publish and implicitPublish for delete + + 1.7.8 (2016-10-31) +++++++++++++++++++ *Minor Bugfixes to ExtNameServer. *Advanced Redirect SDK calls (Beta) From 37812539ce03766a7efd53fff843ac49cd7865f8 Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 28 Nov 2016 11:18:33 -0500 Subject: [PATCH 18/38] Version Bump, History. --- HISTORY.rst | 4 ++++ dyn/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index ec5c796..70dfa5b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,10 @@ Release History --------------- +1.7.10 (2016-12-08) +++++++++++++++++++ +*TSIG names can now be attached to `dyn.tm.zones.ExternalNamserver` + 1.7.9 (2016-11-28) ++++++++++++++++++ *Add publish parameter to delete methods diff --git a/dyn/__init__.py b/dyn/__init__.py index dc2f49d..495dbbe 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 9) +version_info = (1, 7, 10) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' From fd26caafbed0c63c3f41681fe66fb8f1a7fe168b Mon Sep 17 00:00:00 2001 From: mhowes Date: Mon, 28 Nov 2016 13:57:36 -0500 Subject: [PATCH 19/38] We accept Elliptic Curve, so lets add that to the documentation. --- dyn/tm/services/dnssec.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dyn/tm/services/dnssec.py b/dyn/tm/services/dnssec.py index 23f3e32..c911bd9 100644 --- a/dyn/tm/services/dnssec.py +++ b/dyn/tm/services/dnssec.py @@ -30,8 +30,10 @@ def __init__(self, key_type, algorithm, bits, start_ts=None, lifetime=None, """Create a :class:`DNSSECKey` object :param key_type: The type of this key. (KSK or ZSK) - :param algorithm: One of (RSA/SHA-1, RSA/SHA-256, RSA/SHA-512, DSA) - :param bits: length of the key. Valid values: 1024, 2048, or 4096 + :param algorithm: One of (RSA/SHA-1, RSA/SHA-256, RSA/SHA-512, DSA, + ECDSAP256SHA256, ECDSAP384SHA384) + :param bits: length of the key. Valid values: 256, 384, 1024, 2048, + or 4096 :param start_ts: An epoch time when key is to be valid :param lifetime: Lifetime of the key expressed in seconds :param overlap: Time before key expiration when a replacement key is From 7828bf8626ae61e2b9c4d7d4cbbbdb925211e683 Mon Sep 17 00:00:00 2001 From: ChrisArgyle Date: Thu, 23 Feb 2017 15:41:47 -0500 Subject: [PATCH 20/38] Fix incorrect FQDN returned by Zone.get_all_httpredirect() * function was using parent zone as FQDN instead of the FQDN returned by API --- dyn/tm/zones.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index fbb39d5..cdfe914 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -635,10 +635,11 @@ def get_all_httpredirect(self): response = DynectSession.get_session().execute(uri, 'GET', api_args) httpredirs = [] for httpredir in response['data']: + fqdn = httpredir['fqdn'] del httpredir['zone'] del httpredir['fqdn'] httpredirs.append( - HTTPRedirect(self._name, self._fqdn, api=False, **httpredir)) + HTTPRedirect(self._name, fqdn, api=False, **httpredir)) return httpredirs def get_all_advanced_redirect(self): From 12a6fedbf3dbc2cda751e398dc83802ec339b3a2 Mon Sep 17 00:00:00 2001 From: rnorthover Date: Fri, 7 Apr 2017 16:01:41 -0400 Subject: [PATCH 21/38] Initial code changes for CAA record type. Comments to follow. --- dyn/tm/records.py | 111 +++++++++++++++++++++++++++++++++++++++-- dyn/tm/services/dsf.py | 4 +- dyn/tm/zones.py | 38 +++++++------- 3 files changed, 128 insertions(+), 25 deletions(-) diff --git a/dyn/tm/records.py b/dyn/tm/records.py index 4ac1888..c85d42c 100644 --- a/dyn/tm/records.py +++ b/dyn/tm/records.py @@ -9,11 +9,11 @@ from ..compat import force_unicode __author__ = 'jnappi' -__all__ = ['DNSRecord', 'ARecord', 'AAAARecord', 'ALIASRecord', 'CDSRecord', - 'CDNSKEYRecord', 'CERTRecord', 'CNAMERecord', 'CSYNCRecord', - 'DHCIDRecord', 'DNAMERecord', 'DNSKEYRecord', 'DSRecord', - 'KEYRecord', 'KXRecord', 'LOCRecord', 'IPSECKEYRecord', 'MXRecord', - 'NAPTRRecord', 'PTRRecord', 'PXRecord', 'NSAPRecord', +__all__ = ['DNSRecord', 'ARecord', 'AAAARecord', 'ALIASRecord', 'CAARecord', + 'CDSRecord', 'CDNSKEYRecord', 'CERTRecord', 'CNAMERecord', + 'CSYNCRecord', 'DHCIDRecord', 'DNAMERecord', 'DNSKEYRecord', + 'DSRecord', 'KEYRecord', 'KXRecord', 'LOCRecord', 'IPSECKEYRecord', + 'MXRecord', 'NAPTRRecord', 'PTRRecord', 'PXRecord', 'NSAPRecord', 'RPRecord', 'NSRecord', 'SOARecord', 'SPFRecord', 'SRVRecord', 'TLSARecord', 'TXTRecord', 'SSHFPRecord', 'UNKNOWNRecord'] @@ -1239,6 +1239,107 @@ def __repr__(self): """print override""" return self.__str__() +class CAARecord(DNSRecord): + """ + """ + + def __init__(self, zone, fqdn, *args, **kwargs): + """Create a :class:`~dyn.tm.records.CAARecord` object + + :param zone: Name of zone where the record will be added + :param fqdn: Name of node where the record will be added + :param flags: A byte + :param tag: A string defining the tag component of the = + record property. May be one of: + issue: The issue property entry authorizes the holder of + the domain name or a party acting under + the explicit authority of the holder of that domain name to + issue certificates for the domain in which the property is + published. + + issuewild: The issuewild property entry authorizes the + holder of the domain name or a party + acting under the explicit authority of the holder of that + domain name to issue wildcard certificates for the domain in + which the property is published. + + iodef: Specifies a URL to which an issuer MAY report + certificate issue requests that are inconsistent with the + issuer's Certification Practices or Certificate Policy, or + that a Certificate Evaluator may use to report observation + of a possible policy violation. + :param value: A string representing the value component of the property. + This will be an issuer domain name or a URL. + :param ttl: TTL for this record. Use 0 for zone default + """ + fields = ['flags', 'tag', 'value', 'ttl'] + + create = kwargs.pop('create', None) + if create is not None: + super(CAARecord, self).__init__(zone, fqdn, create) + self._build(kwargs) + self._record_type = 'CAARecord' + else: + super(CAARecord, self).__init__(zone, fqdn) + self._record_type = 'CAARecord' + arg_length = len(args) + len(kwargs) + if 'record_id' in kwargs: + self._get_record(kwargs['record_id']) + elif arg_length == 1: + self._get_record(*args, **kwargs) + elif any(field in kwargs for field in fields) or arg_length >= 1: + self._post(*args, **kwargs) + + def _post(self, flags, tag, value, ttl=0): + self._flags = flags + self._tag = tag + self._value = value + self._ttl = ttl + self.api_args = dict( + rdata=dict(flags=flags, tag=tag, value=value), + ttl=ttl + ) + self._create_record(self.api_args) + + def rdata(self): + return dict(caa_rdata=super(CAARecord, self).rdata()) + + @property + def flags(self): + self.pull() + return self._flags + + @flags.setter + def flags(self, value): + self.api_args['rdata']['flags'] = value + self._update_record(self.api_args) + if self._implicitPublish: + self._flags = value + + @property + def tag(self): + self.pull() + return self._tag + + @tag.setter + def tag(self, value): + self.api_args['rdata']['tag'] = value + self._update_record(self.api_args) + if self._implicitPublish: + self._tag = value + + @property + def value(self): + self.pull() + return self._value + + @value.setter + def value(self, value): + self.api_args['rdata']['value'] = value + self._update_record(self.api_args) + if self._implicitPublish: + self._value = value + class DSRecord(DNSRecord): """The Delegation Signer (DS) record type is used in DNSSEC to create the diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 88f307b..89e1149 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -6,8 +6,8 @@ from dyn.compat import force_unicode, string_types from dyn.tm.utils import APIList, Active from dyn.tm.errors import DynectInvalidArgumentError -from dyn.tm.records import (ARecord, AAAARecord, ALIASRecord, CDSRecord, - CDNSKEYRecord, CSYNCRecord, CERTRecord, +from dyn.tm.records import (ARecord, AAAARecord, ALIASRecord, CAARecord, + CDSRecord, CDNSKEYRecord, CSYNCRecord, CERTRecord, CNAMERecord, DHCIDRecord, DNAMERecord, DNSKEYRecord, DSRecord, KEYRecord, KXRecord, LOCRecord, IPSECKEYRecord, MXRecord, NAPTRRecord, diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index fbb39d5..d18bce8 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -9,7 +9,7 @@ from dyn.tm.errors import (DynectCreateError, DynectGetError, DynectInvalidArgumentError) from dyn.tm.records import (ARecord, AAAARecord, ALIASRecord, CDSRecord, - CDNSKEYRecord, CSYNCRecord, CERTRecord, + CAA, CDNSKEYRecord, CSYNCRecord, CERTRecord, CNAMERecord, DHCIDRecord, DNAMERecord, DNSKEYRecord, DSRecord, KEYRecord, KXRecord, LOCRecord, IPSECKEYRecord, MXRecord, NAPTRRecord, @@ -27,15 +27,15 @@ 'ExternalNameserver', 'ExternalNameserverEntry'] RECS = {'A': ARecord, 'AAAA': AAAARecord, 'ALIAS': ALIASRecord, - 'CDS': CDSRecord, 'CDNSKEY': CDNSKEYRecord, 'CSYNC': CSYNCRecord, - 'CERT': CERTRecord, 'CNAME': CNAMERecord, 'DHCID': DHCIDRecord, - 'DNAME': DNAMERecord, 'DNSKEY': DNSKEYRecord, 'DS': DSRecord, - 'KEY': KEYRecord, 'KX': KXRecord, 'LOC': LOCRecord, + 'CAA': CAARecord, 'CDS': CDSRecord, 'CDNSKEY': CDNSKEYRecord, + 'CSYNC': CSYNCRecord, 'CERT': CERTRecord, 'CNAME': CNAMERecord, + 'DHCID': DHCIDRecord, 'DNAME': DNAMERecord, 'DNSKEY': DNSKEYRecord, + 'DS': DSRecord, 'KEY': KEYRecord, 'KX': KXRecord, 'LOC': LOCRecord, 'IPSECKEY': IPSECKEYRecord, 'MX': MXRecord, 'NAPTR': NAPTRRecord, 'PTR': PTRRecord, 'PX': PXRecord, 'NSAP': NSAPRecord, - 'RP': RPRecord, 'NS': NSRecord, 'SOA': SOARecord, - 'SPF': SPFRecord, 'SRV': SRVRecord, 'TLSA': TLSARecord, - 'TXT': TXTRecord, 'SSHFP': SSHFPRecord, 'UNKNOWN': UNKNOWNRecord} + 'RP': RPRecord, 'NS': NSRecord, 'SOA': SOARecord, 'SPF': SPFRecord, + 'SRV': SRVRecord, 'TLSA': TLSARecord, 'TXT': TXTRecord, + 'SSHFP': SSHFPRecord, 'UNKNOWN': UNKNOWNRecord} def get_all_zones(): @@ -522,14 +522,14 @@ def get_all_records_by_type(self, record_type): are owned by this node. :param record_type: The type of :class:`DNSRecord` you wish returned. - Valid record_type arguments are: 'A', 'AAAA', 'CERT', 'CNAME', + Valid record_type arguments are: 'A', 'AAAA', 'CAA', 'CERT', 'CNAME', 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', 'IPSECKEY', 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', 'SPF', 'SRV', and 'TXT'. :return: A :class:`List` of :class:`DNSRecord`'s """ names = {'A': 'ARecord', 'AAAA': 'AAAARecord', 'ALIAS': 'ALIASRecord', - 'CDS': 'CDSRecord', 'CDNSKEY': 'CDNSKEYRecord', + 'CAA': 'CAARecord', 'CDS': 'CDSRecord', 'CDNSKEY': 'CDNSKEYRecord', 'CERT': 'CERTRecord', 'CSYNC': 'CSYNCRecord', 'CNAME': 'CNAMERecord', 'DHCID': 'DHCIDRecord', 'DNAME': 'DNAMERecord', 'DNSKEY': 'DNSKEYRecord', @@ -1052,16 +1052,18 @@ def get_all_records_by_type(self, record_type): 'SRV', and 'TXT'. :return: A list of :class:`DNSRecord`'s """ - names = {'A': 'ARecord', 'AAAA': 'AAAARecord', 'CERT': 'CERTRecord', - 'CNAME': 'CNAMERecord', 'DHCID': 'DHCIDRecord', - 'DNAME': 'DNAMERecord', 'DNSKEY': 'DNSKEYRecord', - 'DS': 'DSRecord', 'KEY': 'KEYRecord', 'KX': 'KXRecord', - 'LOC': 'LOCRecord', 'IPSECKEY': 'IPSECKEYRecord', - 'MX': 'MXRecord', 'NAPTR': 'NAPTRRecord', 'PTR': 'PTRRecord', + names = {'A': 'ARecord', 'AAAA': 'AAAARecord', 'CAA': 'CAARecord', + 'CERT': 'CERTRecord', 'CNAME': 'CNAMERecord', + 'DHCID': 'DHCIDRecord', 'DNAME': 'DNAMERecord', + 'DNSKEY': 'DNSKEYRecord', 'DS': 'DSRecord', + 'KEY': 'KEYRecord', 'KX': 'KXRecord', 'LOC': 'LOCRecord', + 'IPSECKEY': 'IPSECKEYRecord', 'MX': 'MXRecord', + 'NAPTR': 'NAPTRRecord', 'PTR': 'PTRRecord', 'PX': 'PXRecord', 'NSAP': 'NSAPRecord', 'RP': 'RPRecord', 'NS': 'NSRecord', 'SOA': 'SOARecord', 'SPF': 'SPFRecord', - 'SRV': 'SRVRecord', 'TLSA': 'TLSARecord', 'TXT': 'TXTRecord', - 'SSHFP': 'SSHFPRecord', 'ALIAS': 'ALIASRecord'} + 'SRV': 'SRVRecord', 'TLSA': 'TLSARecord', + 'TXT': 'TXTRecord', 'SSHFP': 'SSHFPRecord', + 'ALIAS': 'ALIASRecord'} constructor = RECS[record_type] uri = '/{}/{}/{}/'.format(names[record_type], self.zone, self.fqdn) From c2c31d58a4ba080b2f2a3c217ec50eedfce86fde Mon Sep 17 00:00:00 2001 From: rnorthover Date: Mon, 10 Apr 2017 16:39:25 -0400 Subject: [PATCH 22/38] CAA record support and documentation Additionally: * Exponential backoff and retry logic for `blocked` tasks * Automatic retry after 5 seconds for throttled jobs --- docs/tm/records/records.rst | 6 +++++ dyn/core.py | 53 ++++++++++++++++++++++++++++++++----- dyn/tm/records.py | 17 +++++++++--- dyn/tm/zones.py | 2 +- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/docs/tm/records/records.rst b/docs/tm/records/records.rst index 1eaa080..f9a83e1 100644 --- a/docs/tm/records/records.rst +++ b/docs/tm/records/records.rst @@ -18,6 +18,12 @@ ALIASRecord :members: :undoc-members: +CAARecord +========== +.. autoclass:: dyn.tm.records.CAARecord + :members: + :undoc-members: + CERTRecord ========== .. autoclass:: dyn.tm.records.CERTRecord diff --git a/dyn/core.py b/dyn/core.py index 53508e9..c6d71af 100644 --- a/dyn/core.py +++ b/dyn/core.py @@ -6,10 +6,11 @@ """ import base64 import copy -import time import locale import logging +import re import threading +import time from datetime import datetime from . import __version__ @@ -114,6 +115,7 @@ def __init__(self, host=None, port=443, ssl=True, history=False, self._encoding = locale.getdefaultlocale()[-1] or 'UTF-8' self._token = self._conn = self._last_response = None self._permissions = None + self._tasks = {} @classmethod def new_session(cls, *args, **kwargs): @@ -243,6 +245,40 @@ def _handle_error(self, uri, method, raw_args): """ return None + def _retry(self, msgs, final=False): + """Retry logic around throttled or blocked tasks""" + + throttle_err = 'RATE_LIMIT_EXCEEDED' + throttled = any(throttle_err == err['ERR_CD'] for err in msgs) + + if throttled: + # We're rate limited, so wait 5 seconds and try again + return dict(retry=True, wait=5, final=final) + + blocked_err = 'Operation blocked by current task' + blocked = any(blocked_err in err['INFO'] for err in msgs) + + pat = re.compile(r'^task_id:\s+(\d+)$') + if blocked: + try: + # Get the task id + task = next(pat.match(i['INFO']).group(1) for i in msgs + if pat.match(i.get('INFO', ''))) + except: + # Task id could not be recovered + wait = 1 + else: + # Exponential backoff for individual blocked tasks + wait = self._tasks.get(task, 1) + self._tasks[task] = wait * 2 + 1 + + # Give up if final or wait > 30 seconds + return dict(retry=True, wait=wait, final=wait > 30 or final) + + # Neither blocked nor throttled? + return dict(retry=False, wait=0, final=True) + + def _handle_response(self, response, uri, method, raw_args, final): """Handle the processing of the API's response""" body = response.read() @@ -258,12 +294,15 @@ def _handle_response(self, response, uri, method, raw_args, final): ret_val['status'])) self._meta_update(uri, method, ret_val) - # Handle retrying if ZoneProp is blocking the current task - error_msg = 'Operation blocked by current task' - if ret_val['status'] == 'failure' and error_msg in \ - ret_val['msgs'][0]['INFO'] and not final: - time.sleep(8) - return self.execute(uri, method, raw_args, final=True) + + retry = {} + # Try to retry? + if ret_val['status'] == 'failure' and not final: + retry = self._retry(ret_val['msgs'], final) + + if retry.get('retry', False): + time.sleep(retry['wait']) + return self.execute(uri, method, raw_args, final=retry['final']) else: return self._process_response(ret_val, method) diff --git a/dyn/tm/records.py b/dyn/tm/records.py index c85d42c..e8ed842 100644 --- a/dyn/tm/records.py +++ b/dyn/tm/records.py @@ -1240,7 +1240,16 @@ def __repr__(self): return self.__str__() class CAARecord(DNSRecord): - """ + """Certification Authority Authorization (CAA) Resource Record + + This record allows a DNS domain name holder to specify one or more + Certification Authorities (CAs) authorized to issue certificates for that + domain. CAA Resource Records allow a public Certification Authority to + implement additional controls to reduce the risk of unintended certificate + mis-issue. This document defines the syntax of the CAA record and rules for + processing CAA records by certificate issuers. + + see: https://tools.ietf.org/html/rfc6844 """ def __init__(self, zone, fqdn, *args, **kwargs): @@ -1306,7 +1315,7 @@ def rdata(self): @property def flags(self): - self.pull() + self._pull() return self._flags @flags.setter @@ -1318,7 +1327,7 @@ def flags(self, value): @property def tag(self): - self.pull() + self._pull() return self._tag @tag.setter @@ -1330,7 +1339,7 @@ def tag(self, value): @property def value(self): - self.pull() + self._pull() return self._value @value.setter diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index d18bce8..55c23bd 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -9,7 +9,7 @@ from dyn.tm.errors import (DynectCreateError, DynectGetError, DynectInvalidArgumentError) from dyn.tm.records import (ARecord, AAAARecord, ALIASRecord, CDSRecord, - CAA, CDNSKEYRecord, CSYNCRecord, CERTRecord, + CAARecord, CDNSKEYRecord, CSYNCRecord, CERTRecord, CNAMERecord, DHCIDRecord, DNAMERecord, DNSKEYRecord, DSRecord, KEYRecord, KXRecord, LOCRecord, IPSECKEYRecord, MXRecord, NAPTRRecord, From 25a54018ee55945fd650416ff8a6534b4cb75f9d Mon Sep 17 00:00:00 2001 From: rnorthover Date: Mon, 31 Jul 2017 13:54:16 -0400 Subject: [PATCH 23/38] Add CAA to dsf record types. Fixes unused import. --- dyn/tm/services/dsf.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 89e1149..18ad05d 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -3578,7 +3578,7 @@ def __init__(self, zone, fqdn=None): self.records = {} self.recs = {'A': ARecord, 'AAAA': AAAARecord, - 'ALIAS': ALIASRecord, 'CDS': CDSRecord, + 'ALIAS': ALIASRecord, 'CAA': CAARecord, 'CDS': CDSRecord, 'CDNSKEY': CDNSKEYRecord, 'CSYNC': CSYNCRecord, 'CERT': CERTRecord, 'CNAME': CNAMERecord, 'DHCID': DHCIDRecord, 'DNAME': DNAMERecord, @@ -3597,10 +3597,10 @@ def add_record(self, record_type='A', *args, **kwargs): """Adds an a record with the provided data to this :class:`Node` :param record_type: The type of record you would like to add. - Valid record_type arguments are: 'A', 'AAAA', 'CERT', 'CNAME', - 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', 'IPSECKEY', - 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', 'SPF', - 'SRV', and 'TXT'. + Valid record_type arguments are: 'A', 'AAAA', 'CAA', 'CERT', + 'CNAME', 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', + 'IPSECKEY', 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', + 'SPF', 'SRV', and 'TXT'. :param args: Non-keyword arguments to pass to the Record constructor :param kwargs: Keyword arguments to pass to the Record constructor """ @@ -3650,13 +3650,14 @@ def get_all_records_by_type(self, record_type): are owned by this node. :param record_type: The type of :class:`DNSRecord` you wish returned. - Valid record_type arguments are: 'A', 'AAAA', 'CERT', 'CNAME', - 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', 'IPSECKEY', - 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', 'SPF', - 'SRV', and 'TXT'. + Valid record_type arguments are: 'A', 'AAAA', 'CAA', 'CERT', + 'CNAME', 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', + 'IPSECKEY', 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', + 'SPF', 'SRV', and 'TXT'. :return: A list of :class:`DNSRecord`'s """ - names = {'A': 'ARecord', 'AAAA': 'AAAARecord', 'CERT': 'CERTRecord', + names = {'A': 'ARecord', 'AAAA': 'AAAARecord', + 'CAA': 'CAARecord', 'CERT': 'CERTRecord', 'CNAME': 'CNAMERecord', 'DHCID': 'DHCIDRecord', 'DNAME': 'DNAMERecord', 'DNSKEY': 'DNSKEYRecord', 'DS': 'DSRecord', 'KEY': 'KEYRecord', 'KX': 'KXRecord', From feb13cf58985c65089e45e5376ef469b93c935ea Mon Sep 17 00:00:00 2001 From: rnorthover Date: Mon, 31 Jul 2017 14:27:56 -0400 Subject: [PATCH 24/38] Fix travis style errors --- dyn/core.py | 1 - dyn/tm/records.py | 56 +++++++++++++++++++++++------------------------ dyn/tm/zones.py | 29 ++++++++++++------------ 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/dyn/core.py b/dyn/core.py index c6d71af..b6d2fe8 100644 --- a/dyn/core.py +++ b/dyn/core.py @@ -278,7 +278,6 @@ def _retry(self, msgs, final=False): # Neither blocked nor throttled? return dict(retry=False, wait=0, final=True) - def _handle_response(self, response, uri, method, raw_args, final): """Handle the processing of the API's response""" body = response.read() diff --git a/dyn/tm/records.py b/dyn/tm/records.py index e8ed842..b23ca4a 100644 --- a/dyn/tm/records.py +++ b/dyn/tm/records.py @@ -1239,18 +1239,18 @@ def __repr__(self): """print override""" return self.__str__() + class CAARecord(DNSRecord): """Certification Authority Authorization (CAA) Resource Record - This record allows a DNS domain name holder to specify one or more - Certification Authorities (CAs) authorized to issue certificates for that - domain. CAA Resource Records allow a public Certification Authority to - implement additional controls to reduce the risk of unintended certificate - mis-issue. This document defines the syntax of the CAA record and rules for - processing CAA records by certificate issuers. + This record allows a DNS domain name holder to specify one or more + Certification Authorities (CAs) authorized to issue certificates for that + domain. CAA Resource Records allow a public Certification Authority to + implement additional controls to reduce the risk of unintended certificate + mis-issue. This document defines the syntax of the CAA record and rules + for processing CAA records by certificate issuers. - see: https://tools.ietf.org/html/rfc6844 - """ + see: https://tools.ietf.org/html/rfc6844 """ def __init__(self, zone, fqdn, *args, **kwargs): """Create a :class:`~dyn.tm.records.CAARecord` object @@ -1260,26 +1260,26 @@ def __init__(self, zone, fqdn, *args, **kwargs): :param flags: A byte :param tag: A string defining the tag component of the = record property. May be one of: - issue: The issue property entry authorizes the holder of - the domain name or a party acting under - the explicit authority of the holder of that domain name to - issue certificates for the domain in which the property is - published. - - issuewild: The issuewild property entry authorizes the - holder of the domain name or a party - acting under the explicit authority of the holder of that - domain name to issue wildcard certificates for the domain in - which the property is published. - - iodef: Specifies a URL to which an issuer MAY report - certificate issue requests that are inconsistent with the - issuer's Certification Practices or Certificate Policy, or - that a Certificate Evaluator may use to report observation - of a possible policy violation. - :param value: A string representing the value component of the property. - This will be an issuer domain name or a URL. - :param ttl: TTL for this record. Use 0 for zone default + issue: The issue property entry authorizes the holder of + the domain name or a party acting under + the explicit authority of the holder of that domain name to + issue certificates for the domain in which the property is + published. + + issuewild: The issuewild property entry authorizes the + holder of the domain name or a party + acting under the explicit authority of the holder of that + domain name to issue wildcard certificates for the domain in + which the property is published. + + iodef: Specifies a URL to which an issuer MAY report + certificate issue requests that are inconsistent with the + issuer's Certification Practices or Certificate Policy, or + that a Certificate Evaluator may use to report observation + of a possible policy violation. + :param value: A string representing the value component of the + property. This will be an issuer domain name or a URL. + :param ttl: TTL for this record. Use 0 for zone default """ fields = ['flags', 'tag', 'value', 'ttl'] diff --git a/dyn/tm/zones.py b/dyn/tm/zones.py index 55c23bd..1305bdd 100644 --- a/dyn/tm/zones.py +++ b/dyn/tm/zones.py @@ -522,24 +522,23 @@ def get_all_records_by_type(self, record_type): are owned by this node. :param record_type: The type of :class:`DNSRecord` you wish returned. - Valid record_type arguments are: 'A', 'AAAA', 'CAA', 'CERT', 'CNAME', - 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', 'IPSECKEY', - 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', 'SPF', - 'SRV', and 'TXT'. + Valid record_type arguments are: 'A', 'AAAA', 'CAA', 'CERT', + 'CNAME', 'DHCID', 'DNAME', 'DNSKEY', 'DS', 'KEY', 'KX', 'LOC', + 'IPSECKEY', 'MX', 'NAPTR', 'PTR', 'PX', 'NSAP', 'RP', 'NS', 'SOA', + 'SPF', 'SRV', and 'TXT'. :return: A :class:`List` of :class:`DNSRecord`'s """ names = {'A': 'ARecord', 'AAAA': 'AAAARecord', 'ALIAS': 'ALIASRecord', - 'CAA': 'CAARecord', 'CDS': 'CDSRecord', 'CDNSKEY': 'CDNSKEYRecord', - 'CERT': 'CERTRecord', 'CSYNC': 'CSYNCRecord', - 'CNAME': 'CNAMERecord', 'DHCID': 'DHCIDRecord', - 'DNAME': 'DNAMERecord', 'DNSKEY': 'DNSKEYRecord', - 'DS': 'DSRecord', 'KEY': 'KEYRecord', 'KX': 'KXRecord', - 'LOC': 'LOCRecord', 'IPSECKEY': 'IPSECKEYRecord', - 'MX': 'MXRecord', 'NAPTR': 'NAPTRRecord', 'PTR': 'PTRRecord', - 'PX': 'PXRecord', 'NSAP': 'NSAPRecord', 'RP': 'RPRecord', - 'NS': 'NSRecord', 'SOA': 'SOARecord', 'SPF': 'SPFRecord', - 'SRV': 'SRVRecord', 'TLSA': 'TLSARecord', 'TXT': 'TXTRecord', - 'SSHFP': 'SSHFPRecord'} + 'CAA': 'CAARecord', 'CDS': 'CDSRecord', 'CDNSKEY': + 'CDNSKEYRecord', 'CERT': 'CERTRecord', 'CSYNC': 'CSYNCRecord', + 'CNAME': 'CNAMERecord', 'DHCID': 'DHCIDRecord', 'DNAME': + 'DNAMERecord', 'DNSKEY': 'DNSKEYRecord', 'DS': 'DSRecord', + 'KEY': 'KEYRecord', 'KX': 'KXRecord', 'LOC': 'LOCRecord', + 'IPSECKEY': 'IPSECKEYRecord', 'MX': 'MXRecord', 'NAPTR': + 'NAPTRRecord', 'PTR': 'PTRRecord', 'PX': 'PXRecord', 'NSAP': + 'NSAPRecord', 'RP': 'RPRecord', 'NS': 'NSRecord', 'SOA': + 'SOARecord', 'SPF': 'SPFRecord', 'SRV': 'SRVRecord', 'TLSA': + 'TLSARecord', 'TXT': 'TXTRecord', 'SSHFP': 'SSHFPRecord'} constructor = RECS[record_type] uri = '/{}/{}/{}/'.format(names[record_type], self._name, self.fqdn) From afeb29a13103886bbe988f0dba969a3cdf208193 Mon Sep 17 00:00:00 2001 From: Northover Date: Mon, 31 Jul 2017 14:47:00 -0400 Subject: [PATCH 25/38] Version bump to 1.8.0 (#117) --- dyn/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index 495dbbe..52eec9a 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,12 +5,17 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 7, 10) +version_info = (1, 8, 0) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' -__author__ = 'Jonathan Nappi, Cole Tuininga, Marc Howes, Philip Andrews' +__author__ = ''' + Jonathan Nappi, + Cole Tuininga, + Marc Howes, + Philip Andrews, + Robert Northover''' __version__ = '.'.join([str(x) for x in version_info]) -__maintainer__ = 'Marc Howes' -__email__ = 'mhowes@dyn.com' +__maintainer__ = 'Robert Northover' +__email__ = 'rnorthover@dyn.com' __status__ = 'Stable' __title__ = '{0} version {1}'.format(__name__, __version__) From 0a70d2dc7ed06636f6f68dd28465e2700f5f375b Mon Sep 17 00:00:00 2001 From: Northover Date: Mon, 31 Jul 2017 15:55:22 -0400 Subject: [PATCH 26/38] Version bump to 1.8.0 (#118) * Version bump to 1.8.0 * Update history --- HISTORY.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 70dfa5b..f9698e4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,13 @@ Release History --------------- +1.8.0 (2017-07-31) +++++++++++++++++++ +*CAA Record support +*Exponential backoff on blocked tasks +*Misc bug fixes + + 1.7.10 (2016-12-08) ++++++++++++++++++ *TSIG names can now be attached to `dyn.tm.zones.ExternalNamserver` From 08029531715f21374d99afb0c30fa09d3f4941ca Mon Sep 17 00:00:00 2001 From: Sarah Bennert Date: Tue, 2 Jan 2018 12:23:09 -0500 Subject: [PATCH 27/38] Raise ValueError on invalid response body (#119) * Raise ValueError on empty response body * Add log messaage on json decode ValueError * Remove unused import from dev * Use class logger object --- dyn/core.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dyn/core.py b/dyn/core.py index b6d2fe8..0e12036 100644 --- a/dyn/core.py +++ b/dyn/core.py @@ -287,7 +287,20 @@ def _handle_response(self, response, uri, method, raw_args, final): if self.poll_incomplete: response, body = self.poll_response(response, body) self._last_response = response - ret_val = json.loads(body.decode('UTF-8')) + + if not body: + err_msg_fmt = "Received Empty Response: {!r} status: {!r} {!r}" + error_message = err_msg_fmt.format(body, response.status, uri) + self.logger.error(error_message) + raise ValueError(error_message) + + json_err_fmt = "Decode Error on Response Body: {!r} status: {!r} {!r}" + try: + ret_val = json.loads(body.decode('UTF-8')) + except ValueError: + self.logger.error(json_err_fmt.format(body, response.status, uri)) + raise + if self.__call_cache is not None: self.__call_cache.append((uri, method, clean_args(raw_args), ret_val['status'])) From b165ab2fc9f73dac1c4ac1622fcc3286167adf1c Mon Sep 17 00:00:00 2001 From: Mike Lalumiere Date: Tue, 2 Jan 2018 12:23:30 -0500 Subject: [PATCH 28/38] Fix updates to DSF endpoints. (#124) --- dyn/tm/services/dsf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 18ad05d..0022d8a 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -3099,7 +3099,7 @@ def _update(self, api_args): full_list = self._monitor.endpoints args_list = [] for endpoint in full_list: - if id(endpoint) == id(self): + if endpoint.address == self.address: args_list.append(api_args) else: args_list.append(endpoint._json) From d8d8e937ff84860e1782918baf5f8fb1057dda59 Mon Sep 17 00:00:00 2001 From: Northover Date: Tue, 2 Jan 2018 12:31:39 -0500 Subject: [PATCH 29/38] Bump version to 1.8.1 (#125) --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index 52eec9a..d0d6109 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 0) +version_info = (1, 8, 1) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = ''' From 49d2b8b5a732dc29702033f39f0ceb38467bdd9a Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Tue, 2 Nov 2021 14:19:28 +0200 Subject: [PATCH 30/38] Fix Python 3.10 compatibility (collections.abc imports) Many classes moved from `collections` module to `collections.abc`. https://docs.python.org/3.9/library/collections.html?highlight=collections#module-collections > Deprecated since version 3.3, will be removed in version 3.10: Moved > Collections Abstract Base Classes to the collections.abc module. For > backwards compatibility, they continue to be visible in this module > through Python 3.9. --- dyn/tm/services/dsf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 0022d8a..3713279 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -2,7 +2,7 @@ """This module contains wrappers for interfacing with every element of a Traffic Director (DSF) service. """ -from collections import Iterable +from collections.abc import Iterable from dyn.compat import force_unicode, string_types from dyn.tm.utils import APIList, Active from dyn.tm.errors import DynectInvalidArgumentError From e625a3d9e73cbd72dc0e4a1dbfcf7fc2a7803b9e Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Fri, 25 Feb 2022 13:02:04 -0500 Subject: [PATCH 31/38] Bump version to 1.8.2 --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index d0d6109..a101b61 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 1) +version_info = (1, 8, 2) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = ''' From 5db7f9ecdffee2e42264eddc74f6e13246464cc5 Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Fri, 25 Feb 2022 13:04:28 -0500 Subject: [PATCH 32/38] Update __init__.py --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index a101b61..cde14c1 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 2) +version_info = (1, 8, 3) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = ''' From 7784766211683a29e0f9ca35df1579ccecb43c4d Mon Sep 17 00:00:00 2001 From: mcanning Date: Fri, 25 Feb 2022 13:24:48 -0500 Subject: [PATCH 33/38] Revert "Fix Python 3.10 compatibility (collections.abc imports)" --- dyn/tm/services/dsf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 3713279..0022d8a 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -2,7 +2,7 @@ """This module contains wrappers for interfacing with every element of a Traffic Director (DSF) service. """ -from collections.abc import Iterable +from collections import Iterable from dyn.compat import force_unicode, string_types from dyn.tm.utils import APIList, Active from dyn.tm.errors import DynectInvalidArgumentError From abb62367fd4960e6b0fa19afa379cf93e626d8da Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Fri, 25 Feb 2022 16:33:32 -0500 Subject: [PATCH 34/38] Python 3.10 compatibility --- dyn/tm/services/dsf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dyn/tm/services/dsf.py b/dyn/tm/services/dsf.py index 0022d8a..3801a21 100644 --- a/dyn/tm/services/dsf.py +++ b/dyn/tm/services/dsf.py @@ -2,7 +2,10 @@ """This module contains wrappers for interfacing with every element of a Traffic Director (DSF) service. """ -from collections import Iterable +try: + from collections.abc import Iterable +except ImportError: + from collections import Iterable from dyn.compat import force_unicode, string_types from dyn.tm.utils import APIList, Active from dyn.tm.errors import DynectInvalidArgumentError From 89f20136ed95e647649b40ba1c7b0b2c0ae1a04c Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Fri, 25 Feb 2022 16:35:40 -0500 Subject: [PATCH 35/38] Bump version to 1.8.4 --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index cde14c1..e5c2ade 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 3) +version_info = (1, 8, 4) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = ''' From bb667157d915f35e0a296d6a85e2fe3e659720ff Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:00:30 -0400 Subject: [PATCH 36/38] Fix python3 compatibility issue when using an authenticated proxy --- dyn/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dyn/core.py b/dyn/core.py index 0e12036..7a2e378 100644 --- a/dyn/core.py +++ b/dyn/core.py @@ -185,9 +185,9 @@ def connect(self): use_proxy = True if self.proxy_user and self.proxy_pass: - auth = '{}:{}'.format(self.proxy_user, self.proxy_pass) - headers['Proxy-Authorization'] = 'Basic ' + base64.b64encode( - auth) + auth = '{}:{}'.format(self.proxy_user, self.proxy_pass).encode() + headers['Proxy-Authorization'] = 'Basic ' + str(base64.b64encode( + auth)) if use_proxy: if self.ssl: From 0002a4033ab3fe6f362d7a39bb19943b98e529bb Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:01:01 -0400 Subject: [PATCH 37/38] Bump version to 1.8.5 --- dyn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyn/__init__.py b/dyn/__init__.py index e5c2ade..fcf2e60 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 4) +version_info = (1, 8, 5) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = ''' From 1f32919cb7e8f199525a1b770d1f1a1cff233cea Mon Sep 17 00:00:00 2001 From: siijmDqEaiPR <100380192+siijmDqEaiPR@users.noreply.github.com> Date: Tue, 21 Mar 2023 20:41:33 -0400 Subject: [PATCH 38/38] update changelog --- HISTORY.rst | 263 ++++++++++++++++++++++++------------------------ dyn/__init__.py | 2 +- 2 files changed, 133 insertions(+), 132 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index f9698e4..80794e2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,333 +1,334 @@ Release History --------------- +1.8.6 (2023-03-22) +++++++++++++++++++ +- Better python3 compatibility + 1.8.0 (2017-07-31) ++++++++++++++++++ -*CAA Record support -*Exponential backoff on blocked tasks -*Misc bug fixes +- CAA Record support +- Exponential backoff on blocked tasks +- Misc bug fixes 1.7.10 (2016-12-08) -++++++++++++++++++ -*TSIG names can now be attached to `dyn.tm.zones.ExternalNamserver` ++++++++++++++++++++ +- TSIG names can now be attached to `dyn.tm.zones.ExternalNamserver` 1.7.9 (2016-11-28) ++++++++++++++++++ -*Add publish parameter to delete methods -*Check publish and implicitPublish for delete +- Add publish parameter to delete methods +- Check publish and implicitPublish for delete 1.7.8 (2016-10-31) ++++++++++++++++++ -*Minor Bugfixes to ExtNameServer. -*Advanced Redirect SDK calls (Beta) +- Minor Bugfixes to ExtNameServer. +- Advanced Redirect SDK calls (Beta) 1.7.7 (2016-10-20) ++++++++++++++++++ -*Add 'all_ds' field to DNSSECKey class for multi-DS support -*Add `dyn.tm.zones.ExternalNamserver` and `dyn.tm.zones.ExternalNameserverEntry` +- Add 'all_ds' field to DNSSECKey class for multi-DS support +- Add `dyn.tm.zones.ExternalNamserver` and `dyn.tm.zones.ExternalNameserverEntry` 1.7.6 (2016-09-29) ++++++++++++++++++ -*Bug fix for DSFNode export -*Internal Improvement for multiprocess applications. +- Bug fix for DSFNode export +- Internal Improvement for multiprocess applications. 1.7.5 (2016-09-09) ++++++++++++++++++ -*Bug fix for token renewal on connection timeout +- Bug fix for token renewal on connection timeout 1.7.4 (2016-08-30) ++++++++++++++++++ -*Added IPACL feature to accounts library. Customers can now control Account Login ACLs for API and Web independently. +- Added IPACL feature to accounts library. Customers can now control Account Login ACLs for API and Web independently. 1.7.2 (2016-08-17) ++++++++++++++++++ -*Update add_node and remove_node functions in Traffic Director to respect implicitPublish setting. -*Updated permission fixes dyn.tm.accounts +- Update add_node and remove_node functions in Traffic Director to respect implicitPublish setting. +- Updated permission fixes dyn.tm.accounts 1.7.1 (2016-08-11) ++++++++++++++++++ -*task_id is now returned for a number of calls that spawn system tasks -*Bug fixes in RTTM. If you are using the RTTM with the SDK against our system, after Release-5.2.17 you will have to upgrade to this version. +- task_id is now returned for a number of calls that spawn system tasks +- Bug fixes in RTTM. If you are using the RTTM with the SDK against our system, after Release-5.2.17 you will have to upgrade to this version. 1.7.0 (2016-06-22) ++++++++++++++++++ -*Bug fix for implicit publishes in the DSF service with Publish Notes. -*Added `dyn.tm.dsf.DSFNode` Node type for DSF services. `dyn.tm.dsf.TrafficDirector` should now accept this node type, - as well as produce it. Regular `dyn.tm.zones.Node` objects can still be passed in, but they will no longer be generated - as output. -*Python3 compatability fixes as well as a through linting. +- Bug fix for implicit publishes in the DSF service with Publish Notes. +- Added `dyn.tm.dsf.DSFNode` Node type for DSF services. `dyn.tm.dsf.TrafficDirector` should now accept this node type, as well as produce it. Regular `dyn.tm.zones.Node` objects can still be passed in, but they will no longer be generated as output. +- Python3 compatability fixes as well as a through linting. 1.6.4 (2016-05-20) ++++++++++++++++++ -*Added Publish Notes to Traffic Director Service. User created Zone Notes can now be generated on a Traffic Director - Publish. This includes in line setter publishes, or full Service level publishes. +- Added Publish Notes to Traffic Director Service. User created Zone Notes can now be generated on a Traffic Director Publish. This includes in line setter publishes, or full Service level publishes. 1.6.3 (2016-3-21) -++++++++++++++++ -*Added TrafficDirector:replace_all_rulesets to wholesale replace rulesets on a TrafficDirector -*Added TrafficDirector:replace_one_ruleset to remove and replace a single ruleset entry in place -*Merged Proxy support from PR #73 ++++++++++++++++++ +- Added TrafficDirector:replace_all_rulesets to wholesale replace rulesets on a TrafficDirector +- Added TrafficDirector:replace_one_ruleset to remove and replace a single ruleset entry in place +- Merged Proxy support from PR #73 1.6.2 (2016-3-7) ++++++++++++++++ -*Added order_rulesets() to TrafficDirector object, for re-ordering Rulesets -*Added index=n to Ruleset create() so New rulesets can be placed in a certain location in the chain. -*Added getters for single DSF objects get_record(), get_record_set() etc. -*Fixed bug with DSF Monitor options -*Fixed bug where adding criteria to rulesets with 'always' criteria_type changes it to 'geoip' by default. +- Added order_rulesets() to TrafficDirector object, for re-ordering Rulesets +- Added index=n to Ruleset create() so New rulesets can be placed in a certain location in the chain. +- Added getters for single DSF objects get_record(), get_record_set() etc. +- Fixed bug with DSF Monitor options +- Fixed bug where adding criteria to rulesets with 'always' criteria_type changes it to 'geoip' by default. 1.6.1 (2016-2-11) +++++++++++++++++ -*Added UNKNOWN record type -*DSF records status getter added +- Added UNKNOWN record type +- DSF records status getter added 1.6.0 (2016-1-28) +++++++++++++++++ -*DSF service objects can now be independently Created, Updated, Read, and Deleted. -*Signifigant changes to how DSF service works. There may be some minor breaking changes here. -*Record getters now automatically pull data from system instead of storing them locally. +- DSF service objects can now be independently Created, Updated, Read, and Deleted. +- Signifigant changes to how DSF service works. There may be some minor breaking changes here. +- Record getters now automatically pull data from system instead of storing them locally. 1.5.2 (2016-1-11) +++++++++++++++++ -*Addition of Delay feature to GSLB Services -*Minor Improvements to GSLB features. -*Addition of Apex Finder +- Addition of Delay feature to GSLB Services +- Minor Improvements to GSLB features. +- Addition of Apex Finder 1.5.1 (2015-12-17) ++++++++++++++++++ -*Addition of CSYNC records +- Addition of CSYNC records 1.5.0 (2015-12-14) ++++++++++++++++++ -*Alias Traffic Director Support, coincides with ALIAS product release. -*Addition of CDS and CDNSKEY records. +- Alias Traffic Director Support, coincides with ALIAS product release. +- Addition of CDS and CDNSKEY records. 1.4.5 (2015-12-9) +++++++++++++++++ -* Added support for new syslog delivery type. `syslog_delivery` where `all` delivers messages no matter what the state and `change` only does so upon a detected change. +- Added support for new syslog delivery type. `syslog_delivery` where `all` delivers messages no matter what the state and `change` only does so upon a detected change. 1.4.4 (2015-11-25) ++++++++++++++++++ -* Added support for ALIAS records. +- Added support for ALIAS records. 1.4.3 (2015-08-14) ++++++++++++++++++ -*Added support for configurable Syslog Messages +- Added support for configurable Syslog Messages 1.4.2 (2015-08-10) ++++++++++++++++++ -* Added support for deleting all records of a certain type per #47. Thanks @tarokkk -* Exception classes are now based on `Exception` per #51. Thanks @thedebugger -* Fixed potential circular dependency in `dyn.tm.services` -* Added HTTP response debug logging +- Added support for deleting all records of a certain type per #47. Thanks @tarokkk +- Exception classes are now based on `Exception` per #51. Thanks @thedebugger +- Fixed potential circular dependency in `dyn.tm.services` +- Added HTTP response debug logging 1.4.1 (2015-07-23) ++++++++++++++++++ -*added zone notes at publish capabilities. -*added TSIG support +- added zone notes at publish capabilities. +- added TSIG support 1.4.0 (2015-06-26) ++++++++++++++++++ -*Added better coverage for passing Node Objects -*New way of handling DSFNodes with new API call +- Added better coverage for passing Node Objects +- New way of handling DSFNodes with new API call 1.3.14 (2015-06-22) +++++++++++++++++++ -* Internal fixes with zone. +- Internal fixes with zone. 1.3.13 (2015-06-15) +++++++++++++++++++ -*DSF Ruleset Feature enhancement +- DSF Ruleset Feature enhancement 1.3.12 (2015-06-03) +++++++++++++++++++ -*Added active properties for secondary zones. +- Added active properties for secondary zones. 1.3.4 (2014-11-11) ++++++++++++++++++ -* Bugfix for MMSesion JSON Error caused by arg filtering -* Bugfix for DSFRecord Creation on DSF GET calls +- Bugfix for MMSesion JSON Error caused by arg filtering +- Bugfix for DSFRecord Creation on DSF GET calls 1.3.3 (2014-10-26) ++++++++++++++++++ -* Fixed the majority of warnings when building docs, per issue #18 -* Added `dyn.tm.zones.get_all_secondary_zones` function for retrieving all secondary zones for an account +- Fixed the majority of warnings when building docs, per issue #18 +- Added `dyn.tm.zones.get_all_secondary_zones` function for retrieving all secondary zones for an account 1.3.2 (2014-10-21) ++++++++++++++++++ -* Fixed an issue where attempting to access a Zone's serial resulted in always performing a GET call +- Fixed an issue where attempting to access a Zone's serial resulted in always performing a GET call 1.3.1 (2014-10-16) ++++++++++++++++++ -* Adding additional hooks to dyn.tm.errors that return collections of exceptions +- Adding additional hooks to dyn.tm.errors that return collections of exceptions 1.3.0 (2014-10-14) ++++++++++++++++++ -* dyn.tm.session.DynectSession now accepts a `history` flag to enable per-session history recording +- dyn.tm.session.DynectSession now accepts a `history` flag to enable per-session history recording 1.2.0 (2014-09-29) ++++++++++++++++++ -* Addition of dyn.tm.tools module -* Added change_ip and map_ip functions to dyn.tm.tools -* Added __enter__ and __exit__ methods to DynectSession for allow for use as a context manager -* Added dyn.core.SessionEngine.new_session classmethod for forcing new session generation +- Addition of dyn.tm.tools module +- Added change_ip and map_ip functions to dyn.tm.tools +- Added __enter__ and __exit__ methods to DynectSession for allow for use as a context manager +- Added dyn.core.SessionEngine.new_session classmethod for forcing new session generation 1.1.0 (2014-09-16) ++++++++++++++++++ -* Internally improved Python2/3 compaability with the intoduction of the dyn.compat module -* Timestamps for various report types are accepted as Python datetime.datetime instances -* Added qps report access to Zones -* Added __str__, __repr__, __unicode__, and __bytes__ methods to all API object types -* Added conditional password encryption to allow for better in-app security -* Added the ability for users to specify their own password encryption keys -* Added __getstate__ and __setstate__ methods to SessionEngine, allowing sessions to be serialized -* Misc bug fixes +- Internally improved Python2/3 compaability with the intoduction of the dyn.compat module +- Timestamps for various report types are accepted as Python datetime.datetime instances +- Added qps report access to Zones +- Added __str__, __repr__, __unicode__, and __bytes__ methods to all API object types +- Added conditional password encryption to allow for better in-app security +- Added the ability for users to specify their own password encryption keys +- Added __getstate__ and __setstate__ methods to SessionEngine, allowing sessions to be serialized +- Misc bug fixes 1.0.3 (2014-09-05) ++++++++++++++++++ -* Adding changes provided by @thomasco to allow for GSLB monitor replacements +- Adding changes provided by @thomasco to allow for GSLB monitor replacements 1.0.2 (2014-08-26) ++++++++++++++++++ -* Added reports module -* Updated installation documentation +- Added reports module +- Updated installation documentation 1.0.1 (2014-08-06) ++++++++++++++++++ -* Small bugfix for an issue affecting sending EMails via the HTMLEmail class +- Small bugfix for an issue affecting sending EMails via the HTMLEmail class 1.0.0 (2014-08-05) ++++++++++++++++++ -* Revamed how sessions are structured to support the new SessionEngine interface -* Message Management is now out of BETA due to many bug fixes and additional testing -* You can now have one SessionEngine instance (Singleton) per Thread -* Added File Encoding definitions to source code -* Updated dyn.mm docs to actually include code samples -* Adding some general information on sessions, primarily for my own sanity -* Added EMail subclasses for easier formatting/sending of EMail messages -* mm.session.session and tm.session.session functions have been replaced by the SessionEngine get_session class method -* Completed the dyn.mm.reports module -* Misc MM related bug fixes +- Revamed how sessions are structured to support the new SessionEngine interface +- Message Management is now out of BETA due to many bug fixes and additional testing +- You can now have one SessionEngine instance (Singleton) per Thread +- Added File Encoding definitions to source code +- Updated dyn.mm docs to actually include code samples +- Adding some general information on sessions, primarily for my own sanity +- Added EMail subclasses for easier formatting/sending of EMail messages +- mm.session.session and tm.session.session functions have been replaced by the SessionEngine get_session class method +- Completed the dyn.mm.reports module +- Misc MM related bug fixes 0.9.11 (2014-07-25) +++++++++++++++++++ -* Fixed a bug with how calls to ``get_all_zones`` created ``Zone`` objects -* Tackled a possible bug also stemming from ``get_all_zones`` calls where a ``Zone``'s ``contact`` and ``ttl`` attributes could always be ``None`` +- Fixed a bug with how calls to ``get_all_zones`` created ``Zone`` objects +- Tackled a possible bug also stemming from ``get_all_zones`` calls where a ``Zone``'s ``contact`` and ``ttl`` attributes could always be ``None`` 0.9.10 (2014-07-07) +++++++++++++++++++ -* Added fix for potentially improperly formatted search parameters in dyn.tm.accounts.get_users +- Added fix for potentially improperly formatted search parameters in dyn.tm.accounts.get_users 0.9.9 (2014-06-26) ++++++++++++++++++ -* Added SecondaryZone delete method -* Added better User __str__ representations -* Added SOA TTL bug fix +- Added SecondaryZone delete method +- Added better User __str__ representations +- Added SOA TTL bug fix 0.9.6 (2014-05-16) ++++++++++++++++++ -* Added Zone attribute updating -* Misc Bug fixes for Python 2.x/3.x cross-compatibility -* GSLB _build bug fix +- Added Zone attribute updating +- Misc Bug fixes for Python 2.x/3.x cross-compatibility +- GSLB _build bug fix 0.9.5 (2014-05-12) ++++++++++++++++++ -* Added custom User-Agent to DynectSession -* Added __all__ attributes where appropriate to simplify imports -* Improved dyn.tm.services import structure +- Added custom User-Agent to DynectSession +- Added __all__ attributes where appropriate to simplify imports +- Improved dyn.tm.services import structure 0.9.3 (2014-05-08) ++++++++++++++++++ -* Added Active class type for all TM services -* Misc DSFMonitor/Record bug fixes -* Added DSFMonitorEndpoint class +- Added Active class type for all TM services +- Misc DSFMonitor/Record bug fixes +- Added DSFMonitorEndpoint class 0.8.0 (2014-05-08) ++++++++++++++++++ -* Integrated _APILists into GSLB and RTTM services -* Added a more intuitive polling solution for Zone XFERs +- Integrated _APILists into GSLB and RTTM services +- Added a more intuitive polling solution for Zone XFERs 0.7.0 (2014-05-02) ++++++++++++++++++ -* Fixed Notifier URI construction -* Added _APIDict and _APIList implementations to improve seamless updating of services -* Added custom DSF Record Type Objects to greatly improve ease of creation/management of DSF Services +- Fixed Notifier URI construction +- Added _APIDict and _APIList implementations to improve seamless updating of services +- Added custom DSF Record Type Objects to greatly improve ease of creation/management of DSF Services 0.6.0 (2014-04-23) ++++++++++++++++++ -* Fixed Python 3.x support with singleton DynectSession instance -* Finished implementation of dyn.mm.accounts -* Improved RTTM support -* Added Zone XFER support -* Added code examples to documentation -* Added better Geo TM support including custom Geo Record Type objects +- Fixed Python 3.x support with singleton DynectSession instance +- Finished implementation of dyn.mm.accounts +- Improved RTTM support +- Added Zone XFER support +- Added code examples to documentation +- Added better Geo TM support including custom Geo Record Type objects 0.5.0 (2014-04-07) ++++++++++++++++++ -* Added initial pass at Message Management BETA functionality -* Cleaned up exception raising and general logic involving internal exception handling +- Added initial pass at Message Management BETA functionality +- Cleaned up exception raising and general logic involving internal exception handling 0.4.0 (2014-03-25) ++++++++++++++++++ -* Initial fork of Cole Tuininga's code base -* Began creation of OO models -* General cleanup of .pyc files +- Initial fork of Cole Tuininga's code base +- Began creation of OO models +- General cleanup of .pyc files 0.3.0 (2012-10-05) ++++++++++++++++++ -* Updated by Cole Tuininga -* Compatibility update to work with Python 3, incorporating patches suggested by Jonathan Kamens -* Added a newline to debug output when polling for a result +- Updated by Cole Tuininga +- Compatibility update to work with Python 3, incorporating patches suggested by Jonathan Kamens +- Added a newline to debug output when polling for a result 0.2.0 (2012-05-27) ++++++++++++++++++ -* Updated by Cole Tuininga -* Minor reorg to make it easier to add the library to PyPI +- Updated by Cole Tuininga +- Minor reorg to make it easier to add the library to PyPI 0.1.0 (2011-10-08) ++++++++++++++++++ -* Updated by Cole Tuininga -* Initial release +- Updated by Cole Tuininga +- Initial release diff --git a/dyn/__init__.py b/dyn/__init__.py index fcf2e60..2ee048f 100644 --- a/dyn/__init__.py +++ b/dyn/__init__.py @@ -5,7 +5,7 @@ Requires Python 2.6 or higher, or the "simplejson" package. """ -version_info = (1, 8, 5) +version_info = (1, 8, 6) __name__ = 'dyn' __doc__ = 'A python wrapper for the DynDNS and DynEmail APIs' __author__ = '''