Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Refactor get_ec2_userdata to return list
Browse files Browse the repository at this point in the history
This makes it easier to override the userdata in other modules. This
means that bootstrap salt can extend the userdata without having to
decode the mime message and re-mime it afterwards.
  • Loading branch information
mattmb committed Jul 23, 2015
1 parent 2038504 commit 08e434d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 24 deletions.
4 changes: 3 additions & 1 deletion bootstrap_cfn/config.py
Expand Up @@ -551,7 +551,7 @@ def get_ec2_userdata(self):
})

if len(parts):
return mime_packer.pack(parts)
return parts

HOSTNAME_BOOTHOOK_TEMPLATE = textwrap.dedent("""\
#!/bin/sh
Expand Down Expand Up @@ -654,8 +654,10 @@ def ec2(self):
ImageId=FindInMap("AWSRegion2AMI", Ref("AWS::Region"), "AMI"),
BlockDeviceMappings=devices,
)

user_data = self.get_ec2_userdata()
if user_data:
user_data = mime_packer.pack(user_data)
launch_config.UserData = Base64(user_data)

resources.append(launch_config)
Expand Down
36 changes: 36 additions & 0 deletions tests/test_mime_packer.py
@@ -0,0 +1,36 @@
import email

import unittest

from testfixtures import compare

from bootstrap_cfn import mime_packer


class TestMimePacker(unittest.TestCase):

def setUp(self):
self.parts = []
self.parts.append({
'content': 'MORESTRING',
'mime_type': 'text/cloud-boothook'
})
self.parts.append({
'content': 'SOMESTRING',
'mime_type': 'text/cloud-config'
})

def test_encode(self):
ret = mime_packer.pack(self.parts)
self.assertTrue('SOMESTRING' in ret)
self.assertTrue('MORESTRING' in ret)

def test_decode(self):
ret = mime_packer.pack(self.parts)
parts = [part for part in email.message_from_string(ret).walk()]
compare(
[part.get_content_type() for part in parts],
["multipart/mixed", "text/cloud-boothook", "text/cloud-config"],
prefix="mimeparts are in expected order")
compare(parts[1].get_payload(), "MORESTRING")
compare(parts[2].get_payload(), "SOMESTRING")
32 changes: 9 additions & 23 deletions tests/tests.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
import email
import json
import unittest
from StringIO import StringIO
Expand All @@ -18,6 +17,7 @@
import yaml

from bootstrap_cfn import errors
from bootstrap_cfn import mime_packer
from bootstrap_cfn.config import ConfigParser, ProjectConfig


Expand Down Expand Up @@ -1047,14 +1047,14 @@ def test_launchconfig_userdata(self):
IamInstanceProfile=Ref("InstanceProfile"),
InstanceType="t2.micro",
AssociatePublicIpAddress="true",
UserData=Base64("Mock Userdata String"),
UserData=Base64("Mock String"),
)

with patch.object(config, "get_ec2_userdata", return_value="Mock Userdata String"):
ec2_json = self._resources_to_dict(config.ec2())
expected = self._resources_to_dict([BaseHostLaunchConfig])
compare(ec2_json['BaseHostLaunchConfig'], expected['BaseHostLaunchConfig'])
pass
with patch.object(config, "get_ec2_userdata", return_value="Mock String"):
with patch.object(mime_packer, "pack", side_effect=lambda x: x):
ec2_json = self._resources_to_dict(config.ec2())
expected = self._resources_to_dict([BaseHostLaunchConfig])
compare(ec2_json['BaseHostLaunchConfig'], expected['BaseHostLaunchConfig'])

def test_get_ec2_userdata(self):
data = {
Expand All @@ -1063,24 +1063,10 @@ def test_get_ec2_userdata(self):
}
}
config = ConfigParser(data, environment="env", application="test", stack_name="my-stack")

with patch.object(config, 'get_hostname_boothook', return_value={"content": "sentinel"}) as mock_boothook:
# This test is slightly silly as we are testing the decoding with
# the same code as the generator... but it's that or we test it
# with regexp.
mime_text = config.get_ec2_userdata()

compare(yaml.load(config.get_ec2_userdata()[1]['content']), data['ec2']['cloud_config'])
mock_boothook.assert_called_once_with(data['ec2'])

parts = [part for part in email.message_from_string(mime_text).walk()]

compare(
[part.get_content_type() for part in parts],
["multipart/mixed", "text/plain", "text/cloud-config"],
prefix="Userdata parts are in expected order")

compare(parts[1].get_payload(), "sentinel")
compare(yaml.load(parts[2].get_payload()), data['ec2']['cloud_config'])
compare(config.get_ec2_userdata()[0]['content'], 'sentinel')

def test_get_hostname_boothook(self):
config = ConfigParser({}, environment="env", application="test", stack_name="my-stack")
Expand Down

0 comments on commit 08e434d

Please sign in to comment.