Repository: getmoto/moto

Issue:
Cloudformation doesn`t work with yaml templates
When i try to use moto to mock a call to `create_stack` the following happens:

Traceback:
```
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/core/responses.py", line 107, in dispatch
    return cls()._dispatch(*args, **kwargs)
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/core/responses.py", line 167, in _dispatch
    return self.call_action()
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/core/responses.py", line 183, in call_action
    response = method()
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/cloudformation/responses.py", line 51, in create_stack
    role_arn=role_arn,
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/cloudformation/models.py", line 126, in create_stack
    role_arn=role_arn,
  File "/Users/iuryalvesdesouza/projects/bastion/venv/lib/python3.6/site-packages/moto/cloudformation/models.py", line 18, in __init__
    self.template_dict = json.loads(self.template)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
```

#### How to reproduce

```python
# coding: utf-8

import unittest
from boto.cloudformation import connect_to_region
from moto import mock_cloudformation


class TestCase(unittest.TestCase):

        @mock_cloudformation
        def test_cloudformation_create_stack(self):
	    connection = connect_to_region('sa-east-1')
	    with open('ec2.yml') as fp:
                template = fp.read()

            connection.create_stack('test-stack', template_body=template)


if __name__ == '__main__':
    unittest.main()
```

Template: ec2.yaml
```yaml
Resources:
  BastionInstance:
    Type: "AWS::EC2::Instance"
    Properties: 
      AvailabilityZone: sa-east-1a
      DisableApiTermination: false
      ImageId: ami-37cfad5b
      InstanceType: t2.micro
```

Moto version: 0.4.31
Boto Version: 2.46.1
Python Version: Python 3.6.0rc1
System: Darwin Iurys-MacBook-Pro.local 15.5.0 Darwin Kernel Version 15.5.0: Tue Apr 19 18:36:36 PDT 2016; root:xnu-3248.50.21~8/RELEASE_X86_64 x86_64



Discussion:

Resolving patch:
diff --git a/moto/cloudformation/models.py b/moto/cloudformation/models.py
--- a/moto/cloudformation/models.py
+++ b/moto/cloudformation/models.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 from datetime import datetime
 import json
+import yaml
 import uuid
 
 import boto.cloudformation
@@ -17,7 +18,7 @@ def __init__(self, stack_id, name, template, parameters, region_name, notificati
         self.stack_id = stack_id
         self.name = name
         self.template = template
-        self.template_dict = json.loads(self.template)
+        self._parse_template()
         self.parameters = parameters
         self.region_name = region_name
         self.notification_arns = notification_arns if notification_arns else []
@@ -70,6 +71,12 @@ def _add_resource_event(self, logical_resource_id, resource_status, resource_sta
             resource_properties=resource_properties,
         ))
 
+    def _parse_template(self):
+        try:
+            self.template_dict = yaml.load(self.template)
+        except yaml.parser.ParserError:
+            self.template_dict = json.loads(self.template)
+
     @property
     def stack_parameters(self):
         return self.resource_map.resolved_parameters
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -11,6 +11,7 @@
     "dicttoxml",
     "six",
     "werkzeug",
+    "pyaml",
     "pytz",
     "python-dateutil",
 ]


Test patch:
diff --git a/tests/test_cloudformation/test_stack_parsing.py b/tests/test_cloudformation/test_stack_parsing.py
--- a/tests/test_cloudformation/test_stack_parsing.py
+++ b/tests/test_cloudformation/test_stack_parsing.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals
 import json
+import yaml
 
 from mock import patch
 import sure  # noqa
@@ -126,6 +127,20 @@ def test_parse_stack_with_name_type_resource():
     queue.should.be.a(Queue)
 
 
+def test_parse_stack_with_yaml_template():
+    stack = FakeStack(
+        stack_id="test_id",
+        name="test_stack",
+        template=yaml.dump(name_type_template),
+        parameters={},
+        region_name='us-west-1')
+
+    stack.resource_map.should.have.length_of(1)
+    list(stack.resource_map.keys())[0].should.equal('Queue')
+    queue = list(stack.resource_map.values())[0]
+    queue.should.be.a(Queue)
+
+
 def test_parse_stack_with_outputs():
     stack = FakeStack(
         stack_id="test_id",