|
|
@ -87,7 +87,9 @@ class Record(EqualityTupleMixin): |
|
|
_CLASSES = {} |
|
|
_CLASSES = {} |
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def register_type(cls, _type, _class): |
|
|
|
|
|
|
|
|
def register_type(cls, _class, _type=None): |
|
|
|
|
|
if _type is None: |
|
|
|
|
|
_type = _class._type |
|
|
existing = cls._CLASSES.get(_type, None) |
|
|
existing = cls._CLASSES.get(_type, None) |
|
|
if existing: |
|
|
if existing: |
|
|
module = existing.__module__ |
|
|
module = existing.__module__ |
|
|
@ -283,11 +285,11 @@ class GeoValue(EqualityTupleMixin): |
|
|
"{self.subdivision_code} {self.values}'" |
|
|
"{self.subdivision_code} {self.values}'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _ValuesMixin(object): |
|
|
|
|
|
|
|
|
class ValuesMixin(object): |
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def validate(cls, name, fqdn, data): |
|
|
def validate(cls, name, fqdn, data): |
|
|
reasons = super(_ValuesMixin, cls).validate(name, fqdn, data) |
|
|
|
|
|
|
|
|
reasons = super(ValuesMixin, cls).validate(name, fqdn, data) |
|
|
|
|
|
|
|
|
values = data.get('values', data.get('value', [])) |
|
|
values = data.get('values', data.get('value', [])) |
|
|
|
|
|
|
|
|
@ -296,7 +298,7 @@ class _ValuesMixin(object): |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
def __init__(self, zone, name, data, source=None): |
|
|
def __init__(self, zone, name, data, source=None): |
|
|
super(_ValuesMixin, self).__init__(zone, name, data, source=source) |
|
|
|
|
|
|
|
|
super(ValuesMixin, self).__init__(zone, name, data, source=source) |
|
|
try: |
|
|
try: |
|
|
values = data['values'] |
|
|
values = data['values'] |
|
|
except KeyError: |
|
|
except KeyError: |
|
|
@ -306,10 +308,10 @@ class _ValuesMixin(object): |
|
|
def changes(self, other, target): |
|
|
def changes(self, other, target): |
|
|
if self.values != other.values: |
|
|
if self.values != other.values: |
|
|
return Update(self, other) |
|
|
return Update(self, other) |
|
|
return super(_ValuesMixin, self).changes(other, target) |
|
|
|
|
|
|
|
|
return super(ValuesMixin, self).changes(other, target) |
|
|
|
|
|
|
|
|
def _data(self): |
|
|
def _data(self): |
|
|
ret = super(_ValuesMixin, self)._data() |
|
|
|
|
|
|
|
|
ret = super(ValuesMixin, self)._data() |
|
|
if len(self.values) > 1: |
|
|
if len(self.values) > 1: |
|
|
values = [getattr(v, 'data', v) for v in self.values if v] |
|
|
values = [getattr(v, 'data', v) for v in self.values if v] |
|
|
if len(values) > 1: |
|
|
if len(values) > 1: |
|
|
@ -329,7 +331,7 @@ class _ValuesMixin(object): |
|
|
return f"<{klass} {self._type} {self.ttl}, {self.fqdn}, ['{values}']>" |
|
|
return f"<{klass} {self._type} {self.ttl}, {self.fqdn}, ['{values}']>" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _GeoMixin(_ValuesMixin): |
|
|
|
|
|
|
|
|
class _GeoMixin(ValuesMixin): |
|
|
''' |
|
|
''' |
|
|
Adds GeoDNS support to a record. |
|
|
Adds GeoDNS support to a record. |
|
|
|
|
|
|
|
|
@ -380,26 +382,26 @@ class _GeoMixin(_ValuesMixin): |
|
|
return super(_GeoMixin, self).__repr__() |
|
|
return super(_GeoMixin, self).__repr__() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _ValueMixin(object): |
|
|
|
|
|
|
|
|
class ValueMixin(object): |
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def validate(cls, name, fqdn, data): |
|
|
def validate(cls, name, fqdn, data): |
|
|
reasons = super(_ValueMixin, cls).validate(name, fqdn, data) |
|
|
|
|
|
|
|
|
reasons = super(ValueMixin, cls).validate(name, fqdn, data) |
|
|
reasons.extend(cls._value_type.validate(data.get('value', None), |
|
|
reasons.extend(cls._value_type.validate(data.get('value', None), |
|
|
cls._type)) |
|
|
cls._type)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
def __init__(self, zone, name, data, source=None): |
|
|
def __init__(self, zone, name, data, source=None): |
|
|
super(_ValueMixin, self).__init__(zone, name, data, source=source) |
|
|
|
|
|
|
|
|
super(ValueMixin, self).__init__(zone, name, data, source=source) |
|
|
self.value = self._value_type.process(data['value']) |
|
|
self.value = self._value_type.process(data['value']) |
|
|
|
|
|
|
|
|
def changes(self, other, target): |
|
|
def changes(self, other, target): |
|
|
if self.value != other.value: |
|
|
if self.value != other.value: |
|
|
return Update(self, other) |
|
|
return Update(self, other) |
|
|
return super(_ValueMixin, self).changes(other, target) |
|
|
|
|
|
|
|
|
return super(ValueMixin, self).changes(other, target) |
|
|
|
|
|
|
|
|
def _data(self): |
|
|
def _data(self): |
|
|
ret = super(_ValueMixin, self)._data() |
|
|
|
|
|
|
|
|
ret = super(ValueMixin, self)._data() |
|
|
if self.value: |
|
|
if self.value: |
|
|
ret['value'] = getattr(self.value, 'data', self.value) |
|
|
ret['value'] = getattr(self.value, 'data', self.value) |
|
|
return ret |
|
|
return ret |
|
|
@ -803,7 +805,7 @@ class ARecord(_DynamicMixin, _GeoMixin, Record): |
|
|
_value_type = Ipv4List |
|
|
_value_type = Ipv4List |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('A', ARecord) |
|
|
|
|
|
|
|
|
Record.register_type(ARecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AaaaRecord(_DynamicMixin, _GeoMixin, Record): |
|
|
class AaaaRecord(_DynamicMixin, _GeoMixin, Record): |
|
|
@ -811,14 +813,14 @@ class AaaaRecord(_DynamicMixin, _GeoMixin, Record): |
|
|
_value_type = Ipv6List |
|
|
_value_type = Ipv6List |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('AAAA', AaaaRecord) |
|
|
|
|
|
|
|
|
Record.register_type(AaaaRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AliasValue(_TargetValue): |
|
|
class AliasValue(_TargetValue): |
|
|
pass |
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AliasRecord(_ValueMixin, Record): |
|
|
|
|
|
|
|
|
class AliasRecord(ValueMixin, Record): |
|
|
_type = 'ALIAS' |
|
|
_type = 'ALIAS' |
|
|
_value_type = AliasValue |
|
|
_value_type = AliasValue |
|
|
|
|
|
|
|
|
@ -831,7 +833,7 @@ class AliasRecord(_ValueMixin, Record): |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('ALIAS', AliasRecord) |
|
|
|
|
|
|
|
|
Record.register_type(AliasRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CaaValue(EqualityTupleMixin): |
|
|
class CaaValue(EqualityTupleMixin): |
|
|
@ -880,15 +882,15 @@ class CaaValue(EqualityTupleMixin): |
|
|
return f'{self.flags} {self.tag} "{self.value}"' |
|
|
return f'{self.flags} {self.tag} "{self.value}"' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CaaRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class CaaRecord(ValuesMixin, Record): |
|
|
_type = 'CAA' |
|
|
_type = 'CAA' |
|
|
_value_type = CaaValue |
|
|
_value_type = CaaValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('CAA', CaaRecord) |
|
|
|
|
|
|
|
|
Record.register_type(CaaRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CnameRecord(_DynamicMixin, _ValueMixin, Record): |
|
|
|
|
|
|
|
|
class CnameRecord(_DynamicMixin, ValueMixin, Record): |
|
|
_type = 'CNAME' |
|
|
_type = 'CNAME' |
|
|
_value_type = CnameValue |
|
|
_value_type = CnameValue |
|
|
|
|
|
|
|
|
@ -901,15 +903,15 @@ class CnameRecord(_DynamicMixin, _ValueMixin, Record): |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('CNAME', CnameRecord) |
|
|
|
|
|
|
|
|
Record.register_type(CnameRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DnameRecord(_DynamicMixin, _ValueMixin, Record): |
|
|
|
|
|
|
|
|
class DnameRecord(_DynamicMixin, ValueMixin, Record): |
|
|
_type = 'DNAME' |
|
|
_type = 'DNAME' |
|
|
_value_type = DnameValue |
|
|
_value_type = DnameValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('DNAME', DnameRecord) |
|
|
|
|
|
|
|
|
Record.register_type(DnameRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LocValue(EqualityTupleMixin): |
|
|
class LocValue(EqualityTupleMixin): |
|
|
@ -1083,12 +1085,12 @@ class LocValue(EqualityTupleMixin): |
|
|
f"{self.precision_horz:.2f}m {self.precision_vert:.2f}m'" |
|
|
f"{self.precision_horz:.2f}m {self.precision_vert:.2f}m'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LocRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class LocRecord(ValuesMixin, Record): |
|
|
_type = 'LOC' |
|
|
_type = 'LOC' |
|
|
_value_type = LocValue |
|
|
_value_type = LocValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('LOC', LocRecord) |
|
|
|
|
|
|
|
|
Record.register_type(LocRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MxValue(EqualityTupleMixin): |
|
|
class MxValue(EqualityTupleMixin): |
|
|
@ -1156,12 +1158,12 @@ class MxValue(EqualityTupleMixin): |
|
|
return f"'{self.preference} {self.exchange}'" |
|
|
return f"'{self.preference} {self.exchange}'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MxRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class MxRecord(ValuesMixin, Record): |
|
|
_type = 'MX' |
|
|
_type = 'MX' |
|
|
_value_type = MxValue |
|
|
_value_type = MxValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('MX', MxRecord) |
|
|
|
|
|
|
|
|
Record.register_type(MxRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NaptrValue(EqualityTupleMixin): |
|
|
class NaptrValue(EqualityTupleMixin): |
|
|
@ -1237,12 +1239,12 @@ class NaptrValue(EqualityTupleMixin): |
|
|
f"\"{regexp}\" {self.replacement}'" |
|
|
f"\"{regexp}\" {self.replacement}'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NaptrRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class NaptrRecord(ValuesMixin, Record): |
|
|
_type = 'NAPTR' |
|
|
_type = 'NAPTR' |
|
|
_value_type = NaptrValue |
|
|
_value_type = NaptrValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('NAPTR', NaptrRecord) |
|
|
|
|
|
|
|
|
Record.register_type(NaptrRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _NsValue(object): |
|
|
class _NsValue(object): |
|
|
@ -1267,12 +1269,12 @@ class _NsValue(object): |
|
|
return values |
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NsRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class NsRecord(ValuesMixin, Record): |
|
|
_type = 'NS' |
|
|
_type = 'NS' |
|
|
_value_type = _NsValue |
|
|
_value_type = _NsValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('NS', NsRecord) |
|
|
|
|
|
|
|
|
Record.register_type(NsRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PtrValue(_TargetValue): |
|
|
class PtrValue(_TargetValue): |
|
|
@ -1297,7 +1299,7 @@ class PtrValue(_TargetValue): |
|
|
return [super(PtrValue, cls).process(v) for v in values] |
|
|
return [super(PtrValue, cls).process(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PtrRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class PtrRecord(ValuesMixin, Record): |
|
|
_type = 'PTR' |
|
|
_type = 'PTR' |
|
|
_value_type = PtrValue |
|
|
_value_type = PtrValue |
|
|
|
|
|
|
|
|
@ -1308,7 +1310,7 @@ class PtrRecord(_ValuesMixin, Record): |
|
|
return self.values[0] |
|
|
return self.values[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('PTR', PtrRecord) |
|
|
|
|
|
|
|
|
Record.register_type(PtrRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SshfpValue(EqualityTupleMixin): |
|
|
class SshfpValue(EqualityTupleMixin): |
|
|
@ -1370,15 +1372,15 @@ class SshfpValue(EqualityTupleMixin): |
|
|
return f"'{self.algorithm} {self.fingerprint_type} {self.fingerprint}'" |
|
|
return f"'{self.algorithm} {self.fingerprint_type} {self.fingerprint}'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SshfpRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class SshfpRecord(ValuesMixin, Record): |
|
|
_type = 'SSHFP' |
|
|
_type = 'SSHFP' |
|
|
_value_type = SshfpValue |
|
|
_value_type = SshfpValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('SSHFP', SshfpRecord) |
|
|
|
|
|
|
|
|
Record.register_type(SshfpRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _ChunkedValuesMixin(_ValuesMixin): |
|
|
|
|
|
|
|
|
class _ChunkedValuesMixin(ValuesMixin): |
|
|
CHUNK_SIZE = 255 |
|
|
CHUNK_SIZE = 255 |
|
|
_unescaped_semicolon_re = re.compile(r'\w;') |
|
|
_unescaped_semicolon_re = re.compile(r'\w;') |
|
|
|
|
|
|
|
|
@ -1427,7 +1429,7 @@ class SpfRecord(_ChunkedValuesMixin, Record): |
|
|
_value_type = _ChunkedValue |
|
|
_value_type = _ChunkedValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('SPF', SpfRecord) |
|
|
|
|
|
|
|
|
Record.register_type(SpfRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SrvValue(EqualityTupleMixin): |
|
|
class SrvValue(EqualityTupleMixin): |
|
|
@ -1498,7 +1500,7 @@ class SrvValue(EqualityTupleMixin): |
|
|
return f"'{self.priority} {self.weight} {self.port} {self.target}'" |
|
|
return f"'{self.priority} {self.weight} {self.port} {self.target}'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SrvRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class SrvRecord(ValuesMixin, Record): |
|
|
_type = 'SRV' |
|
|
_type = 'SRV' |
|
|
_value_type = SrvValue |
|
|
_value_type = SrvValue |
|
|
_name_re = re.compile(r'^(\*|_[^\.]+)\.[^\.]+') |
|
|
_name_re = re.compile(r'^(\*|_[^\.]+)\.[^\.]+') |
|
|
@ -1512,7 +1514,7 @@ class SrvRecord(_ValuesMixin, Record): |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('SRV', SrvRecord) |
|
|
|
|
|
|
|
|
Record.register_type(SrvRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _TxtValue(_ChunkedValue): |
|
|
class _TxtValue(_ChunkedValue): |
|
|
@ -1524,7 +1526,7 @@ class TxtRecord(_ChunkedValuesMixin, Record): |
|
|
_value_type = _TxtValue |
|
|
_value_type = _TxtValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('TXT', TxtRecord) |
|
|
|
|
|
|
|
|
Record.register_type(TxtRecord) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UrlfwdValue(EqualityTupleMixin): |
|
|
class UrlfwdValue(EqualityTupleMixin): |
|
|
@ -1599,9 +1601,9 @@ class UrlfwdValue(EqualityTupleMixin): |
|
|
f'{self.masking} {self.query}' |
|
|
f'{self.masking} {self.query}' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UrlfwdRecord(_ValuesMixin, Record): |
|
|
|
|
|
|
|
|
class UrlfwdRecord(ValuesMixin, Record): |
|
|
_type = 'URLFWD' |
|
|
_type = 'URLFWD' |
|
|
_value_type = UrlfwdValue |
|
|
_value_type = UrlfwdValue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record.register_type('URLFWD', UrlfwdRecord) |
|
|
|
|
|
|
|
|
Record.register_type(UrlfwdRecord) |