Add support and unittests for Route53 tags

This commit is contained in:
Alfred Moreno 2016-09-20 17:41:23 -07:00
parent 97513590c8
commit 9a7556b3af
4 changed files with 136 additions and 2 deletions

View File

@ -1,5 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from collections import defaultdict
import uuid import uuid
from jinja2 import Template from jinja2 import Template
@ -226,6 +228,7 @@ class Route53Backend(BaseBackend):
def __init__(self): def __init__(self):
self.zones = {} self.zones = {}
self.health_checks = {} self.health_checks = {}
self.resource_tags = defaultdict(dict)
def create_hosted_zone(self, name, private_zone, comment=None): def create_hosted_zone(self, name, private_zone, comment=None):
new_id = get_random_hex() new_id = get_random_hex()
@ -233,6 +236,25 @@ class Route53Backend(BaseBackend):
self.zones[new_id] = new_zone self.zones[new_id] = new_zone
return new_zone return new_zone
def change_tags_for_resource(self, resource_id, tags):
if 'Tag' in tags:
for key, tag in tags.items():
for t in tag:
self.resource_tags[resource_id][t['Key']] = t['Value']
else:
for _, keys in tags.items():
if isinstance(keys, list):
for key in keys:
del(self.resource_tags[resource_id][key])
else:
del(self.resource_tags[resource_id][keys])
def list_tags_for_resource(self, resource_id):
if resource_id in self.resource_tags:
return self.resource_tags[resource_id]
def get_all_hosted_zones(self): def get_all_hosted_zones(self):
return self.zones.values() return self.zones.values()

View File

@ -138,6 +138,52 @@ def not_implemented_response(request, full_url, headers):
raise NotImplementedError("The action for {0} has not been implemented for route 53".format(action)) raise NotImplementedError("The action for {0} has not been implemented for route 53".format(action))
def list_or_change_tags_for_resource_request(request, full_url, headers):
parsed_url = urlparse(full_url)
id_ = parsed_url.path.split("/")[-1]
type_ = parsed_url.path.split("/")[-2]
if request.method == "GET":
tags = route53_backend.list_tags_for_resource(id_)
template = Template(LIST_TAGS_FOR_RESOURCE_RESPONSE)
return 200, headers, template.render(
resource_type=type_, resource_id=id_, tags=tags)
if request.method == "POST":
tags = xmltodict.parse(
request.body)['ChangeTagsForResourceRequest']
if 'AddTags' in tags:
tags = tags['AddTags']
elif 'RemoveTagKeys' in tags:
tags = tags['RemoveTagKeys']
route53_backend.change_tags_for_resource(id_, tags)
template = Template(CHANGE_TAGS_FOR_RESOURCE_RESPONSE)
return 200, headers, template.render()
LIST_TAGS_FOR_RESOURCE_RESPONSE = """
<ListTagsForResourceResponse xmlns="https://route53.amazonaws.com/doc/2015-01-01/">
<ResourceTagSet>
<ResourceType>{{resource_type}}</ResourceType>
<ResourceId>{{resource_id}}</ResourceId>
<Tags>
{% for key, value in tags.items() %}
<Tag>
<Key>{{key}}</Key>
<Value>{{value}}</Value>
</Tag>
{% endfor %}
</Tags>
</ResourceTagSet>
</ListTagsForResourceResponse>
"""
CHANGE_TAGS_FOR_RESOURCE_RESPONSE = """<ChangeTagsForResourceResponse xmlns="https://route53.amazonaws.com/doc/2015-01-01/">
</ChangeTagsForResourceResponse>
"""
LIST_RRSET_REPONSE = """<ListResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/"> LIST_RRSET_REPONSE = """<ListResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
<ResourceRecordSets> <ResourceRecordSets>
{% for record_set in record_sets %} {% for record_set in record_sets %}

View File

@ -10,5 +10,6 @@ url_paths = {
'{0}hostedzone/[^/]+$': responses.get_or_delete_hostzone_response, '{0}hostedzone/[^/]+$': responses.get_or_delete_hostzone_response,
'{0}hostedzone/[^/]+/rrset/?$': responses.rrset_response, '{0}hostedzone/[^/]+/rrset/?$': responses.rrset_response,
'{0}healthcheck': responses.health_check_response, '{0}healthcheck': responses.health_check_response,
'{0}tags|trafficpolicyinstances/*': responses.not_implemented_response, '{0}tags/(healthcheck|hostedzone)/*': responses.list_or_change_tags_for_resource_request,
'{0}trafficpolicyinstances/*': responses.not_implemented_response
} }

View File

@ -7,6 +7,8 @@ from boto.route53.record import ResourceRecordSets
import sure # noqa import sure # noqa
import uuid
from moto import mock_route53 from moto import mock_route53
@ -328,3 +330,66 @@ def test_hosted_zone_private_zone_preserved_boto3():
# zone = conn.list_hosted_zones_by_name(DNSName="testdns.aws.com.") # zone = conn.list_hosted_zones_by_name(DNSName="testdns.aws.com.")
# zone.config["PrivateZone"].should.equal(True) # zone.config["PrivateZone"].should.equal(True)
@mock_route53
def test_list_or_change_tags_for_resource_request():
conn = boto3.client('route53')
healthcheck_id = str(uuid.uuid4())
tag1 = {"Key": "Deploy", "Value": "True"}
tag2 = {"Key": "Name", "Value": "UnitTest"}
# Test adding a tag for a resource id
conn.change_tags_for_resource(
ResourceType='healthcheck',
ResourceId=healthcheck_id,
AddTags=[tag1, tag2]
)
# Check to make sure that the response has the 'ResourceTagSet' key
response = conn.list_tags_for_resource(ResourceType='healthcheck', ResourceId=healthcheck_id)
response.should.contain('ResourceTagSet')
# Validate that each key was added
response['ResourceTagSet']['Tags'].should.contain(tag1)
response['ResourceTagSet']['Tags'].should.contain(tag2)
# Try to remove the tags
conn.change_tags_for_resource(
ResourceType='healthcheck',
ResourceId=healthcheck_id,
RemoveTagKeys=[tag1['Key']]
)
# Check to make sure that the response has the 'ResourceTagSet' key
response = conn.list_tags_for_resource(ResourceType='healthcheck', ResourceId=healthcheck_id)
response.should.contain('ResourceTagSet')
response['ResourceTagSet']['Tags'].should_not.contain(tag1)
response['ResourceTagSet']['Tags'].should.contain(tag2)
# Remove the second tag
conn.change_tags_for_resource(
ResourceType='healthcheck',
ResourceId=healthcheck_id,
RemoveTagKeys=[tag2['Key']]
)
response = conn.list_tags_for_resource(ResourceType='healthcheck', ResourceId=healthcheck_id)
response['ResourceTagSet']['Tags'].should_not.contain(tag2)
# Re-add the tags
conn.change_tags_for_resource(
ResourceType='healthcheck',
ResourceId=healthcheck_id,
AddTags=[tag1, tag2]
)
# Remove both
conn.change_tags_for_resource(
ResourceType='healthcheck',
ResourceId=healthcheck_id,
RemoveTagKeys=[tag1['Key'], tag2['Key']]
)
response = conn.list_tags_for_resource(ResourceType='healthcheck', ResourceId=healthcheck_id)
response['ResourceTagSet']['Tags'].should.be.empty