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:
commit
16ed24d0c0
2 changed files with 88 additions and 5 deletions
53
cloud/gce
53
cloud/gce
|
@ -89,6 +89,13 @@ options:
|
|||
required: false
|
||||
default: "false"
|
||||
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:
|
||||
description:
|
||||
- desired state of the resource
|
||||
|
@ -209,8 +216,16 @@ def get_instance_info(inst):
|
|||
netname = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
|
||||
except:
|
||||
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({
|
||||
'image': not inst.image is None and inst.image.split('/')[-1] or None,
|
||||
'disks': disk_names,
|
||||
'machine_type': inst.size,
|
||||
'metadata': metadata,
|
||||
'name': inst.name,
|
||||
|
@ -240,6 +255,7 @@ def create_instances(module, gce, instance_names):
|
|||
metadata = module.params.get('metadata')
|
||||
network = module.params.get('network')
|
||||
persistent_boot_disk = module.params.get('persistent_boot_disk')
|
||||
disks = module.params.get('disks')
|
||||
state = module.params.get('state')
|
||||
tags = module.params.get('tags')
|
||||
zone = module.params.get('zone')
|
||||
|
@ -248,6 +264,16 @@ def create_instances(module, gce, instance_names):
|
|||
changed = False
|
||||
|
||||
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_machine_type = gce.ex_get_size(machine_type)
|
||||
lc_zone = gce.ex_get_zone(zone)
|
||||
|
@ -282,7 +308,9 @@ def create_instances(module, gce, instance_names):
|
|||
|
||||
for name in instance_names:
|
||||
pd = None
|
||||
if persistent_boot_disk:
|
||||
if lc_disks:
|
||||
pd = lc_disks[0]
|
||||
elif persistent_boot_disk:
|
||||
try:
|
||||
pd = gce.create_volume(None, "%s" % name, image=lc_image)
|
||||
except ResourceExistsError:
|
||||
|
@ -299,6 +327,28 @@ def create_instances(module, gce, instance_names):
|
|||
module.fail_json(msg='Unexpected error attempting to create ' + \
|
||||
'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:
|
||||
new_instances.append(inst)
|
||||
|
||||
|
@ -351,6 +401,7 @@ def main():
|
|||
name = dict(),
|
||||
network = dict(default='default'),
|
||||
persistent_boot_disk = dict(type='bool', default=False),
|
||||
disks = dict(type='list'),
|
||||
state = dict(choices=['active', 'present', 'absent', 'deleted'],
|
||||
default='present'),
|
||||
tags = dict(type='list'),
|
||||
|
|
40
cloud/gce_pd
40
cloud/gce_pd
|
@ -24,9 +24,7 @@ short_description: utilize GCE persistent disk resources
|
|||
description:
|
||||
- This module can create and destroy unformatted GCE persistent disks
|
||||
U(https://developers.google.com/compute/docs/disks#persistentdisks).
|
||||
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.
|
||||
It also supports attaching and detaching disks from running instances.
|
||||
Full install/configuration instructions for the gce* modules can
|
||||
be found in the comments of ansible/test/gce_tests.py.
|
||||
options:
|
||||
|
@ -62,6 +60,20 @@ options:
|
|||
required: false
|
||||
default: 10
|
||||
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:
|
||||
description:
|
||||
- desired state of the persistent disk
|
||||
|
@ -132,6 +144,8 @@ def main():
|
|||
mode = dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']),
|
||||
name = dict(required=True),
|
||||
size_gb = dict(default=10),
|
||||
image = dict(),
|
||||
snapshot = dict(),
|
||||
state = dict(default='present'),
|
||||
zone = dict(default='us-central1-b'),
|
||||
service_account_email = dict(),
|
||||
|
@ -147,6 +161,8 @@ def main():
|
|||
mode = module.params.get('mode')
|
||||
name = module.params.get('name')
|
||||
size_gb = module.params.get('size_gb')
|
||||
image = module.params.get('image')
|
||||
snapshot = module.params.get('snapshot')
|
||||
state = module.params.get('state')
|
||||
zone = module.params.get('zone')
|
||||
|
||||
|
@ -204,8 +220,20 @@ def main():
|
|||
instance_name, zone), changed=False)
|
||||
|
||||
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:
|
||||
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:
|
||||
pass
|
||||
except QuotaExceededError:
|
||||
|
@ -214,6 +242,10 @@ def main():
|
|||
except Exception, e:
|
||||
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
||||
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
|
||||
if inst and not is_attached:
|
||||
try:
|
||||
|
|
Loading…
Reference in a new issue