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 .sqs import mock_sqs
|
||||
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.sqs import sqs_backend
|
||||
from moto.sts import sts_backend
|
||||
from moto.route53 import route53_backend
|
||||
|
||||
BACKENDS = {
|
||||
'autoscaling': autoscaling_backend,
|
||||
@ -20,4 +21,5 @@ BACKENDS = {
|
||||
'ses': ses_backend,
|
||||
'sqs': sqs_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
|
||||
requests
|
||||
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