Fix SQS tag list from CloudFormation resource creation (#3197)

* fix sqs tag list from cloudformation resource creation

the method `create_from_cloudformation_json` of the Sqs resource
does not handle the difference of format of the Tags field in the
resource template and the format expected in Sqs resource class.

In cfn resource template Tags is specified as a list of dicts. But
the Sqs resource expects that the tags field be a single dict.
This behaviour causes a crash when a queue is created with tags
from `create_from_cloudformation_json` and later the list_queue_tags
is called because it tries to call `items` from `queue.tags` but
tags is actually a list of dicts.

* fix comment

* fix linter

* minor

Co-authored-by: Hudo Assenco <hudo.assenco@gmail.com>
This commit is contained in:
Waldemar Hummer 2020-07-29 12:44:02 +02:00 committed by GitHub
parent 736c8b77ce
commit 08a08b6af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 3 deletions

View File

@ -356,3 +356,14 @@ def tags_from_query_string(
else:
response_values[tag_key] = None
return response_values
def tags_from_cloudformation_tags_list(tags_list):
"""Return tags in dict form from cloudformation resource tags form (list of dicts)"""
tags = {}
for entry in tags_list:
key = entry["Key"]
value = entry["Value"]
tags[key] = value
return tags

View File

@ -18,6 +18,7 @@ from moto.core.utils import (
get_random_message_id,
unix_time,
unix_time_millis,
tags_from_cloudformation_tags_list,
)
from .utils import generate_receipt_handle
from .exceptions import (
@ -357,11 +358,17 @@ class Queue(BaseModel):
def create_from_cloudformation_json(
cls, resource_name, cloudformation_json, region_name
):
properties = cloudformation_json["Properties"]
properties = deepcopy(cloudformation_json["Properties"])
# remove Tags from properties and convert tags list to dict
tags = properties.pop("Tags", [])
tags_dict = tags_from_cloudformation_tags_list(tags)
sqs_backend = sqs_backends[region_name]
return sqs_backend.create_queue(
name=properties["QueueName"], region=region_name, **properties
name=properties["QueueName"],
tags=tags_dict,
region=region_name,
**properties
)
@classmethod

View File

@ -17,12 +17,34 @@ from boto.exception import SQSError
from boto.sqs.message import Message, RawMessage
from botocore.exceptions import ClientError
from freezegun import freeze_time
from moto import mock_sqs, mock_sqs_deprecated, settings
from moto import mock_sqs, mock_sqs_deprecated, mock_cloudformation, settings
from nose import SkipTest
from nose.tools import assert_raises
from tests.helpers import requires_boto_gte
from moto.core import ACCOUNT_ID
sqs_template_with_tags = """
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SQSQueue": {
"Type": "AWS::SQS::Queue",
"Properties": {
"Tags" : [
{
"Key" : "keyname1",
"Value" : "value1"
},
{
"Key" : "keyname2",
"Value" : "value2"
}
]
}
}
}
}"""
@mock_sqs
def test_create_fifo_queue_fail():
@ -1933,3 +1955,17 @@ def test_send_messages_to_fifo_without_message_group_id():
ex.response["Error"]["Message"].should.equal(
"The request must contain the parameter MessageGroupId."
)
@mock_sqs
@mock_cloudformation
def test_create_from_cloudformation_json_with_tags():
cf = boto3.client("cloudformation", region_name="us-east-1")
client = boto3.client("sqs", region_name="us-east-1")
cf.create_stack(StackName="test-sqs", TemplateBody=sqs_template_with_tags)
queue_url = client.list_queues()["QueueUrls"][0]
queue_tags = client.list_queue_tags(QueueUrl=queue_url)["Tags"]
queue_tags.should.equal({"keyname1": "value1", "keyname2": "value2"})