Merge pull request #4534 from willthames/ec2_mount_volumes
Added the ability to add EBS volumes to EC2 instances at creation time
This commit is contained in:
commit
8ff1b06879
1 changed files with 79 additions and 0 deletions
|
@ -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…
Reference in a new issue