You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2014/03/21 15:35:46 UTC
[2/6] git commit: Update Route53 driver so update_record method works
correctly for records with multiple values.
Update Route53 driver so update_record method works correctly for records with
multiple values.
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/692c5283
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/692c5283
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/692c5283
Branch: refs/heads/trunk
Commit: 692c5283459e7f6a6ccf064292fa4c0d1a7e9508
Parents: ae7d6ae
Author: Tomaz Muraus <to...@apache.org>
Authored: Fri Mar 21 14:31:18 2014 +0100
Committer: Tomaz Muraus <to...@apache.org>
Committed: Fri Mar 21 14:34:45 2014 +0100
----------------------------------------------------------------------
libcloud/dns/drivers/route53.py | 128 ++++++++++++++++++++++++++++++++---
1 file changed, 120 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/692c5283/libcloud/dns/drivers/route53.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/drivers/route53.py b/libcloud/dns/drivers/route53.py
index 09dc250..5cc8664 100644
--- a/libcloud/dns/drivers/route53.py
+++ b/libcloud/dns/drivers/route53.py
@@ -21,6 +21,7 @@ import base64
import hmac
import datetime
import uuid
+import copy
from libcloud.utils.py3 import httplib
from hashlib import sha1
@@ -190,9 +191,71 @@ class Route53DNSDriver(DNSDriver):
return Record(id=id, name=name, type=type, data=data, zone=zone,
driver=self, extra=extra)
+ def _update_single_value_record(self, record, name=None, type=None,
+ data=None, extra=None):
+ batch = [
+ ('DELETE', record.name, record.type, record.data, record.extra),
+ ('CREATE', name, type, data, extra)
+ ]
+
+ return self._post_changeset(record.zone, batch)
+
+ def _update_multi_value_record(self, record, name=None, type=None,
+ data=None, extra=None):
+ other_records = record.extra.get('_other_records', [])
+
+ attrs = {'xmlns': NAMESPACE}
+ changeset = ET.Element('ChangeResourceRecordSetsRequest', attrs)
+ batch = ET.SubElement(changeset, 'ChangeBatch')
+ changes = ET.SubElement(batch, 'Changes')
+
+ # Delete existing records
+ change = ET.SubElement(changes, 'Change')
+ ET.SubElement(change, 'Action').text = 'DELETE'
+
+ rrs = ET.SubElement(change, 'ResourceRecordSet')
+ ET.SubElement(rrs, 'Name').text = record.name + '.' + \
+ record.zone.domain
+ ET.SubElement(rrs, 'Type').text = self.RECORD_TYPE_MAP[record.type]
+ ET.SubElement(rrs, 'TTL').text = str(record.extra.get('ttl', '0'))
+
+ rrecs = ET.SubElement(rrs, 'ResourceRecords')
+
+ rrec = ET.SubElement(rrecs, 'ResourceRecord')
+ ET.SubElement(rrec, 'Value').text = record.data
+
+ for other_record in other_records:
+ rrec = ET.SubElement(rrecs, 'ResourceRecord')
+ ET.SubElement(rrec, 'Value').text = other_record['data']
+
+ # Re-create new (updated) records. Since we are updating a multi value
+ # record, only a single record is updated and others are left as is.
+ change = ET.SubElement(changes, 'Change')
+ ET.SubElement(change, 'Action').text = 'CREATE'
+
+ rrs = ET.SubElement(change, 'ResourceRecordSet')
+ ET.SubElement(rrs, 'Name').text = name + '.' + record.zone.domain
+ ET.SubElement(rrs, 'Type').text = self.RECORD_TYPE_MAP[type]
+ ET.SubElement(rrs, 'TTL').text = str(extra.get('ttl', '0'))
+
+ rrecs = ET.SubElement(rrs, 'ResourceRecords')
+
+ rrec = ET.SubElement(rrecs, 'ResourceRecord')
+ ET.SubElement(rrec, 'Value').text = data
+
+ for other_record in other_records:
+ rrec = ET.SubElement(rrecs, 'ResourceRecord')
+ ET.SubElement(rrec, 'Value').text = other_record['data']
+
+ uri = API_ROOT + 'hostedzone/' + record.zone.id + '/rrset'
+ data = ET.tostring(changeset)
+ self.connection.set_context({'zone_id': record.zone.id})
+ response = self.connection.request(uri, method='POST', data=data)
+
+ return response.status == httplib.OK
+
def update_record(self, record, name=None, type=None, data=None,
extra=None):
-
if not name:
name = record.name
@@ -202,10 +265,20 @@ class Route53DNSDriver(DNSDriver):
if not extra:
extra = record.extra
- batch = [
- ('DELETE', record.name, record.type, record.data, record.extra),
- ('CREATE', name, type, data, extra)]
- self._post_changeset(record.zone, batch)
+ # Multiple value records need to be handled specially - we need to
+ # pass values for other records as well
+ multiple_value_record = record.extra.get('_multi_value', False)
+ other_records = record.extra.get('_other_records', [])
+
+ if multiple_value_record and other_records:
+ self._update_multi_value_record(record=record, name=name,
+ type=type, data=data,
+ extra=extra)
+ else:
+ self._update_single_value_record(record=record, name=name,
+ type=type, data=data,
+ extra=extra)
+
id = ':'.join((self.RECORD_TYPE_MAP[type], name))
return Record(id=id, name=name, type=type, data=data, zone=record.zone,
driver=self, extra=extra)
@@ -247,7 +320,7 @@ class Route53DNSDriver(DNSDriver):
ET.SubElement(change, 'Action').text = action
rrs = ET.SubElement(change, 'ResourceRecordSet')
- ET.SubElement(rrs, 'Name').text = name + "." + zone.domain
+ ET.SubElement(rrs, 'Name').text = name + '.' + zone.domain
ET.SubElement(rrs, 'Type').text = self.RECORD_TYPE_MAP[type_]
ET.SubElement(rrs, 'TTL').text = str(extra.get('ttl', '0'))
@@ -258,7 +331,9 @@ class Route53DNSDriver(DNSDriver):
uri = API_ROOT + 'hostedzone/' + zone.id + '/rrset'
data = ET.tostring(changeset)
self.connection.set_context({'zone_id': zone.id})
- self.connection.request(uri, method='POST', data=data)
+ response = self.connection.request(uri, method='POST', data=data)
+
+ return response.status == httplib.OK
def _to_zones(self, data):
zones = []
@@ -294,8 +369,45 @@ class Route53DNSDriver(DNSDriver):
record_set = elem.findall(fixxpath(
xpath='ResourceRecords/ResourceRecord',
namespace=NAMESPACE))
+ record_count = len(record_set)
+ multiple_value_record = (record_count > 1)
+
+ record_set_records = []
+
for index, record in enumerate(record_set):
- records.append(self._to_record(elem, zone, index))
+ # Need to special handling for records with multiple values for
+ # update to work correctly
+ record = self._to_record(elem=elem, zone=zone, index=index)
+ record.extra['_multi_value'] = multiple_value_record
+
+ if multiple_value_record:
+ record.extra['_other_records'] = []
+
+ record_set_records.append(record)
+
+ # Store reference to other records so update works correctly
+ if multiple_value_record:
+ for index in range(0, len(record_set_records)):
+ record = record_set_records[index]
+
+ for other_index, other_record in \
+ enumerate(record_set_records):
+ if index == other_index:
+ # Skip current record
+ continue
+
+ extra = copy.deepcopy(other_record.extra)
+ extra.pop('_multi_value')
+ extra.pop('_other_records')
+
+ item = {'name': other_record.name,
+ 'data': other_record.data,
+ 'type': other_record.type,
+ 'extra': extra}
+ record.extra['_other_records'].append(item)
+
+ records.extend(record_set_records)
+
return records
def _to_record(self, elem, zone, index=0):