Merge pull request #6976 from clconway/gce-snapshots

Adds support for snapshots and extra persistent disks to the gce modules
This commit is contained in:
Michael DeHaan 2014-07-19 19:07:29 -04:00
commit 16ed24d0c0
2 changed files with 88 additions and 5 deletions

View file

@ -89,6 +89,13 @@ options:
required: false required: false
default: "false" default: "false"
aliases: [] aliases: []
disks:
description:
- a list of persistent disks to attach to the instance; a string value gives the name of the disk; alternatively, a dictionary value can define 'name' and 'mode' ('READ_ONLY' or 'READ_WRITE'). The first entry will be the boot disk (which must be READ_WRITE).
required: false
default: null
aliases: []
version_added: "1.6"
state: state:
description: description:
- desired state of the resource - desired state of the resource
@ -209,8 +216,16 @@ def get_instance_info(inst):
netname = inst.extra['networkInterfaces'][0]['network'].split('/')[-1] netname = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
except: except:
netname = None netname = None
if 'disks' in inst.extra:
disk_names = [disk_info['source'].split('/')[-1]
for disk_info
in sorted(inst.extra['disks'],
key=lambda disk_info: disk_info['index'])]
else:
disk_names = []
return({ return({
'image': not inst.image is None and inst.image.split('/')[-1] or None, 'image': not inst.image is None and inst.image.split('/')[-1] or None,
'disks': disk_names,
'machine_type': inst.size, 'machine_type': inst.size,
'metadata': metadata, 'metadata': metadata,
'name': inst.name, 'name': inst.name,
@ -240,6 +255,7 @@ def create_instances(module, gce, instance_names):
metadata = module.params.get('metadata') metadata = module.params.get('metadata')
network = module.params.get('network') network = module.params.get('network')
persistent_boot_disk = module.params.get('persistent_boot_disk') persistent_boot_disk = module.params.get('persistent_boot_disk')
disks = module.params.get('disks')
state = module.params.get('state') state = module.params.get('state')
tags = module.params.get('tags') tags = module.params.get('tags')
zone = module.params.get('zone') zone = module.params.get('zone')
@ -248,6 +264,16 @@ def create_instances(module, gce, instance_names):
changed = False changed = False
lc_image = gce.ex_get_image(image) lc_image = gce.ex_get_image(image)
lc_disks = []
disk_modes = []
for i, disk in enumerate(disks or []):
if isinstance(disk, dict):
lc_disks.append(gce.ex_get_volume(disk['name']))
disk_modes.append(disk['mode'])
else:
lc_disks.append(gce.ex_get_volume(disk))
# boot disk is implicitly READ_WRITE
disk_modes.append('READ_ONLY' if i > 0 else 'READ_WRITE')
lc_network = gce.ex_get_network(network) lc_network = gce.ex_get_network(network)
lc_machine_type = gce.ex_get_size(machine_type) lc_machine_type = gce.ex_get_size(machine_type)
lc_zone = gce.ex_get_zone(zone) lc_zone = gce.ex_get_zone(zone)
@ -282,7 +308,9 @@ def create_instances(module, gce, instance_names):
for name in instance_names: for name in instance_names:
pd = None pd = None
if persistent_boot_disk: if lc_disks:
pd = lc_disks[0]
elif persistent_boot_disk:
try: try:
pd = gce.create_volume(None, "%s" % name, image=lc_image) pd = gce.create_volume(None, "%s" % name, image=lc_image)
except ResourceExistsError: except ResourceExistsError:
@ -299,6 +327,28 @@ def create_instances(module, gce, instance_names):
module.fail_json(msg='Unexpected error attempting to create ' + \ module.fail_json(msg='Unexpected error attempting to create ' + \
'instance %s, error: %s' % (name, e.value)) 'instance %s, error: %s' % (name, e.value))
for i, lc_disk in enumerate(lc_disks):
# Check whether the disk is already attached
if (len(inst.extra['disks']) > i):
attached_disk = inst.extra['disks'][i]
if attached_disk['source'] != lc_disk.extra['selfLink']:
module.fail_json(
msg=("Disk at index %d does not match: requested=%s found=%s" % (
i, lc_disk.extra['selfLink'], attached_disk['source'])))
elif attached_disk['mode'] != disk_modes[i]:
module.fail_json(
msg=("Disk at index %d is in the wrong mode: requested=%s found=%s" % (
i, disk_modes[i], attached_disk['mode'])))
else:
continue
gce.attach_volume(inst, lc_disk, ex_mode=disk_modes[i])
# Work around libcloud bug: attached volumes don't get added
# to the instance metadata. get_instance_info() only cares about
# source and index.
if len(inst.extra['disks']) != i+1:
inst.extra['disks'].append(
{'source': lc_disk.extra['selfLink'], 'index': i})
if inst: if inst:
new_instances.append(inst) new_instances.append(inst)
@ -351,6 +401,7 @@ def main():
name = dict(), name = dict(),
network = dict(default='default'), network = dict(default='default'),
persistent_boot_disk = dict(type='bool', default=False), persistent_boot_disk = dict(type='bool', default=False),
disks = dict(type='list'),
state = dict(choices=['active', 'present', 'absent', 'deleted'], state = dict(choices=['active', 'present', 'absent', 'deleted'],
default='present'), default='present'),
tags = dict(type='list'), tags = dict(type='list'),

View file

@ -24,9 +24,7 @@ short_description: utilize GCE persistent disk resources
description: description:
- This module can create and destroy unformatted GCE persistent disks - This module can create and destroy unformatted GCE persistent disks
U(https://developers.google.com/compute/docs/disks#persistentdisks). U(https://developers.google.com/compute/docs/disks#persistentdisks).
It also supports attaching and detaching disks from running instances It also supports attaching and detaching disks from running instances.
but does not support creating boot disks from images or snapshots. The
'gce' module supports creating instances with boot disks.
Full install/configuration instructions for the gce* modules can Full install/configuration instructions for the gce* modules can
be found in the comments of ansible/test/gce_tests.py. be found in the comments of ansible/test/gce_tests.py.
options: options:
@ -62,6 +60,20 @@ options:
required: false required: false
default: 10 default: 10
aliases: [] aliases: []
image:
description:
- the source image to use for the disk
required: false
default: null
aliases: []
version_added: "1.6"
snapshot:
description:
- the source snapshot to use for the disk
required: false
default: null
aliases: []
version_added: "1.6"
state: state:
description: description:
- desired state of the persistent disk - desired state of the persistent disk
@ -132,6 +144,8 @@ def main():
mode = dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']), mode = dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']),
name = dict(required=True), name = dict(required=True),
size_gb = dict(default=10), size_gb = dict(default=10),
image = dict(),
snapshot = dict(),
state = dict(default='present'), state = dict(default='present'),
zone = dict(default='us-central1-b'), zone = dict(default='us-central1-b'),
service_account_email = dict(), service_account_email = dict(),
@ -147,6 +161,8 @@ def main():
mode = module.params.get('mode') mode = module.params.get('mode')
name = module.params.get('name') name = module.params.get('name')
size_gb = module.params.get('size_gb') size_gb = module.params.get('size_gb')
image = module.params.get('image')
snapshot = module.params.get('snapshot')
state = module.params.get('state') state = module.params.get('state')
zone = module.params.get('zone') zone = module.params.get('zone')
@ -204,8 +220,20 @@ def main():
instance_name, zone), changed=False) instance_name, zone), changed=False)
if not disk: if not disk:
if image is not None and snapshot is not None:
module.fail_json(
msg='Cannot give both image (%s) and snapshot (%s)' % (
image, snapshot), changed=False)
lc_image = None
lc_snapshot = None
if image is not None:
lc_image = gce.ex_get_image(image)
elif snapshot is not None:
lc_snapshot = gce.ex_get_snapshot(snapshot)
try: try:
disk = gce.create_volume(size_gb, name, location=zone) disk = gce.create_volume(
size_gb, name, location=zone, image=lc_image,
snapshot=lc_snapshot)
except ResourceExistsError: except ResourceExistsError:
pass pass
except QuotaExceededError: except QuotaExceededError:
@ -214,6 +242,10 @@ def main():
except Exception, e: except Exception, e:
module.fail_json(msg=unexpected_error_msg(e), changed=False) module.fail_json(msg=unexpected_error_msg(e), changed=False)
json_output['size_gb'] = size_gb json_output['size_gb'] = size_gb
if image is not None:
json_output['image'] = image
if snapshot is not None:
json_output['snapshot'] = snapshot
changed = True changed = True
if inst and not is_attached: if inst and not is_attached:
try: try: