We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Refresh EC2 AMIs for 0.1.1 release
There are a few package updates, esp. Docker 0.6.4. Having the AMIs up-to-date speeds node scaling time somewhat, and it's a slow but mostly-automated process so let's get in the habit of doing this each release.

(Ditto for Rackspace, Vagrant .box images on S3, and DigitalOcean when we get there for each of them...)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `provider/ec2.py`
Content:
```
1 """
2 Deis cloud provider implementation for Amazon EC2.
3 """
4 
5 from __future__ import unicode_literals
6 
7 import json
8 import time
9 
10 from boto import ec2
11 from boto.exception import EC2ResponseError
12 
13 # from api.ssh import connect_ssh, exec_ssh
14 from deis import settings
15 
16 
17 # Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,
18 # and large docker images (e.g. buildstep) pre-installed
19 IMAGE_MAP = {
20     'ap-northeast-1': 'ami-d95ac4d8',
21     'ap-southeast-1': 'ami-1823694a',
22     'ap-southeast-2': 'ami-e56af7df',
23     'eu-west-1': 'ami-7447a003',
24     'sa-east-1': 'ami-334bec2e',
25     'us-east-1': 'ami-493d6a20',
26     'us-west-1': 'ami-0e2b1f4b',
27     'us-west-2': 'ami-72e27c42',
28 }
29 
30 
31 def seed_flavors():
32     """Seed the database with default flavors for each EC2 region.
33 
34     :rtype: list of dicts containing flavor data
35     """
36     flavors = []
37     for r in ('us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1',
38               'ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2',
39               'sa-east-1'):
40         flavors.append({'id': 'ec2-{}'.format(r),
41                         'provider': 'ec2',
42                         'params': json.dumps({
43                             'region': r,
44                             'image': IMAGE_MAP[r],
45                             'zone': 'any',
46                             'size': 'm1.medium'})})
47     return flavors
48 
49 
50 def build_layer(layer):
51     """
52     Build a layer.
53 
54     :param layer: a dict containing formation, id, params, and creds info
55     """
56     region = layer['params'].get('region', 'us-east-1')
57     conn = _create_ec2_connection(layer['creds'], region)
58     # create a new sg and authorize all ports
59     # use iptables on the host to firewall ports
60     name = "{formation}-{id}".format(**layer)
61     sg = conn.create_security_group(name, 'Created by Deis')
62     # import a new keypair using the layer key material
63     conn.import_key_pair(name, layer['ssh_public_key'])
64     # loop until the sg is *actually* there
65     for i in xrange(10):
66         try:
67             sg.authorize(ip_protocol='tcp', from_port=1, to_port=65535,
68                          cidr_ip='0.0.0.0/0')
69             break
70         except EC2ResponseError:
71             if i < 10:
72                 time.sleep(1.5)
73                 continue
74             else:
75                 raise RuntimeError('Failed to authorize security group')
76 
77 
78 def destroy_layer(layer):
79     """
80     Destroy a layer.
81 
82     :param layer: a dict containing formation, id, params, and creds info
83     """
84     region = layer['params'].get('region', 'us-east-1')
85     name = "{formation}-{id}".format(**layer)
86     conn = _create_ec2_connection(layer['creds'], region)
87     conn.delete_key_pair(name)
88     # there's an ec2 race condition on instances terminating
89     # successfully but still holding a lock on the security group
90     # let's take a nap
91     time.sleep(5)
92     try:
93         conn.delete_security_group(name)
94     except EC2ResponseError as e:
95         if e.code != 'InvalidGroup.NotFound':
96             raise e
97 
98 
99 def build_node(node):
100     """
101     Build a node.
102 
103     :param node: a dict containing formation, layer, params, and creds info.
104     :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)
105     """
106     params, creds = node['params'], node['creds']
107     region = params.setdefault('region', 'us-east-1')
108     conn = _create_ec2_connection(creds, region)
109     name = "{formation}-{layer}".format(**node)
110     params['key_name'] = name
111     sg = conn.get_all_security_groups(name)[0]
112     params.setdefault('security_groups', []).append(sg.name)
113     image_id = params.get(
114         'image', getattr(settings, 'IMAGE_MAP', IMAGE_MAP)[region])
115     images = conn.get_all_images([image_id])
116     if len(images) != 1:
117         raise LookupError('Could not find AMI: %s' % image_id)
118     image = images[0]
119     kwargs = _prepare_run_kwargs(params)
120     reservation = image.run(**kwargs)
121     instances = reservation.instances
122     boto = instances[0]
123     # sleep before tagging
124     time.sleep(10)
125     boto.update()
126     boto.add_tag('Name', node['id'])
127     # loop until running
128     while(True):
129         time.sleep(2)
130         boto.update()
131         if boto.state == 'running':
132             break
133     # prepare return values
134     provider_id = boto.id
135     fqdn = boto.public_dns_name
136     metadata = _format_metadata(boto)
137     return provider_id, fqdn, metadata
138 
139 
140 def destroy_node(node):
141     """
142     Destroy a node.
143 
144     :param node: a dict containing a node's provider_id, params, and creds
145     """
146     provider_id = node['provider_id']
147     region = node['params'].get('region', 'us-east-1')
148     conn = _create_ec2_connection(node['creds'], region)
149     if provider_id:
150         conn.terminate_instances([provider_id])
151         i = conn.get_all_instances([provider_id])[0].instances[0]
152         while(True):
153             time.sleep(2)
154             i.update()
155             if i.state == "terminated":
156                 break
157 
158 
159 def _create_ec2_connection(creds, region):
160     """
161     Connect to an EC2 region with the given credentials.
162 
163     :param creds: a dict containing an EC2 access_key and secret_key
164     :region: the name of an EC2 region, such as "us-west-2"
165     :rtype: a connected :class:`~boto.ec2.connection.EC2Connection`
166     :raises EnvironmentError: if no credentials are provided
167     """
168     if not creds:
169         raise EnvironmentError('No credentials provided')
170     return ec2.connect_to_region(region,
171                                  aws_access_key_id=creds['access_key'],
172                                  aws_secret_access_key=creds['secret_key'])
173 
174 
175 def _prepare_run_kwargs(params):
176     # start with sane defaults
177     kwargs = {
178         'min_count': 1, 'max_count': 1,
179         'user_data': None, 'addressing_type': None,
180         'instance_type': None, 'placement': None,
181         'kernel_id': None, 'ramdisk_id': None,
182         'monitoring_enabled': False, 'subnet_id': None,
183         'block_device_map': None,
184     }
185     # convert zone "any" to NoneType
186     requested_zone = params.get('zone')
187     if requested_zone and requested_zone.lower() == 'any':
188         requested_zone = None
189     # lookup kwargs from params
190     param_kwargs = {
191         'instance_type': params.get('size', 'm1.medium'),
192         'security_groups': params['security_groups'],
193         'placement': requested_zone,
194         'key_name': params['key_name'],
195         'kernel_id': params.get('kernel', None),
196     }
197     # add user_data if provided in params
198     user_data = params.get('user_data')
199     if user_data:
200         kwargs.update({'user_data': user_data})
201     # params override defaults
202     kwargs.update(param_kwargs)
203     return kwargs
204 
205 
206 def _format_metadata(boto):
207     return {
208         'architecture': boto.architecture,
209         'block_device_mapping': {
210             k: v.volume_id for k, v in boto.block_device_mapping.items()
211         },
212         'client_token': boto.client_token,
213         'dns_name': boto.dns_name,
214         'ebs_optimized': boto.ebs_optimized,
215         'eventsSet': boto.eventsSet,
216         'group_name': boto.group_name,
217         'groups': [g.id for g in boto.groups],
218         'hypervisor': boto.hypervisor,
219         'id': boto.id,
220         'image_id': boto.image_id,
221         'instance_profile': boto.instance_profile,
222         'instance_type': boto.instance_type,
223         'interfaces': list(boto.interfaces),
224         'ip_address': boto.ip_address,
225         'kernel': boto.kernel,
226         'key_name': boto.key_name,
227         'launch_time': boto.launch_time,
228         'monitored': boto.monitored,
229         'monitoring_state': boto.monitoring_state,
230         'persistent': boto.persistent,
231         'placement': boto.placement,
232         'placement_group': boto.placement_group,
233         'placement_tenancy': boto.placement_tenancy,
234         'previous_state': boto.previous_state,
235         'private_dns_name': boto.private_dns_name,
236         'private_ip_address': boto.private_ip_address,
237         'public_dns_name': boto.public_dns_name,
238         'ramdisk': boto.ramdisk,
239         'region': boto.region.name,
240         'root_device_name': boto.root_device_name,
241         'root_device_type': boto.root_device_type,
242         'spot_instance_request_id': boto.spot_instance_request_id,
243         'state': boto.state,
244         'state_code': boto.state_code,
245         'state_reason': boto.state_reason,
246         'subnet_id': boto.subnet_id,
247         'tags': dict(boto.tags),
248         'virtualization_type': boto.virtualization_type,
249         'vpc_id': boto.vpc_id,
250     }
251
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/provider/ec2.py b/provider/ec2.py
--- a/provider/ec2.py
+++ b/provider/ec2.py
@@ -17,14 +17,14 @@
 # Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,
 # and large docker images (e.g. buildstep) pre-installed
 IMAGE_MAP = {
-    'ap-northeast-1': 'ami-d95ac4d8',
-    'ap-southeast-1': 'ami-1823694a',
-    'ap-southeast-2': 'ami-e56af7df',
-    'eu-west-1': 'ami-7447a003',
-    'sa-east-1': 'ami-334bec2e',
-    'us-east-1': 'ami-493d6a20',
-    'us-west-1': 'ami-0e2b1f4b',
-    'us-west-2': 'ami-72e27c42',
+    'ap-northeast-1': 'ami-0b45de0a',
+    'ap-southeast-1': 'ami-eaf9b3b8',
+    'ap-southeast-2': 'ami-e9970bd3',
+    'eu-west-1': 'ami-c021c1b7',
+    'sa-east-1': 'ami-b5da7ca8',
+    'us-east-1': 'ami-a30b57ca',
+    'us-west-1': 'ami-30e3d475',
+    'us-west-2': 'ami-ca63fafa',
 }

{"golden_diff": "diff --git a/provider/ec2.py b/provider/ec2.py\n--- a/provider/ec2.py\n+++ b/provider/ec2.py\n@@ -17,14 +17,14 @@\n # Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,\n # and large docker images (e.g. buildstep) pre-installed\n IMAGE_MAP = {\n-    'ap-northeast-1': 'ami-d95ac4d8',\n-    'ap-southeast-1': 'ami-1823694a',\n-    'ap-southeast-2': 'ami-e56af7df',\n-    'eu-west-1': 'ami-7447a003',\n-    'sa-east-1': 'ami-334bec2e',\n-    'us-east-1': 'ami-493d6a20',\n-    'us-west-1': 'ami-0e2b1f4b',\n-    'us-west-2': 'ami-72e27c42',\n+    'ap-northeast-1': 'ami-0b45de0a',\n+    'ap-southeast-1': 'ami-eaf9b3b8',\n+    'ap-southeast-2': 'ami-e9970bd3',\n+    'eu-west-1': 'ami-c021c1b7',\n+    'sa-east-1': 'ami-b5da7ca8',\n+    'us-east-1': 'ami-a30b57ca',\n+    'us-west-1': 'ami-30e3d475',\n+    'us-west-2': 'ami-ca63fafa',\n }\n", "issue": "Refresh EC2 AMIs for 0.1.1 release\nThere are a few package updates, esp. Docker 0.6.4. Having the AMIs up-to-date speeds node scaling time somewhat, and it's a slow but mostly-automated process so let's get in the habit of doing this each release.\n\n(Ditto for Rackspace, Vagrant .box images on S3, and DigitalOcean when we get there for each of them...)\n\n", "before_files": [{"content": "\"\"\"\nDeis cloud provider implementation for Amazon EC2.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport json\nimport time\n\nfrom boto import ec2\nfrom boto.exception import EC2ResponseError\n\n# from api.ssh import connect_ssh, exec_ssh\nfrom deis import settings\n\n\n# Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,\n# and large docker images (e.g. buildstep) pre-installed\nIMAGE_MAP = {\n    'ap-northeast-1': 'ami-d95ac4d8',\n    'ap-southeast-1': 'ami-1823694a',\n    'ap-southeast-2': 'ami-e56af7df',\n    'eu-west-1': 'ami-7447a003',\n    'sa-east-1': 'ami-334bec2e',\n    'us-east-1': 'ami-493d6a20',\n    'us-west-1': 'ami-0e2b1f4b',\n    'us-west-2': 'ami-72e27c42',\n}\n\n\ndef seed_flavors():\n    \"\"\"Seed the database with default flavors for each EC2 region.\n\n    :rtype: list of dicts containing flavor data\n    \"\"\"\n    flavors = []\n    for r in ('us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1',\n              'ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2',\n              'sa-east-1'):\n        flavors.append({'id': 'ec2-{}'.format(r),\n                        'provider': 'ec2',\n                        'params': json.dumps({\n                            'region': r,\n                            'image': IMAGE_MAP[r],\n                            'zone': 'any',\n                            'size': 'm1.medium'})})\n    return flavors\n\n\ndef build_layer(layer):\n    \"\"\"\n    Build a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    region = layer['params'].get('region', 'us-east-1')\n    conn = _create_ec2_connection(layer['creds'], region)\n    # create a new sg and authorize all ports\n    # use iptables on the host to firewall ports\n    name = \"{formation}-{id}\".format(**layer)\n    sg = conn.create_security_group(name, 'Created by Deis')\n    # import a new keypair using the layer key material\n    conn.import_key_pair(name, layer['ssh_public_key'])\n    # loop until the sg is *actually* there\n    for i in xrange(10):\n        try:\n            sg.authorize(ip_protocol='tcp', from_port=1, to_port=65535,\n                         cidr_ip='0.0.0.0/0')\n            break\n        except EC2ResponseError:\n            if i < 10:\n                time.sleep(1.5)\n                continue\n            else:\n                raise RuntimeError('Failed to authorize security group')\n\n\ndef destroy_layer(layer):\n    \"\"\"\n    Destroy a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    region = layer['params'].get('region', 'us-east-1')\n    name = \"{formation}-{id}\".format(**layer)\n    conn = _create_ec2_connection(layer['creds'], region)\n    conn.delete_key_pair(name)\n    # there's an ec2 race condition on instances terminating\n    # successfully but still holding a lock on the security group\n    # let's take a nap\n    time.sleep(5)\n    try:\n        conn.delete_security_group(name)\n    except EC2ResponseError as e:\n        if e.code != 'InvalidGroup.NotFound':\n            raise e\n\n\ndef build_node(node):\n    \"\"\"\n    Build a node.\n\n    :param node: a dict containing formation, layer, params, and creds info.\n    :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)\n    \"\"\"\n    params, creds = node['params'], node['creds']\n    region = params.setdefault('region', 'us-east-1')\n    conn = _create_ec2_connection(creds, region)\n    name = \"{formation}-{layer}\".format(**node)\n    params['key_name'] = name\n    sg = conn.get_all_security_groups(name)[0]\n    params.setdefault('security_groups', []).append(sg.name)\n    image_id = params.get(\n        'image', getattr(settings, 'IMAGE_MAP', IMAGE_MAP)[region])\n    images = conn.get_all_images([image_id])\n    if len(images) != 1:\n        raise LookupError('Could not find AMI: %s' % image_id)\n    image = images[0]\n    kwargs = _prepare_run_kwargs(params)\n    reservation = image.run(**kwargs)\n    instances = reservation.instances\n    boto = instances[0]\n    # sleep before tagging\n    time.sleep(10)\n    boto.update()\n    boto.add_tag('Name', node['id'])\n    # loop until running\n    while(True):\n        time.sleep(2)\n        boto.update()\n        if boto.state == 'running':\n            break\n    # prepare return values\n    provider_id = boto.id\n    fqdn = boto.public_dns_name\n    metadata = _format_metadata(boto)\n    return provider_id, fqdn, metadata\n\n\ndef destroy_node(node):\n    \"\"\"\n    Destroy a node.\n\n    :param node: a dict containing a node's provider_id, params, and creds\n    \"\"\"\n    provider_id = node['provider_id']\n    region = node['params'].get('region', 'us-east-1')\n    conn = _create_ec2_connection(node['creds'], region)\n    if provider_id:\n        conn.terminate_instances([provider_id])\n        i = conn.get_all_instances([provider_id])[0].instances[0]\n        while(True):\n            time.sleep(2)\n            i.update()\n            if i.state == \"terminated\":\n                break\n\n\ndef _create_ec2_connection(creds, region):\n    \"\"\"\n    Connect to an EC2 region with the given credentials.\n\n    :param creds: a dict containing an EC2 access_key and secret_key\n    :region: the name of an EC2 region, such as \"us-west-2\"\n    :rtype: a connected :class:`~boto.ec2.connection.EC2Connection`\n    :raises EnvironmentError: if no credentials are provided\n    \"\"\"\n    if not creds:\n        raise EnvironmentError('No credentials provided')\n    return ec2.connect_to_region(region,\n                                 aws_access_key_id=creds['access_key'],\n                                 aws_secret_access_key=creds['secret_key'])\n\n\ndef _prepare_run_kwargs(params):\n    # start with sane defaults\n    kwargs = {\n        'min_count': 1, 'max_count': 1,\n        'user_data': None, 'addressing_type': None,\n        'instance_type': None, 'placement': None,\n        'kernel_id': None, 'ramdisk_id': None,\n        'monitoring_enabled': False, 'subnet_id': None,\n        'block_device_map': None,\n    }\n    # convert zone \"any\" to NoneType\n    requested_zone = params.get('zone')\n    if requested_zone and requested_zone.lower() == 'any':\n        requested_zone = None\n    # lookup kwargs from params\n    param_kwargs = {\n        'instance_type': params.get('size', 'm1.medium'),\n        'security_groups': params['security_groups'],\n        'placement': requested_zone,\n        'key_name': params['key_name'],\n        'kernel_id': params.get('kernel', None),\n    }\n    # add user_data if provided in params\n    user_data = params.get('user_data')\n    if user_data:\n        kwargs.update({'user_data': user_data})\n    # params override defaults\n    kwargs.update(param_kwargs)\n    return kwargs\n\n\ndef _format_metadata(boto):\n    return {\n        'architecture': boto.architecture,\n        'block_device_mapping': {\n            k: v.volume_id for k, v in boto.block_device_mapping.items()\n        },\n        'client_token': boto.client_token,\n        'dns_name': boto.dns_name,\n        'ebs_optimized': boto.ebs_optimized,\n        'eventsSet': boto.eventsSet,\n        'group_name': boto.group_name,\n        'groups': [g.id for g in boto.groups],\n        'hypervisor': boto.hypervisor,\n        'id': boto.id,\n        'image_id': boto.image_id,\n        'instance_profile': boto.instance_profile,\n        'instance_type': boto.instance_type,\n        'interfaces': list(boto.interfaces),\n        'ip_address': boto.ip_address,\n        'kernel': boto.kernel,\n        'key_name': boto.key_name,\n        'launch_time': boto.launch_time,\n        'monitored': boto.monitored,\n        'monitoring_state': boto.monitoring_state,\n        'persistent': boto.persistent,\n        'placement': boto.placement,\n        'placement_group': boto.placement_group,\n        'placement_tenancy': boto.placement_tenancy,\n        'previous_state': boto.previous_state,\n        'private_dns_name': boto.private_dns_name,\n        'private_ip_address': boto.private_ip_address,\n        'public_dns_name': boto.public_dns_name,\n        'ramdisk': boto.ramdisk,\n        'region': boto.region.name,\n        'root_device_name': boto.root_device_name,\n        'root_device_type': boto.root_device_type,\n        'spot_instance_request_id': boto.spot_instance_request_id,\n        'state': boto.state,\n        'state_code': boto.state_code,\n        'state_reason': boto.state_reason,\n        'subnet_id': boto.subnet_id,\n        'tags': dict(boto.tags),\n        'virtualization_type': boto.virtualization_type,\n        'vpc_id': boto.vpc_id,\n    }\n", "path": "provider/ec2.py"}], "after_files": [{"content": "\"\"\"\nDeis cloud provider implementation for Amazon EC2.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport json\nimport time\n\nfrom boto import ec2\nfrom boto.exception import EC2ResponseError\n\n# from api.ssh import connect_ssh, exec_ssh\nfrom deis import settings\n\n\n# Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,\n# and large docker images (e.g. buildstep) pre-installed\nIMAGE_MAP = {\n    'ap-northeast-1': 'ami-0b45de0a',\n    'ap-southeast-1': 'ami-eaf9b3b8',\n    'ap-southeast-2': 'ami-e9970bd3',\n    'eu-west-1': 'ami-c021c1b7',\n    'sa-east-1': 'ami-b5da7ca8',\n    'us-east-1': 'ami-a30b57ca',\n    'us-west-1': 'ami-30e3d475',\n    'us-west-2': 'ami-ca63fafa',\n}\n\n\ndef seed_flavors():\n    \"\"\"Seed the database with default flavors for each EC2 region.\n\n    :rtype: list of dicts containing flavor data\n    \"\"\"\n    flavors = []\n    for r in ('us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1',\n              'ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2',\n              'sa-east-1'):\n        flavors.append({'id': 'ec2-{}'.format(r),\n                        'provider': 'ec2',\n                        'params': json.dumps({\n                            'region': r,\n                            'image': IMAGE_MAP[r],\n                            'zone': 'any',\n                            'size': 'm1.medium'})})\n    return flavors\n\n\ndef build_layer(layer):\n    \"\"\"\n    Build a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    region = layer['params'].get('region', 'us-east-1')\n    conn = _create_ec2_connection(layer['creds'], region)\n    # create a new sg and authorize all ports\n    # use iptables on the host to firewall ports\n    name = \"{formation}-{id}\".format(**layer)\n    sg = conn.create_security_group(name, 'Created by Deis')\n    # import a new keypair using the layer key material\n    conn.import_key_pair(name, layer['ssh_public_key'])\n    # loop until the sg is *actually* there\n    for i in xrange(10):\n        try:\n            sg.authorize(ip_protocol='tcp', from_port=1, to_port=65535,\n                         cidr_ip='0.0.0.0/0')\n            break\n        except EC2ResponseError:\n            if i < 10:\n                time.sleep(1.5)\n                continue\n            else:\n                raise RuntimeError('Failed to authorize security group')\n\n\ndef destroy_layer(layer):\n    \"\"\"\n    Destroy a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    region = layer['params'].get('region', 'us-east-1')\n    name = \"{formation}-{id}\".format(**layer)\n    conn = _create_ec2_connection(layer['creds'], region)\n    conn.delete_key_pair(name)\n    # there's an ec2 race condition on instances terminating\n    # successfully but still holding a lock on the security group\n    # let's take a nap\n    time.sleep(5)\n    try:\n        conn.delete_security_group(name)\n    except EC2ResponseError as e:\n        if e.code != 'InvalidGroup.NotFound':\n            raise e\n\n\ndef build_node(node):\n    \"\"\"\n    Build a node.\n\n    :param node: a dict containing formation, layer, params, and creds info.\n    :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)\n    \"\"\"\n    params, creds = node['params'], node['creds']\n    region = params.setdefault('region', 'us-east-1')\n    conn = _create_ec2_connection(creds, region)\n    name = \"{formation}-{layer}\".format(**node)\n    params['key_name'] = name\n    sg = conn.get_all_security_groups(name)[0]\n    params.setdefault('security_groups', []).append(sg.name)\n    image_id = params.get(\n        'image', getattr(settings, 'IMAGE_MAP', IMAGE_MAP)[region])\n    images = conn.get_all_images([image_id])\n    if len(images) != 1:\n        raise LookupError('Could not find AMI: %s' % image_id)\n    image = images[0]\n    kwargs = _prepare_run_kwargs(params)\n    reservation = image.run(**kwargs)\n    instances = reservation.instances\n    boto = instances[0]\n    # sleep before tagging\n    time.sleep(10)\n    boto.update()\n    boto.add_tag('Name', node['id'])\n    # loop until running\n    while(True):\n        time.sleep(2)\n        boto.update()\n        if boto.state == 'running':\n            break\n    # prepare return values\n    provider_id = boto.id\n    fqdn = boto.public_dns_name\n    metadata = _format_metadata(boto)\n    return provider_id, fqdn, metadata\n\n\ndef destroy_node(node):\n    \"\"\"\n    Destroy a node.\n\n    :param node: a dict containing a node's provider_id, params, and creds\n    \"\"\"\n    provider_id = node['provider_id']\n    region = node['params'].get('region', 'us-east-1')\n    conn = _create_ec2_connection(node['creds'], region)\n    if provider_id:\n        conn.terminate_instances([provider_id])\n        i = conn.get_all_instances([provider_id])[0].instances[0]\n        while(True):\n            time.sleep(2)\n            i.update()\n            if i.state == \"terminated\":\n                break\n\n\ndef _create_ec2_connection(creds, region):\n    \"\"\"\n    Connect to an EC2 region with the given credentials.\n\n    :param creds: a dict containing an EC2 access_key and secret_key\n    :region: the name of an EC2 region, such as \"us-west-2\"\n    :rtype: a connected :class:`~boto.ec2.connection.EC2Connection`\n    :raises EnvironmentError: if no credentials are provided\n    \"\"\"\n    if not creds:\n        raise EnvironmentError('No credentials provided')\n    return ec2.connect_to_region(region,\n                                 aws_access_key_id=creds['access_key'],\n                                 aws_secret_access_key=creds['secret_key'])\n\n\ndef _prepare_run_kwargs(params):\n    # start with sane defaults\n    kwargs = {\n        'min_count': 1, 'max_count': 1,\n        'user_data': None, 'addressing_type': None,\n        'instance_type': None, 'placement': None,\n        'kernel_id': None, 'ramdisk_id': None,\n        'monitoring_enabled': False, 'subnet_id': None,\n        'block_device_map': None,\n    }\n    # convert zone \"any\" to NoneType\n    requested_zone = params.get('zone')\n    if requested_zone and requested_zone.lower() == 'any':\n        requested_zone = None\n    # lookup kwargs from params\n    param_kwargs = {\n        'instance_type': params.get('size', 'm1.medium'),\n        'security_groups': params['security_groups'],\n        'placement': requested_zone,\n        'key_name': params['key_name'],\n        'kernel_id': params.get('kernel', None),\n    }\n    # add user_data if provided in params\n    user_data = params.get('user_data')\n    if user_data:\n        kwargs.update({'user_data': user_data})\n    # params override defaults\n    kwargs.update(param_kwargs)\n    return kwargs\n\n\ndef _format_metadata(boto):\n    return {\n        'architecture': boto.architecture,\n        'block_device_mapping': {\n            k: v.volume_id for k, v in boto.block_device_mapping.items()\n        },\n        'client_token': boto.client_token,\n        'dns_name': boto.dns_name,\n        'ebs_optimized': boto.ebs_optimized,\n        'eventsSet': boto.eventsSet,\n        'group_name': boto.group_name,\n        'groups': [g.id for g in boto.groups],\n        'hypervisor': boto.hypervisor,\n        'id': boto.id,\n        'image_id': boto.image_id,\n        'instance_profile': boto.instance_profile,\n        'instance_type': boto.instance_type,\n        'interfaces': list(boto.interfaces),\n        'ip_address': boto.ip_address,\n        'kernel': boto.kernel,\n        'key_name': boto.key_name,\n        'launch_time': boto.launch_time,\n        'monitored': boto.monitored,\n        'monitoring_state': boto.monitoring_state,\n        'persistent': boto.persistent,\n        'placement': boto.placement,\n        'placement_group': boto.placement_group,\n        'placement_tenancy': boto.placement_tenancy,\n        'previous_state': boto.previous_state,\n        'private_dns_name': boto.private_dns_name,\n        'private_ip_address': boto.private_ip_address,\n        'public_dns_name': boto.public_dns_name,\n        'ramdisk': boto.ramdisk,\n        'region': boto.region.name,\n        'root_device_name': boto.root_device_name,\n        'root_device_type': boto.root_device_type,\n        'spot_instance_request_id': boto.spot_instance_request_id,\n        'state': boto.state,\n        'state_code': boto.state_code,\n        'state_reason': boto.state_reason,\n        'subnet_id': boto.subnet_id,\n        'tags': dict(boto.tags),\n        'virtualization_type': boto.virtualization_type,\n        'vpc_id': boto.vpc_id,\n    }\n", "path": "provider/ec2.py"}]}