diff --git a/octodns/provider/rackspace.py b/octodns/provider/rackspace.py index 5038929..28b7f05 100644 --- a/octodns/provider/rackspace.py +++ b/octodns/provider/rackspace.py @@ -7,13 +7,16 @@ from __future__ import absolute_import, division, print_function, \ from requests import HTTPError, Session, post from collections import defaultdict import logging -import string import time from ..record import Record from .base import BaseProvider +def _value_keyer(v): + return '{}-{}-{}'.format(v.get('type', ''), v['name'], v.get('data', '')) + + def add_trailing_dot(s): assert s assert s[-1] != '.' @@ -28,12 +31,12 @@ def remove_trailing_dot(s): def escape_semicolon(s): assert s - return string.replace(s, ';', '\\;') + return s.replace(';', '\\;') def unescape_semicolon(s): assert s - return string.replace(s, '\\;', ';') + return s.replace('\\;', ';') class RackspaceProvider(BaseProvider): @@ -367,11 +370,9 @@ class RackspaceProvider(BaseProvider): self._delete('domains/{}/records?{}'.format(domain_id, params)) if updates: - data = {"records": sorted(updates, key=lambda v: v['name'])} + data = {"records": sorted(updates, key=_value_keyer)} self._put('domains/{}/records'.format(domain_id), data=data) if creates: - data = {"records": sorted(creates, key=lambda v: v['type'] + - v['name'] + - v.get('data', ''))} + data = {"records": sorted(creates, key=_value_keyer)} self._post('domains/{}/records'.format(domain_id), data=data) diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index b377d14..a782018 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -723,7 +723,8 @@ class _IpList(object): @classmethod def process(cls, values): - return values + # Translating None into '' so that the list will be sortable in python3 + return [v if v is not None else '' for v in values] class Ipv4List(_IpList): @@ -918,6 +919,9 @@ class MxValue(object): 'exchange': self.exchange, } + def __hash__(self): + return hash('{} {}'.format(self.preference, self.exchange)) + def __eq__(self, other): return ((self.preference, self.exchange) == (other.preference, other.exchange)) @@ -1010,6 +1014,9 @@ class NaptrValue(object): 'replacement': self.replacement, } + def __hash__(self): + return hash(self.__repr__()) + def __eq__(self, other): return ((self.order, self.preference, self.flags, self.service, self.regexp, self.replacement) == @@ -1145,6 +1152,9 @@ class SshfpValue(object): 'fingerprint': self.fingerprint, } + def __hash__(self): + return hash(self.__repr__()) + def __eq__(self, other): return ((self.algorithm, self.fingerprint_type, self.fingerprint) == (other.algorithm, other.fingerprint_type, other.fingerprint)) @@ -1283,6 +1293,9 @@ class SrvValue(object): 'target': self.target, } + def __hash__(self): + return hash(self.__repr__()) + def __eq__(self, other): return ((self.priority, self.weight, self.port, self.target) == (other.priority, other.weight, other.port, other.target)) diff --git a/tests/test_octodns_provider_rackspace.py b/tests/test_octodns_provider_rackspace.py index 3dfdd5f..0a6564d 100644 --- a/tests/test_octodns_provider_rackspace.py +++ b/tests/test_octodns_provider_rackspace.py @@ -792,13 +792,13 @@ class TestRackspaceProvider(TestCase): ExpectedUpdates = { "records": [{ "name": "unit.tests", - "id": "A-222222", - "data": "1.2.3.5", + "id": "A-111111", + "data": "1.2.3.4", "ttl": 3600 }, { "name": "unit.tests", - "id": "A-111111", - "data": "1.2.3.4", + "id": "A-222222", + "data": "1.2.3.5", "ttl": 3600 }, { "name": "unit.tests", diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index c26b301..0845ddf 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -594,6 +594,30 @@ class TestRecord(TestCase): # __repr__ doesn't blow up a.__repr__() + # Hash + v = NaptrValue({ + 'order': 30, + 'preference': 31, + 'flags': 'M', + 'service': 'N', + 'regexp': 'O', + 'replacement': 'z', + }) + o = NaptrValue({ + 'order': 30, + 'preference': 32, + 'flags': 'M', + 'service': 'N', + 'regexp': 'O', + 'replacement': 'z', + }) + values = set() + values.add(v) + self.assertTrue(v in values) + self.assertFalse(o in values) + values.add(o) + self.assertTrue(o in values) + def test_ns(self): a_values = ['5.6.7.8.', '6.7.8.9.', '7.8.9.0.'] a_data = {'ttl': 30, 'values': a_values} @@ -1114,6 +1138,14 @@ class TestRecord(TestCase): self.assertTrue(c >= c) self.assertTrue(c <= c) + # Hash + values = set() + values.add(a) + self.assertTrue(a in values) + self.assertFalse(b in values) + values.add(b) + self.assertTrue(b in values) + def test_srv_value(self): a = SrvValue({'priority': 0, 'weight': 0, 'port': 0, 'target': 'foo.'}) b = SrvValue({'priority': 1, 'weight': 0, 'port': 0, 'target': 'foo.'}) @@ -1172,6 +1204,14 @@ class TestRecord(TestCase): self.assertTrue(c >= c) self.assertTrue(c <= c) + # Hash + values = set() + values.add(a) + self.assertTrue(a in values) + self.assertFalse(b in values) + values.add(b) + self.assertTrue(b in values) + class TestRecordValidation(TestCase): zone = Zone('unit.tests.', [])