Merge pull request #4534 from willthames/ec2_mount_volumes

Added the ability to add EBS volumes to EC2 instances at creation time
pull/5784/head
jctanner 11 years ago
commit 8ff1b06879

@ -191,6 +191,13 @@ options:
required: false required: false
default: 'present' default: 'present'
aliases: [] aliases: []
volumes:
version_added: "1.5"
description:
- a list of volume dicts, each containing device name and optionally ephemeral id or snapshot id. Size and type (and number of iops for io device type) must be specified for a new volume or a root volume, and may be passed for a snapshot volume. For any volume, a volume size less than 1 will be interpreted as a request not to create the volume.
required: false
default: null
aliases: []
requirements: [ "boto" ] requirements: [ "boto" ]
author: Seth Vidal, Tim Gerla, Lester Wade author: Seth Vidal, Tim Gerla, Lester Wade
@ -223,6 +230,23 @@ EXAMPLES = '''
instance_tags: '{"db":"postgres"}' instance_tags: '{"db":"postgres"}'
monitoring=yes monitoring=yes
# Single instance with additional IOPS volume from snapshot
local_action:
module: ec2
keypair: mykey
group: webserver
instance_type: m1.large
image: ami-6e649707
wait: yes
wait_timeout: 500
volumes:
- device_name: /dev/sdb
snapshot: snap-abcdef12
device_type: io1
iops: 1000
volume_size: 100
monitoring=yes
# Multiple groups example # Multiple groups example
local_action: local_action:
module: ec2 module: ec2
@ -236,6 +260,22 @@ local_action:
instance_tags: '{"db":"postgres"}' instance_tags: '{"db":"postgres"}'
monitoring=yes monitoring=yes
# Multiple instances with additional volume from snapshot
local_action:
module: ec2
keypair: mykey
group: webserver
instance_type: m1.large
image: ami-6e649707
wait: yes
wait_timeout: 500
count: 5
volumes:
- device_name: /dev/sdb
snapshot: snap-abcdef12
volume_size: 10
monitoring=yes
# VPC example # VPC example
- local_action: - local_action:
module: ec2 module: ec2
@ -296,6 +336,7 @@ import time
try: try:
import boto.ec2 import boto.ec2
from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
from boto.exception import EC2ResponseError from boto.exception import EC2ResponseError
except ImportError: except ImportError:
print "failed=True msg='boto required for this module'" print "failed=True msg='boto required for this module'"
@ -364,6 +405,30 @@ def boto_supports_profile_name_arg(ec2):
run_instances_method = getattr(ec2, 'run_instances') run_instances_method = getattr(ec2, 'run_instances')
return 'instance_profile_name' in run_instances_method.func_code.co_varnames return 'instance_profile_name' in run_instances_method.func_code.co_varnames
def create_block_device(module, ec2, volume):
# Not aware of a way to determine this programatically
# http://aws.amazon.com/about-aws/whats-new/2013/10/09/ebs-provisioned-iops-maximum-iops-gb-ratio-increased-to-30-1/
MAX_IOPS_TO_SIZE_RATIO = 30
if 'snapshot' not in volume and 'ephemeral' not in volume:
if 'volume_size' not in volume:
module.fail_json(msg = 'Size must be specified when creating a new volume or modifying the root volume')
if 'snapshot' in volume:
if 'device_type' in volume and volume.get('device_type') == 'io1' and 'iops' not in volume:
module.fail_json(msg = 'io1 volumes must have an iops value set')
if 'iops' in volume:
snapshot = ec2.get_all_snapshots(snapshot_ids=[volume['snapshot']])[0]
size = volume.get('volume_size', snapshot.volume_size)
if int(volume['iops']) > MAX_IOPS_TO_SIZE_RATIO * size:
module.fail_json(msg = 'IOPS must be at most %d times greater than size' % MAX_IOPS_TO_SIZE_RATIO)
if 'ephemeral' in volume:
if 'snapshot' in volume:
module.fail_json(msg = 'Cannot set both ephemeral and snapshot')
return BlockDeviceType(snapshot_id=volume.get('snapshot'),
ephemeral_name=volume.get('ephemeral'),
size=volume.get('volume_size'),
volume_type=volume.get('device_type'),
delete_on_termination=volume.get('delete_on_termination', False),
iops=volume.get('iops'))
def create_instances(module, ec2): def create_instances(module, ec2):
""" """
@ -397,6 +462,7 @@ def create_instances(module, ec2):
assign_public_ip = module.boolean(module.params.get('assign_public_ip')) assign_public_ip = module.boolean(module.params.get('assign_public_ip'))
private_ip = module.params.get('private_ip') private_ip = module.params.get('private_ip')
instance_profile_name = module.params.get('instance_profile_name') instance_profile_name = module.params.get('instance_profile_name')
volumes = module.params.get('volumes')
# group_id and group_name are exclusive of each other # group_id and group_name are exclusive of each other
if group_id and group_name: if group_id and group_name:
@ -489,6 +555,18 @@ def create_instances(module, ec2):
else: else:
params['security_groups'] = group_name params['security_groups'] = group_name
if volumes:
bdm = BlockDeviceMapping()
for volume in volumes:
if 'device_name' not in volume:
module.fail_json(msg = 'Device name must be set for volume')
# Minimum volume size is 1GB. We'll use volume size explicitly set to 0
# to be a signal not to create this volume
if 'volume_size' not in volume or int(volume['volume_size']) > 0:
bdm[volume['device_name']] = create_block_device(module, ec2, volume)
params['block_device_map'] = bdm
res = ec2.run_instances(**params) res = ec2.run_instances(**params)
except boto.exception.BotoServerError, e: except boto.exception.BotoServerError, e:
module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message)) module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message))
@ -641,6 +719,7 @@ def main():
instance_profile_name = dict(), instance_profile_name = dict(),
instance_ids = dict(type='list'), instance_ids = dict(type='list'),
state = dict(default='present'), state = dict(default='present'),
volumes = dict(type='list'),
) )
) )

Loading…
Cancel
Save