PageRenderTime 27ms CodeModel.GetById 8ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/boto-2.5.2/boto/route53/record.py

#
Python | 291 lines | 258 code | 3 blank | 30 comment | 0 complexity | 9fe360118db000fcf066d9187f3fb39e MD5 | raw file
  1# Copyright (c) 2010 Chris Moyer http://coredumped.org/
  2# Copyright (c) 2012 Mitch Garnaat http://garnaat.org/
  3# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
  4# All rights reserved.
  5#
  6# Permission is hereby granted, free of charge, to any person obtaining a
  7# copy of this software and associated documentation files (the
  8# "Software"), to deal in the Software without restriction, including
  9# without limitation the rights to use, copy, modify, merge, publish, dis-
 10# tribute, sublicense, and/or sell copies of the Software, and to permit
 11# persons to whom the Software is furnished to do so, subject to the fol-
 12# lowing conditions:
 13#
 14# The above copyright notice and this permission notice shall be included
 15# in all copies or substantial portions of the Software.
 16#
 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 18# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 19# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 20# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 21# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 23# IN THE SOFTWARE.
 24
 25RECORD_TYPES = ['A', 'AAAA', 'TXT', 'CNAME', 'MX', 'PTR', 'SRV', 'SPF']
 26
 27from boto.resultset import ResultSet
 28class ResourceRecordSets(ResultSet):
 29    """
 30    A list of resource records.
 31
 32    :ivar hosted_zone_id: The ID of the hosted zone.
 33    :ivar comment: A comment that will be stored with the change.
 34    :ivar changes: A list of changes.
 35    """
 36
 37    ChangeResourceRecordSetsBody = """<?xml version="1.0" encoding="UTF-8"?>
 38    <ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2012-02-29/">
 39            <ChangeBatch>
 40                <Comment>%(comment)s</Comment>
 41                <Changes>%(changes)s</Changes>
 42            </ChangeBatch>
 43        </ChangeResourceRecordSetsRequest>"""
 44
 45    ChangeXML = """<Change>
 46        <Action>%(action)s</Action>
 47        %(record)s
 48    </Change>"""
 49
 50    def __init__(self, connection=None, hosted_zone_id=None, comment=None):
 51        self.connection = connection
 52        self.hosted_zone_id = hosted_zone_id
 53        self.comment = comment
 54        self.changes = []
 55        self.next_record_name = None
 56        self.next_record_type = None
 57        ResultSet.__init__(self, [('ResourceRecordSet', Record)])
 58
 59    def __repr__(self):
 60        return '<ResourceRecordSets: %s>' % self.hosted_zone_id
 61
 62    def add_change(self, action, name, type, ttl=600,
 63            alias_hosted_zone_id=None, alias_dns_name=None, identifier=None,
 64            weight=None, region=None):
 65        """
 66        Add a change request to the set.
 67
 68        :type action: str
 69        :param action: The action to perform ('CREATE'|'DELETE')
 70
 71        :type name: str
 72        :param name: The name of the domain you want to perform the action on.
 73
 74        :type type: str
 75        :param type: The DNS record type.  Valid values are:
 76
 77            * A
 78            * AAAA
 79            * CNAME
 80            * MX
 81            * NS
 82            * PTR
 83            * SOA
 84            * SPF
 85            * SRV
 86            * TXT
 87
 88        :type ttl: int
 89        :param ttl: The resource record cache time to live (TTL), in seconds.
 90
 91        :type alias_hosted_zone_id: str
 92        :param alias_dns_name: *Alias resource record sets only* The value
 93            of the hosted zone ID, CanonicalHostedZoneNameId, for
 94            the LoadBalancer.
 95
 96        :type alias_dns_name: str
 97        :param alias_hosted_zone_id: *Alias resource record sets only*
 98            Information about the domain to which you are redirecting traffic.
 99
100        :type identifier: str
101        :param identifier: *Weighted and latency-based resource record sets
102            only* An identifier that differentiates among multiple resource
103            record sets that have the same combination of DNS name and type.
104
105        :type weight: int
106        :param weight: *Weighted resource record sets only* Among resource
107            record sets that have the same combination of DNS name and type,
108            a value that determines what portion of traffic for the current
109            resource record set is routed to the associated location
110
111        :type region: str
112        :param region: *Latency-based resource record sets only* Among resource
113            record sets that have the same combination of DNS name and type,
114            a value that determines which region this should be associated with
115            for the latency-based routing
116        """
117        change = Record(name, type, ttl,
118                alias_hosted_zone_id=alias_hosted_zone_id,
119                alias_dns_name=alias_dns_name, identifier=identifier,
120                weight=weight, region=None)
121        self.changes.append([action, change])
122        return change
123
124    def to_xml(self):
125        """Convert this ResourceRecordSet into XML
126        to be saved via the ChangeResourceRecordSetsRequest"""
127        changesXML = ""
128        for change in self.changes:
129            changeParams = {"action": change[0], "record": change[1].to_xml()}
130            changesXML += self.ChangeXML % changeParams
131        params = {"comment": self.comment, "changes": changesXML}
132        return self.ChangeResourceRecordSetsBody % params
133
134    def commit(self):
135        """Commit this change"""
136        if not self.connection:
137            import boto
138            self.connection = boto.connect_route53()
139        return self.connection.change_rrsets(self.hosted_zone_id, self.to_xml())
140
141    def endElement(self, name, value, connection):
142        """Overwritten to also add the NextRecordName and
143        NextRecordType to the base object"""
144        if name == 'NextRecordName':
145            self.next_record_name = value
146        elif name == 'NextRecordType':
147            self.next_record_type = value
148        else:
149            return ResultSet.endElement(self, name, value, connection)
150
151    def __iter__(self):
152        """Override the next function to support paging"""
153        results = ResultSet.__iter__(self)
154        while results:
155            for obj in results:
156                yield obj
157            if self.is_truncated:
158                self.is_truncated = False
159                results = self.connection.get_all_rrsets(self.hosted_zone_id, name=self.next_record_name, type=self.next_record_type)
160            else:
161                results = None
162
163
164
165class Record(object):
166    """An individual ResourceRecordSet"""
167
168    XMLBody = """<ResourceRecordSet>
169        <Name>%(name)s</Name>
170        <Type>%(type)s</Type>
171        %(weight)s
172        %(body)s
173    </ResourceRecordSet>"""
174
175    WRRBody = """
176        <SetIdentifier>%(identifier)s</SetIdentifier>
177        <Weight>%(weight)s</Weight>
178    """
179
180    RRRBody = """
181        <SetIdentifier>%(identifier)s</SetIdentifier>
182        <Region>%(region)s</Region>
183    """
184
185    ResourceRecordsBody = """
186        <TTL>%(ttl)s</TTL>
187        <ResourceRecords>
188            %(records)s
189        </ResourceRecords>"""
190
191    ResourceRecordBody = """<ResourceRecord>
192        <Value>%s</Value>
193    </ResourceRecord>"""
194
195    AliasBody = """<AliasTarget>
196        <HostedZoneId>%s</HostedZoneId>
197        <DNSName>%s</DNSName>
198    </AliasTarget>"""
199
200
201
202    def __init__(self, name=None, type=None, ttl=600, resource_records=None,
203            alias_hosted_zone_id=None, alias_dns_name=None, identifier=None,
204            weight=None, region=None):
205        self.name = name
206        self.type = type
207        self.ttl = ttl
208        if resource_records == None:
209            resource_records = []
210        self.resource_records = resource_records
211        self.alias_hosted_zone_id = alias_hosted_zone_id
212        self.alias_dns_name = alias_dns_name
213        self.identifier = identifier
214        self.weight = weight
215        self.region = region
216
217    def add_value(self, value):
218        """Add a resource record value"""
219        self.resource_records.append(value)
220
221    def set_alias(self, alias_hosted_zone_id, alias_dns_name):
222        """Make this an alias resource record set"""
223        self.alias_hosted_zone_id = alias_hosted_zone_id
224        self.alias_dns_name = alias_dns_name
225
226    def to_xml(self):
227        """Spit this resource record set out as XML"""
228        if self.alias_hosted_zone_id != None and self.alias_dns_name != None:
229            # Use alias
230            body = self.AliasBody % (self.alias_hosted_zone_id, self.alias_dns_name)
231        else:
232            # Use resource record(s)
233            records = ""
234            for r in self.resource_records:
235                records += self.ResourceRecordBody % r
236            body = self.ResourceRecordsBody % {
237                "ttl": self.ttl,
238                "records": records,
239            }
240        weight = ""
241        if self.identifier != None and self.weight != None:
242            weight = self.WRRBody % {"identifier": self.identifier, "weight":
243                    self.weight}
244        elif self.identifier != None and self.region != None:
245            weight = self.RRRBody % {"identifier": self.identifier, "region":
246                    self.region}
247        
248        params = {
249            "name": self.name,
250            "type": self.type,
251            "weight": weight,
252            "body": body,
253        }
254        return self.XMLBody % params
255
256    def to_print(self):
257        rr = ""
258        if self.alias_hosted_zone_id != None and self.alias_dns_name != None:
259            # Show alias
260            rr = 'ALIAS ' + self.alias_hosted_zone_id + ' ' + self.alias_dns_name
261        else:
262            # Show resource record(s)
263            rr =  ",".join(self.resource_records)
264
265        if self.identifier != None and self.weight != None:
266            rr += ' (WRR id=%s, w=%s)' % (self.identifier, self.weight)
267
268        return rr
269
270    def endElement(self, name, value, connection):
271        if name == 'Name':
272            self.name = value
273        elif name == 'Type':
274            self.type = value
275        elif name == 'TTL':
276            self.ttl = value
277        elif name == 'Value':
278            self.resource_records.append(value)
279        elif name == 'HostedZoneId':
280            self.alias_hosted_zone_id = value
281        elif name == 'DNSName':
282            self.alias_dns_name = value
283        elif name == 'SetIdentifier':
284            self.identifier = value
285        elif name == 'Weight':
286            self.weight = value
287        elif name == 'Region':
288            self.region = value
289
290    def startElement(self, name, attrs, connection):
291        return None