PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/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. #
  23. import xml.sax
  24. import time
  25. import uuid
  26. import urllib
  27. import boto
  28. from boto.connection import AWSAuthConnection
  29. from boto import handler
  30. from boto.resultset import ResultSet
  31. import boto.jsonresponse
  32. import exception
  33. import hostedzone
  34. HZXML = """<?xml version="1.0" encoding="UTF-8"?>
  35. <CreateHostedZoneRequest xmlns="%(xmlns)s">
  36. <Name>%(name)s</Name>
  37. <CallerReference>%(caller_ref)s</CallerReference>
  38. <HostedZoneConfig>
  39. <Comment>%(comment)s</Comment>
  40. </HostedZoneConfig>
  41. </CreateHostedZoneRequest>"""
  42. #boto.set_stream_logger('dns')
  43. class Route53Connection(AWSAuthConnection):
  44. DefaultHost = 'route53.amazonaws.com'
  45. """The default Route53 API endpoint to connect to."""
  46. Version = '2012-02-29'
  47. """Route53 API version."""
  48. XMLNameSpace = 'https://route53.amazonaws.com/doc/2012-02-29/'
  49. """XML schema for this Route53 API version."""
  50. def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
  51. port=None, proxy=None, proxy_port=None,
  52. host=DefaultHost, debug=0, security_token=None):
  53. AWSAuthConnection.__init__(self, host,
  54. aws_access_key_id, aws_secret_access_key,
  55. True, port, proxy, proxy_port, debug=debug,
  56. security_token=security_token)
  57. def _required_auth_capability(self):
  58. return ['route53']
  59. def _credentials_expired(self, response):
  60. if response.status != 403:
  61. return False
  62. error = exception.DNSServerError('', '', body=response.read())
  63. return error.error_code == 'InvalidClientTokenId'
  64. def make_request(self, action, path, headers=None, data='', params=None):
  65. if params:
  66. pairs = []
  67. for key, val in params.iteritems():
  68. if val is None:
  69. continue
  70. pairs.append(key + '=' + urllib.quote(str(val)))
  71. path += '?' + '&'.join(pairs)
  72. return AWSAuthConnection.make_request(self, action, path,
  73. headers, data)
  74. # Hosted Zones
  75. def get_all_hosted_zones(self, start_marker=None, zone_list=None):
  76. """
  77. Returns a Python data structure with information about all
  78. Hosted Zones defined for the AWS account.
  79. :param int start_marker: start marker to pass when fetching additional
  80. results after a truncated list
  81. :param list zone_list: a HostedZones list to prepend to results
  82. """
  83. params = {}
  84. if start_marker:
  85. params = {'marker': start_marker}
  86. response = self.make_request('GET', '/%s/hostedzone' % self.Version,
  87. params=params)
  88. body = response.read()
  89. boto.log.debug(body)
  90. if response.status >= 300:
  91. raise exception.DNSServerError(response.status,
  92. response.reason,
  93. body)
  94. e = boto.jsonresponse.Element(list_marker='HostedZones',
  95. item_marker=('HostedZone',))
  96. h = boto.jsonresponse.XmlHandler(e, None)
  97. h.parse(body)
  98. if zone_list:
  99. e['ListHostedZonesResponse']['HostedZones'].extend(zone_list)
  100. while 'NextMarker' in e['ListHostedZonesResponse']:
  101. next_marker = e['ListHostedZonesResponse']['NextMarker']
  102. zone_list = e['ListHostedZonesResponse']['HostedZones']
  103. e = self.get_all_hosted_zones(next_marker, zone_list)
  104. return e
  105. def get_hosted_zone(self, hosted_zone_id):
  106. """
  107. Get detailed information about a particular Hosted Zone.
  108. :type hosted_zone_id: str
  109. :param hosted_zone_id: The unique identifier for the Hosted Zone
  110. """
  111. uri = '/%s/hostedzone/%s' % (self.Version, hosted_zone_id)
  112. response = self.make_request('GET', uri)
  113. body = response.read()
  114. boto.log.debug(body)
  115. if response.status >= 300:
  116. raise exception.DNSServerError(response.status,
  117. response.reason,
  118. body)
  119. e = boto.jsonresponse.Element(list_marker='NameServers',
  120. item_marker=('NameServer',))
  121. h = boto.jsonresponse.XmlHandler(e, None)
  122. h.parse(body)
  123. return e
  124. def get_hosted_zone_by_name(self, hosted_zone_name):
  125. """
  126. Get detailed information about a particular Hosted Zone.
  127. :type hosted_zone_name: str
  128. :param hosted_zone_name: The fully qualified domain name for the Hosted
  129. Zone
  130. """
  131. if hosted_zone_name[-1] != '.':
  132. hosted_zone_name += '.'
  133. all_hosted_zones = self.get_all_hosted_zones()
  134. for zone in all_hosted_zones['ListHostedZonesResponse']['HostedZones']:
  135. #check that they gave us the FQDN for their zone
  136. if zone['Name'] == hosted_zone_name:
  137. return self.get_hosted_zone(zone['Id'].split('/')[-1])
  138. def create_hosted_zone(self, domain_name, caller_ref=None, comment=''):
  139. """
  140. Create a new Hosted Zone. Returns a Python data structure with
  141. information about the newly created Hosted Zone.
  142. :type domain_name: str
  143. :param domain_name: The name of the domain. This should be a
  144. fully-specified domain, and should end with a final period
  145. as the last label indication. If you omit the final period,
  146. Amazon Route 53 assumes the domain is relative to the root.
  147. This is the name you have registered with your DNS registrar.
  148. It is also the name you will delegate from your registrar to
  149. the Amazon Route 53 delegation servers returned in
  150. response to this request.A list of strings with the image
  151. IDs wanted.
  152. :type caller_ref: str
  153. :param caller_ref: A unique string that identifies the request
  154. and that allows failed CreateHostedZone requests to be retried
  155. without the risk of executing the operation twice. If you don't
  156. provide a value for this, boto will generate a Type 4 UUID and
  157. use that.
  158. :type comment: str
  159. :param comment: Any comments you want to include about the hosted
  160. zone.
  161. """
  162. if caller_ref is None:
  163. caller_ref = str(uuid.uuid4())
  164. params = {'name': domain_name,
  165. 'caller_ref': caller_ref,
  166. 'comment': comment,
  167. 'xmlns': self.XMLNameSpace}
  168. xml = HZXML % params
  169. uri = '/%s/hostedzone' % self.Version
  170. response = self.make_request('POST', uri,
  171. {'Content-Type': 'text/xml'}, xml)
  172. body = response.read()
  173. boto.log.debug(body)
  174. if response.status == 201:
  175. e = boto.jsonresponse.Element(list_marker='NameServers',
  176. item_marker=('NameServer',))
  177. h = boto.jsonresponse.XmlHandler(e, None)
  178. h.parse(body)
  179. return e
  180. else:
  181. raise exception.DNSServerError(response.status,
  182. response.reason,
  183. body)
  184. def delete_hosted_zone(self, hosted_zone_id):
  185. uri = '/%s/hostedzone/%s' % (self.Version, hosted_zone_id)
  186. response = self.make_request('DELETE', uri)
  187. body = response.read()
  188. boto.log.debug(body)
  189. if response.status not in (200, 204):
  190. raise exception.DNSServerError(response.status,
  191. response.reason,
  192. body)
  193. e = boto.jsonresponse.Element()
  194. h = boto.jsonresponse.XmlHandler(e, None)
  195. h.parse(body)
  196. return e
  197. # Resource Record Sets
  198. def get_all_rrsets(self, hosted_zone_id, type=None,
  199. name=None, identifier=None, maxitems=None):
  200. """
  201. Retrieve the Resource Record Sets defined for this Hosted Zone.
  202. Returns the raw XML data returned by the Route53 call.
  203. :type hosted_zone_id: str
  204. :param hosted_zone_id: The unique identifier for the Hosted Zone
  205. :type type: str
  206. :param type: The type of resource record set to begin the record
  207. listing from. Valid choices are:
  208. * A
  209. * AAAA
  210. * CNAME
  211. * MX
  212. * NS
  213. * PTR
  214. * SOA
  215. * SPF
  216. * SRV
  217. * TXT
  218. Valid values for weighted resource record sets:
  219. * A
  220. * AAAA
  221. * CNAME
  222. * TXT
  223. Valid values for Zone Apex Aliases:
  224. * A
  225. * AAAA
  226. :type name: str
  227. :param name: The first name in the lexicographic ordering of domain
  228. names to be retrieved
  229. :type identifier: str
  230. :param identifier: In a hosted zone that includes weighted resource
  231. record sets (multiple resource record sets with the same DNS
  232. name and type that are differentiated only by SetIdentifier),
  233. if results were truncated for a given DNS name and type,
  234. the value of SetIdentifier for the next resource record
  235. set that has the current DNS name and type
  236. :type maxitems: int
  237. :param maxitems: The maximum number of records
  238. """
  239. from boto.route53.record import ResourceRecordSets
  240. params = {'type': type, 'name': name,
  241. 'Identifier': identifier, 'maxitems': maxitems}
  242. uri = '/%s/hostedzone/%s/rrset' % (self.Version, hosted_zone_id)
  243. response = self.make_request('GET', uri, params=params)
  244. body = response.read()
  245. boto.log.debug(body)
  246. if response.status >= 300:
  247. raise exception.DNSServerError(response.status,
  248. response.reason,
  249. body)
  250. rs = ResourceRecordSets(connection=self, hosted_zone_id=hosted_zone_id)
  251. h = handler.XmlHandler(rs, self)
  252. xml.sax.parseString(body, h)
  253. return rs
  254. def change_rrsets(self, hosted_zone_id, xml_body):
  255. """
  256. Create or change the authoritative DNS information for this
  257. Hosted Zone.
  258. Returns a Python data structure with information about the set of
  259. changes, including the Change ID.
  260. :type hosted_zone_id: str
  261. :param hosted_zone_id: The unique identifier for the Hosted Zone
  262. :type xml_body: str
  263. :param xml_body: The list of changes to be made, defined in the
  264. XML schema defined by the Route53 service.
  265. """
  266. uri = '/%s/hostedzone/%s/rrset' % (self.Version, hosted_zone_id)
  267. response = self.make_request('POST', uri,
  268. {'Content-Type': 'text/xml'},
  269. xml_body)
  270. body = response.read()
  271. boto.log.debug(body)
  272. if response.status >= 300:
  273. raise exception.DNSServerError(response.status,
  274. response.reason,
  275. body)
  276. e = boto.jsonresponse.Element()
  277. h = boto.jsonresponse.XmlHandler(e, None)
  278. h.parse(body)
  279. return e
  280. def get_change(self, change_id):
  281. """
  282. Get information about a proposed set of changes, as submitted
  283. by the change_rrsets method.
  284. Returns a Python data structure with status information about the
  285. changes.
  286. :type change_id: str
  287. :param change_id: The unique identifier for the set of changes.
  288. This ID is returned in the response to the change_rrsets method.
  289. """
  290. uri = '/%s/change/%s' % (self.Version, change_id)
  291. response = self.make_request('GET', uri)
  292. body = response.read()
  293. boto.log.debug(body)
  294. if response.status >= 300:
  295. raise exception.DNSServerError(response.status,
  296. response.reason,
  297. body)
  298. e = boto.jsonresponse.Element()
  299. h = boto.jsonresponse.XmlHandler(e, None)
  300. h.parse(body)
  301. return e