PageRenderTime 59ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 1ms

/boto-2.5.2/boto/route53/connection.py

#
Python | 347 lines | 323 code | 2 blank | 22 comment | 0 complexity | 5859c1f6ca6cf7615e5a4c248b724138 MD5 | raw file
  1# Copyright (c) 2006-2010 Mitch Garnaat http://garnaat.org/
  2# Copyright (c) 2010, Eucalyptus Systems, Inc.
  3#
  4# Permission is hereby granted, free of charge, to any person obtaining a
  5# copy of this software and associated documentation files (the
  6# "Software"), to deal in the Software without restriction, including
  7# without limitation the rights to use, copy, modify, merge, publish, dis-
  8# tribute, sublicense, and/or sell copies of the Software, and to permit
  9# persons to whom the Software is furnished to do so, subject to the fol-
 10# lowing conditions:
 11#
 12# The above copyright notice and this permission notice shall be included
 13# in all copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 17# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 18# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21# IN THE SOFTWARE.
 22#
 23import xml.sax
 24import time
 25import uuid
 26import urllib
 27
 28import boto
 29from boto.connection import AWSAuthConnection
 30from boto import handler
 31from boto.resultset import ResultSet
 32import boto.jsonresponse
 33import exception
 34import hostedzone
 35
 36HZXML = """<?xml version="1.0" encoding="UTF-8"?>
 37<CreateHostedZoneRequest xmlns="%(xmlns)s">
 38  <Name>%(name)s</Name>
 39  <CallerReference>%(caller_ref)s</CallerReference>
 40  <HostedZoneConfig>
 41    <Comment>%(comment)s</Comment>
 42  </HostedZoneConfig>
 43</CreateHostedZoneRequest>"""
 44
 45#boto.set_stream_logger('dns')
 46
 47
 48class Route53Connection(AWSAuthConnection):
 49    DefaultHost = 'route53.amazonaws.com'
 50    """The default Route53 API endpoint to connect to."""
 51
 52    Version = '2012-02-29'
 53    """Route53 API version."""
 54
 55    XMLNameSpace = 'https://route53.amazonaws.com/doc/2012-02-29/'
 56    """XML schema for this Route53 API version."""
 57
 58    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
 59                 port=None, proxy=None, proxy_port=None,
 60                 host=DefaultHost, debug=0, security_token=None):
 61        AWSAuthConnection.__init__(self, host,
 62                                   aws_access_key_id, aws_secret_access_key,
 63                                   True, port, proxy, proxy_port, debug=debug,
 64                                   security_token=security_token)
 65
 66    def _required_auth_capability(self):
 67        return ['route53']
 68
 69    def _credentials_expired(self, response):
 70        if response.status != 403:
 71            return False
 72        error = exception.DNSServerError('', '', body=response.read())
 73        return error.error_code == 'InvalidClientTokenId'
 74
 75    def make_request(self, action, path, headers=None, data='', params=None):
 76        if params:
 77            pairs = []
 78            for key, val in params.iteritems():
 79                if val is None:
 80                    continue
 81                pairs.append(key + '=' + urllib.quote(str(val)))
 82            path += '?' + '&'.join(pairs)
 83        return AWSAuthConnection.make_request(self, action, path,
 84                                              headers, data)
 85
 86    # Hosted Zones
 87
 88    def get_all_hosted_zones(self, start_marker=None, zone_list=None):
 89        """
 90        Returns a Python data structure with information about all
 91        Hosted Zones defined for the AWS account.
 92
 93        :param int start_marker: start marker to pass when fetching additional
 94            results after a truncated list
 95        :param list zone_list: a HostedZones list to prepend to results
 96        """
 97        params = {}
 98        if start_marker:
 99            params = {'marker': start_marker}
