add route53
This commit is contained in:
parent
d5b3af202e
commit
a11c80fe20
@ -11,3 +11,4 @@ from .s3bucket_path import mock_s3bucket_path
|
|||||||
from .ses import mock_ses
|
from .ses import mock_ses
|
||||||
from .sqs import mock_sqs
|
from .sqs import mock_sqs
|
||||||
from .sts import mock_sts
|
from .sts import mock_sts
|
||||||
|
from .route53 import mock_route53
|
||||||
|
@ -8,6 +8,7 @@ from moto.s3bucket_path import s3bucket_path_backend
|
|||||||
from moto.ses import ses_backend
|
from moto.ses import ses_backend
|
||||||
from moto.sqs import sqs_backend
|
from moto.sqs import sqs_backend
|
||||||
from moto.sts import sts_backend
|
from moto.sts import sts_backend
|
||||||
|
from moto.route53 import route53_backend
|
||||||
|
|
||||||
BACKENDS = {
|
BACKENDS = {
|
||||||
'autoscaling': autoscaling_backend,
|
'autoscaling': autoscaling_backend,
|
||||||
@ -20,4 +21,5 @@ BACKENDS = {
|
|||||||
'ses': ses_backend,
|
'ses': ses_backend,
|
||||||
'sqs': sqs_backend,
|
'sqs': sqs_backend,
|
||||||
'sts': sts_backend,
|
'sts': sts_backend,
|
||||||
|
'route53': route53_backend
|
||||||
}
|
}
|
||||||
|
2
moto/route53/__init__.py
Normal file
2
moto/route53/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .models import route53_backend
|
||||||
|
mock_route53 = route53_backend.decorator
|
57
moto/route53/models.py
Normal file
57
moto/route53/models.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from moto.core import BaseBackend
|
||||||
|
from moto.core.utils import get_random_hex
|
||||||
|
|
||||||
|
|
||||||
|
class FakeZone:
|
||||||
|
|
||||||
|
def __init__(self, name, id):
|
||||||
|
self.name = name
|
||||||
|
self.id = id
|
||||||
|
self.rrsets = {}
|
||||||
|
|
||||||
|
def add_rrset(self, name, rrset):
|
||||||
|
self.rrsets[name] = rrset
|
||||||
|
|
||||||
|
def delete_rrset(self, name):
|
||||||
|
del self.rrsets[name]
|
||||||
|
|
||||||
|
|
||||||
|
class FakeResourceRecord:
|
||||||
|
def __init__(self, value):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FakeResourceRecordSet:
|
||||||
|
def __init__(self, name, type, ttl, rrlist):
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
self.ttl = ttl
|
||||||
|
self.rrList = rrlist
|
||||||
|
|
||||||
|
class Route53Backend(BaseBackend):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.zones = {}
|
||||||
|
|
||||||
|
def create_hosted_zone(self, name):
|
||||||
|
new_id = get_random_hex()
|
||||||
|
new_zone = FakeZone(name, new_id)
|
||||||
|
self.zones[new_id] = new_zone
|
||||||
|
return new_zone
|
||||||
|
|
||||||
|
def get_all_hosted_zones(self):
|
||||||
|
return self.zones.values()
|
||||||
|
|
||||||
|
def get_hosted_zone(self, id):
|
||||||
|
return self.zones.get(id)
|
||||||
|
|
||||||
|
def delete_hosted_zone(self, id):
|
||||||
|
zone = self.zones.get(id)
|
||||||
|
if zone:
|
||||||
|
del self.zones[id]
|
||||||
|
return zone
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
route53_backend = Route53Backend()
|
||||||
|
|
||||||
|
|
130
moto/route53/responses.py
Normal file
130
moto/route53/responses.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
from jinja2 import Template
|
||||||
|
from urlparse import parse_qs, urlparse
|
||||||
|
from .models import route53_backend
|
||||||
|
import xmltodict
|
||||||
|
import dicttoxml
|
||||||
|
|
||||||
|
|
||||||
|
def list_or_create_hostzone_response(request, full_url, headers):
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
r = xmltodict.parse(request.body)
|
||||||
|
new_zone = route53_backend.create_hosted_zone(r["CreateHostedZoneRequest"]["Name"])
|
||||||
|
template = Template(CREATE_HOSTED_ZONE_RESPONSE)
|
||||||
|
return 201, headers, template.render(zone=new_zone)
|
||||||
|
|
||||||
|
elif request.method == "GET":
|
||||||
|
all_zones = route53_backend.get_all_hosted_zones()
|
||||||
|
template = Template(LIST_HOSTED_ZONES_RESPONSE)
|
||||||
|
return 200, headers, template.render(zones=all_zones)
|
||||||
|
|
||||||
|
|
||||||
|
def get_or_delete_hostzone_response(request, full_url, headers):
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
zoneid = parsed_url.path.rstrip('/').rsplit('/', 1)[1]
|
||||||
|
the_zone = route53_backend.get_hosted_zone(zoneid)
|
||||||
|
if not the_zone:
|
||||||
|
return 404, headers, "Zone %s not Found" % zoneid
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
template = Template(GET_HOSTED_ZONE_RESPONSE)
|
||||||
|
return 200, headers, template.render(zone=the_zone)
|
||||||
|
elif request.method == "DELETE":
|
||||||
|
route53_backend.delete_hosted_zone(zoneid)
|
||||||
|
return 200, headers, DELETE_HOSTED_ZONE_RESPONSE
|
||||||
|
|
||||||
|
def rrset_response(request, full_url, headers):
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
method = request.method
|
||||||
|
|
||||||
|
zoneid = parsed_url.path.rstrip('/').rsplit('/', 2)[1]
|
||||||
|
the_zone = route53_backend.get_hosted_zone(zoneid)
|
||||||
|
if not the_zone:
|
||||||
|
return 404, headers, "Zone %s Not Found" % zoneid
|
||||||
|
|
||||||
|
if method == "POST":
|
||||||
|
r = xmltodict.parse(request.body)
|
||||||
|
for k, v in r['ChangeResourceRecordSetsRequest']['ChangeBatch']['Changes'].items():
|
||||||
|
action = v['Action']
|
||||||
|
rrset = v['ResourceRecordSet']
|
||||||
|
|
||||||
|
if action == 'CREATE':
|
||||||
|
the_zone.add_rrset(rrset["Name"], rrset)
|
||||||
|
elif action == "DELETE":
|
||||||
|
the_zone.delete_rrset(rrset["Name"])
|
||||||
|
|
||||||
|
return 200, headers, CHANGE_RRSET_RESPONSE
|
||||||
|
|
||||||
|
elif method == "GET":
|
||||||
|
querystring = parse_qs(parsed_url.query)
|
||||||
|
template = Template(LIST_RRSET_REPONSE)
|
||||||
|
rrset_list = []
|
||||||
|
for key, value in the_zone.rrsets.items():
|
||||||
|
if 'type' not in querystring or querystring["type"][0] == value["Type"]:
|
||||||
|
rrset_list.append(dicttoxml.dicttoxml({"ResourceRecordSet": value}, root=False))
|
||||||
|
|
||||||
|
return 200, headers, template.render(rrsets=rrset_list)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def not_implemented_response(request, full_url, headers):
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
raise NotImplementedError('handling of %s is not yet implemented' % parsed_url.path)
|
||||||
|
|
||||||
|
|
||||||
|
LIST_RRSET_REPONSE = """<ListResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<ResourceRecordSets>
|
||||||
|
{% for rrset in rrsets %}
|
||||||
|
{{ rrset }}
|
||||||
|
{% endfor %}
|
||||||
|
</ResourceRecordSets>
|
||||||
|
</ListResourceRecordSetsResponse>"""
|
||||||
|
|
||||||
|
CHANGE_RRSET_RESPONSE = """<ChangeResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<ChangeInfo>
|
||||||
|
<Status>PENDING</Status>
|
||||||
|
<SubmittedAt>2010-09-10T01:36:41.958Z</SubmittedAt>
|
||||||
|
</ChangeInfo>
|
||||||
|
</ChangeResourceRecordSetsResponse>"""
|
||||||
|
|
||||||
|
DELETE_HOSTED_ZONE_RESPONSE = """<DeleteHostedZoneResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<ChangeInfo>
|
||||||
|
</ChangeInfo>
|
||||||
|
</DeleteHostedZoneResponse>"""
|
||||||
|
|
||||||
|
GET_HOSTED_ZONE_RESPONSE = """<GetHostedZoneResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<HostedZone>
|
||||||
|
<Id>/hostedzone/{{ zone.id }}</Id>
|
||||||
|
<Name>{{ zone.name }}</Name>
|
||||||
|
<ResourceRecordSetCount>{{ zone.rrsets|count }}</ResourceRecordSetCount>
|
||||||
|
</HostedZone>
|
||||||
|
<DelegationSet>
|
||||||
|
<NameServer>moto.test.com</NameServer>
|
||||||
|
</DelegationSet>
|
||||||
|
</GetHostedZoneResponse>"""
|
||||||
|
|
||||||
|
CREATE_HOSTED_ZONE_RESPONSE = """<CreateHostedZoneResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<HostedZone>
|
||||||
|
<Id>/hostedzone/{{ zone.id }}</Id>
|
||||||
|
<Name>{{ zone.name }}</Name>
|
||||||
|
<ResourceRecordSetCount>0</ResourceRecordSetCount>
|
||||||
|
</HostedZone>
|
||||||
|
<DelegationSet>
|
||||||
|
<NameServers>
|
||||||
|
<NameServer>moto.test.com</NameServer>
|
||||||
|
</NameServers>
|
||||||
|
</DelegationSet>
|
||||||
|
</CreateHostedZoneResponse>"""
|
||||||
|
|
||||||
|
LIST_HOSTED_ZONES_RESPONSE = """<ListHostedZonesResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||||
|
<HostedZones>
|
||||||
|
{% for zone in zones %}
|
||||||
|
<HostedZone>
|
||||||
|
<Id>{{ zone.id }}</Id>
|
||||||
|
<Name>{{ zone.name }}</Name>
|
||||||
|
<ResourceRecordSetCount>{{ zone.rrsets|count }}</ResourceRecordSetCount>
|
||||||
|
</HostedZone>
|
||||||
|
{% endfor %}
|
||||||
|
</HostedZones>
|
||||||
|
</ListHostedZonesResponse>"""
|
||||||
|
|
12
moto/route53/urls.py
Normal file
12
moto/route53/urls.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import responses
|
||||||
|
|
||||||
|
url_bases = [
|
||||||
|
#"https://route53.amazonaws.com/201\d-\d\d-\d\d/hostedzone",
|
||||||
|
"https://route53.amazonaws.com/201.-..-../hostedzone",
|
||||||
|
]
|
||||||
|
|
||||||
|
url_paths = {
|
||||||
|
'{0}$': responses.list_or_create_hostzone_response,
|
||||||
|
'{0}/.+$': responses.get_or_delete_hostzone_response,
|
||||||
|
'{0}/.+/rrset$': responses.rrset_response,
|
||||||
|
}
|
@ -5,3 +5,5 @@ nose
|
|||||||
https://github.com/spulec/python-coveralls/tarball/796d9dba34b759664e42ba39e6414209a0f319ad
|
https://github.com/spulec/python-coveralls/tarball/796d9dba34b759664e42ba39e6414209a0f319ad
|
||||||
requests
|
requests
|
||||||
sure
|
sure
|
||||||
|
xmltodict
|
||||||
|
dicttoxml
|
||||||
|
69
tests/test_route53/test_route53.py
Normal file
69
tests/test_route53/test_route53.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import urllib2
|
||||||
|
|
||||||
|
import boto
|
||||||
|
from boto.exception import S3ResponseError
|
||||||
|
from boto.s3.key import Key
|
||||||
|
from boto.route53.record import ResourceRecordSets
|
||||||
|
from freezegun import freeze_time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import sure # noqa
|
||||||
|
|
||||||
|
from moto import mock_route53
|
||||||
|
|
||||||
|
|
||||||
|
@mock_route53
|
||||||
|
def test_hosted_zone():
|
||||||
|
conn = boto.connect_route53('the_key', 'the_secret')
|
||||||
|
firstzone = conn.create_hosted_zone("testdns.aws.com")
|
||||||
|
zones = conn.get_all_hosted_zones()
|
||||||
|
len(zones["ListHostedZonesResponse"]["HostedZones"]).should.equal(1)
|
||||||
|
|
||||||
|
secondzone = conn.create_hosted_zone("testdns1.aws.com")
|
||||||
|
zones = conn.get_all_hosted_zones()
|
||||||
|
len(zones["ListHostedZonesResponse"]["HostedZones"]).should.equal(2)
|
||||||
|
|
||||||
|
id1 = firstzone["CreateHostedZoneResponse"]["HostedZone"]["Id"]
|
||||||
|
zone = conn.get_hosted_zone(id1)
|
||||||
|
zone["GetHostedZoneResponse"]["HostedZone"]["Name"].should.equal("testdns.aws.com")
|
||||||
|
|
||||||
|
conn.delete_hosted_zone(id1)
|
||||||
|
zones = conn.get_all_hosted_zones()
|
||||||
|
len(zones["ListHostedZonesResponse"]["HostedZones"]).should.equal(1)
|
||||||
|
|
||||||
|
conn.get_hosted_zone.when.called_with("abcd").should.throw(boto.route53.exception.DNSServerError, "404 Not Found")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_route53
|
||||||
|
def test_rrset():
|
||||||
|
conn = boto.connect_route53('the_key', 'the_secret')
|
||||||
|
zone = conn.create_hosted_zone("testdns.aws.com")
|
||||||
|
zoneid = zone["CreateHostedZoneResponse"]["HostedZone"]["Id"]
|
||||||
|
|
||||||
|
changes = ResourceRecordSets(conn, zoneid)
|
||||||
|
change = changes.add_change("CREATE", "foo.bar.testdns.aws.com", "A")
|
||||||
|
change.add_value("1.2.3.4")
|
||||||
|
changes.commit()
|
||||||
|
|
||||||
|
rrsets = conn.get_all_rrsets(zoneid, type="A")
|
||||||
|
rrsets.should.have.length_of(1)
|
||||||
|
rrsets[0].resource_records[0].should.equal('1.2.3.4')
|
||||||
|
|
||||||
|
rrsets = conn.get_all_rrsets(zoneid, type="CNAME")
|
||||||
|
rrsets.should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
changes = ResourceRecordSets(conn, zoneid)
|
||||||
|
changes.add_change("DELETE", "foo.bar.testdns.aws.com", "A")
|
||||||
|
changes.commit()
|
||||||
|
|
||||||
|
rrsets = conn.get_all_rrsets(zoneid)
|
||||||
|
rrsets.should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user