100        response = self.make_request('GET', '/%s/hostedzone' % self.Version,
101                params=params)
102        body = response.read()
103        boto.log.debug(body)
104        if response.status >= 300:
105            raise exception.DNSServerError(response.status,
106                                           response.reason,
107                                           body)
108        e = boto.jsonresponse.Element(list_marker='HostedZones',
109                                      item_marker=('HostedZone',))
110        h = boto.jsonresponse.XmlHandler(e, None)
111        h.parse(body)
112        if zone_list:
113            e['ListHostedZonesResponse']['HostedZones'].extend(zone_list)
114        while 'NextMarker' in e['ListHostedZonesResponse']:
115            next_marker = e['ListHostedZonesResponse']['NextMarker']
116            zone_list = e['ListHostedZonesResponse']['HostedZones']
117            e = self.get_all_hosted_zones(next_marker, zone_list)
118        return e
119
120    def get_hosted_zone(self, hosted_zone_id):
121        """
122        Get detailed information about a particular Hosted Zone.
123
124        :type hosted_zone_id: str
125        :param hosted_zone_id: The unique identifier for the Hosted Zone
126
127        """
128        uri = '/%s/hostedzone/%s' % (self.Version, hosted_zone_id)
129        response = self.make_request('GET', uri)
130        body = response.read()
131        boto.log.debug(body)
132        if response.status >= 300:
133            raise exception.DNSServerError(response.status,
134                                           response.reason,
135                                           body)
136        e = boto.jsonresponse.Element(list_marker='NameServers',
137                                      item_marker=('NameServer',))
138        h = boto.jsonresponse.XmlHandler(e, None)
139        h.parse(body)
140        return e
141
142    def get_hosted_zone_by_name(self, hosted_zone_name):
143        """
144        Get detailed information about a particular Hosted Zone.
145
146        :type hosted_zone_name: str
147        :param hosted_zone_name: The fully qualified domain name for the Hosted
148        Zone
149
150        """
151        if hosted_zone_name[-1] != '.':
152            hosted_zone_name += '.'
153        all_hosted_zones = self.get_all_hosted_zones()
154        for zone in all_hosted_zones['ListHostedZonesResponse']['HostedZones']:
155            #check that they gave us the FQDN for their zone
156            if zone['Name'] == hosted_zone_name:
157                return self.get_hosted_zone(zone['Id'].split('/')[-1])
158
159    def create_hosted_zone(self, domain_name, caller_ref=None, comment=''):
160        """
161        Create a new Hosted Zone.  Returns a Python data structure with
162        information about the newly created Hosted Zone.
163
164        :type domain_name: str
165        :param domain_name: The name of the domain. This should be a
166            fully-specified domain, and should end with a final period
167            as the last label indication.  If you omit the final period,
168            Amazon Route 53 assumes the domain is relative to the root.
169            This is the name you have registered with your DNS registrar.
170            It is also the name you will delegate from your registrar to
171            the Amazon Route 53 delegation servers returned in
172            response to this request.A list of strings with the image
173            IDs wanted.
174
175        :type caller_ref: str
176        :param caller_ref: A unique string that identifies the request
177            and that allows failed CreateHostedZone requests to be retried
178            without the risk of executing the operation twice.  If you don't
179            provide a value for this, boto will generate a Type 4 UUID and
180            use that.
181
182        :type comment: str
183        :param comment: Any comments you want to include about the hosted
184            zone.
185
186        """
187        if caller_ref is None:
188            caller_ref = str(uuid.uuid4())
189        params = {'name': domain_name,
190                  'caller_ref': caller_ref,
191                  'comment': comment,
192                  'xmlns': self.XMLNameSpace}
193        xml = HZXML % params
194        uri = '/%s/hostedzone' % self.Version
195        response = self.make_request('POST', uri,
196                                     {'Content-Type': 'text/xml'}, xml)
197        body = response.read()
198        boto.log.debug(body)
199        if response.status == 201:
200            e = boto.jsonresponse.Element(list_marker='NameServers',
201                                          item_marker=('NameServer',))
202            h = boto.jsonresponse.XmlHandler(e, None)
203            h.parse(body)
204            return e
205        else:
206            raise exception.DNSServerError(response.status,
207                                           response.reason,
208                                           body)
209
210    def delete_hosted_zone(self, hosted_zone_id):
211        uri = '/%s/hostedzone/%s' % (self.Version, hosted_zone_id)
212        response = self.make_request('DELETE', uri)
213        body = response.read()
214        boto.log.debug(body)
215        if response.status not in (200, 204):
216            raise exception.DNSServerError(response.status,
217                                           response.reason,
218                                           body)
219        e = boto.jsonresponse.Element()
220        h = boto.jsonresponse.XmlHandler(e, None)
221        h.parse(body)
222        return e
223
224    # Resource Record Sets
225
226    def get_all_rrsets(self, hosted_zone_id, type=None,
227                       name=None, identifier=None, maxitems=None):
228        """
229        Retrieve the Resource Record Sets defined for this Hosted Zone.
230        Returns the raw XML data returned by the Route53 call.
231
232        :type hosted_zone_id: str
233        :param hosted_zone_id: The unique identifier for the Hosted Zone
234
235        :type type: str
236        :param type: The type of resource record set to begin the record
237            listing from.  Valid choices are:
238
239                * A
240                * AAAA
241                * CNAME
242                * MX
243                * NS
244                * PTR
245                * SOA
246                * SPF
247                * SRV
248                * TXT
249
250            Valid values for weighted resource record sets:
251
252                * A
253                * AAAA
254                * CNAME
255                * TXT
256
257            Valid values for Zone Apex Aliases:
258
259                * A
260                * AAAA
261
262        :type name: str
263        :param name: The first name in the lexicographic ordering of domain
264                     names to be retrieved
265
266        :type identifier: str
267        :param identifier: In a hosted zone that includes weighted resource
268            record sets (multiple resource record sets with the same DNS
269            name and type that are differentiated only by SetIdentifier),
270            if results were truncated for a given DNS name and type,
271            the value of SetIdentifier for the next resource record
272            set that has the current DNS name and type
273
274        :type maxitems: int
275        :param maxitems: The maximum number of records
276
277        """
278        from boto.route53.record import ResourceRecordSets
279        params = {'type': type, 'name': name,
280                  'Identifier': identifier, 'maxitems': maxitems}
281        uri = '/%s/hostedzone/%s/rrset' % (self.Version, hosted_zone_id)
282        response = self.make_request('GET', uri, params=params)
283        body = response.read()
284        boto.log.debug(body)
285        if response.status >= 300:
286            raise exception.DNSServerError(response.status,
287                                           response.reason,
288                                           body)
289        rs = ResourceRecordSets(connection=self, hosted_zone_id=hosted_zone_id)
290        h = handler.XmlHandler(rs, self)
291        xml.sax.parseString(body, h)
292        return rs
293
294    def change_rrsets(self, hosted_zone_id, xml_body):
295        """
296        Create or change the authoritative DNS information for this
297        Hosted Zone.
298        Returns a Python data structure with information about the set of
299        changes, including the Change ID.
300
301        :type hosted_zone_id: str
302        :param hosted_zone_id: The unique identifier for the Hosted Zone
303
304        :type xml_body: str
305        :param xml_body: The list of changes to be made, defined in the
306            XML schema defined by the Route53 service.
307
308        """
309        uri = '/%s/hostedzone/%s/rrset' % (self.Version, hosted_zone_id)
310        response = self.make_request('POST', uri,
311                                     {'Content-Type': 'text/xml'},
312                                     xml_body)
313        body = response.read()
314        boto.log.debug(body)
315        if response.status >= 300:
316            raise exception.DNSServerError(response.status,
317                                           response.reason,
318                                           body)
319        e = boto.jsonresponse.Element()
320        h = boto.jsonresponse.XmlHandler(e, None)
321        h.parse(body)
322        return e
323
324    def get_change(self, change_id):
325        """
326        Get information about a proposed set of changes, as submitted
327        by the change_rrsets method.
328        Returns a Python data structure with status information about the
329        changes.
330
331        :type change_id: str
332        :param change_id: The unique identifier for the set of changes.
333            This ID is returned in the response to the change_rrsets method.
334
335        """
336        uri = '/%s/change/%s' % (self.Version, change_id)
337        response = self.make_request('GET', uri)
338        body = response.read()
339        boto.log.debug(body)
340        if response.status >= 300:
341            raise exception.DNSServerError(response.status,
342                                           response.reason,
343                                           body)
344        e = boto.jsonresponse.Element()
345        h = boto.jsonresponse.XmlHandler(e, None)
346        h.parse(body)
347        return e