GCE libcloud 0.15 support and code cleanup * Code formatting (indentation and white space) fixes for improved PEP8 conformity. * Remove redundant backslashes inside parentheses. * Test for object identity should be 'is not None'. * Test for membership should be 'not in'. * Fit docstring to the PEP8 79 character limit. * Use forward compatible Python 2.6+ 'except .. as' syntax for exception handling. * Support libcloud > 0.15 'metadata' argument format.

pull/18777/head
Pedro Romano 10 years ago committed by Matt Clay
parent 65b9243056
commit bcae9a2b5e

@ -47,7 +47,8 @@ options:
aliases: [] aliases: []
metadata: metadata:
description: description:
- a hash/dictionary of custom data for the instance; '{"key":"value",...}' - a hash/dictionary of custom data for the instance;
'{"key": "value", ...}'
required: false required: false
default: null default: null
aliases: [] aliases: []
@ -61,11 +62,17 @@ options:
service_account_permissions: service_account_permissions:
version_added: 2.0 version_added: 2.0
description: description:
- service account permissions (see U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create), --scopes section for detailed information) - service account permissions (see
U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
--scopes section for detailed information)
required: false required: false
default: null default: null
aliases: [] choices: [
choices: ["bigquery", "cloud-platform", "compute-ro", "compute-rw", "computeaccounts-ro", "computeaccounts-rw", "datastore", "logging-write", "monitoring", "sql", "sql-admin", "storage-full", "storage-ro", "storage-rw", "taskqueue", "userinfo-email"] "bigquery", "cloud-platform", "compute-ro", "compute-rw",
"computeaccounts-ro", "computeaccounts-rw", "datastore", "logging-write",
"monitoring", "sql", "sql-admin", "storage-full", "storage-ro",
"storage-rw", "taskqueue", "userinfo-email"
]
pem_file: pem_file:
version_added: 1.5.1 version_added: 1.5.1
description: description:
@ -99,7 +106,10 @@ options:
aliases: [] aliases: []
disks: disks:
description: 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). - 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 required: false
default: null default: null
aliases: [] aliases: []
@ -126,7 +136,8 @@ options:
ip_forward: ip_forward:
version_added: "1.9" version_added: "1.9"
description: description:
- set to true if the instance can forward ip packets (useful for gateways) - set to true if the instance can forward ip packets (useful for
gateways)
required: false required: false
default: "false" default: "false"
aliases: [] aliases: []
@ -185,7 +196,8 @@ EXAMPLES = '''
tasks: tasks:
- name: Launch instances - name: Launch instances
local_action: gce instance_names={{names}} machine_type={{machine_type}} local_action: gce instance_names={{names}} machine_type={{machine_type}}
image={{image}} zone={{zone}} service_account_email={{ service_account_email }} image={{image}} zone={{zone}}
service_account_email={{ service_account_email }}
pem_file={{ pem_file }} project_id={{ project_id }} pem_file={{ pem_file }} project_id={{ project_id }}
register: gce register: gce
- name: Wait for SSH to come up - name: Wait for SSH to come up
@ -213,10 +225,11 @@ EXAMPLES = '''
''' '''
try: try:
import libcloud
from libcloud.compute.types import Provider from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver from libcloud.compute.providers import get_driver
from libcloud.common.google import GoogleBaseError, QuotaExceededError, \ from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
ResourceExistsError, ResourceInUseError, ResourceNotFoundError ResourceExistsError, ResourceInUseError, ResourceNotFoundError
_ = Provider.GCE _ = Provider.GCE
HAS_LIBCLOUD = True HAS_LIBCLOUD = True
except ImportError: except ImportError:
@ -257,7 +270,7 @@ def get_instance_info(inst):
public_ip = inst.public_ips[0] public_ip = inst.public_ips[0]
return({ return({
'image': not inst.image is None and inst.image.split('/')[-1] or None, 'image': inst.image is not None and inst.image.split('/')[-1] or None,
'disks': disk_names, 'disks': disk_names,
'machine_type': inst.size, 'machine_type': inst.size,
'metadata': metadata, 'metadata': metadata,
@ -268,7 +281,8 @@ def get_instance_info(inst):
'status': ('status' in inst.extra) and inst.extra['status'] or None, 'status': ('status' in inst.extra) and inst.extra['status'] or None,
'tags': ('tags' in inst.extra) and inst.extra['tags'] or [], 'tags': ('tags' in inst.extra) and inst.extra['tags'] or [],
'zone': ('zone' in inst.extra) and inst.extra['zone'].name or None, 'zone': ('zone' in inst.extra) and inst.extra['zone'].name or None,
}) })
def create_instances(module, gce, instance_names): def create_instances(module, gce, instance_names):
"""Creates new instances. Attributes other than instance_names are picked """Creates new instances. Attributes other than instance_names are picked
@ -326,25 +340,31 @@ def create_instances(module, gce, instance_names):
# with: # with:
# [ {'key': key1, 'value': value1}, {'key': key2, 'value': value2}, ...] # [ {'key': key1, 'value': value1}, {'key': key2, 'value': value2}, ...]
if metadata: if metadata:
try: if isinstance(metadata, dict):
md = literal_eval(str(metadata)) md = metadata
if not isinstance(md, dict): else:
raise ValueError('metadata must be a dict') try:
except ValueError, e: md = literal_eval(str(metadata))
module.fail_json(msg='bad metadata: %s' % str(e)) if not isinstance(md, dict):
except SyntaxError, e: raise ValueError('metadata must be a dict')
module.fail_json(msg='bad metadata syntax') except ValueError as e:
module.fail_json(msg='bad metadata: %s' % str(e))
except SyntaxError as e:
module.fail_json(msg='bad metadata syntax')
if hasattr(libcloud, '__version__') and libcloud.__version__ < '0.15':
items = [] items = []
for k,v in md.items(): for k, v in md.items():
items.append({"key": k,"value": v}) items.append({"key": k, "value": v})
metadata = {'items': items} metadata = {'items': items}
else:
metadata = md
ex_sa_perms = [] ex_sa_perms = []
bad_perms = [] bad_perms = []
if service_account_permissions: if service_account_permissions:
for perm in service_account_permissions: for perm in service_account_permissions:
if not perm in gce.SA_SCOPES_MAP.keys(): if perm not in gce.SA_SCOPES_MAP.keys():
bad_perms.append(perm) bad_perms.append(perm)
if len(bad_perms) > 0: if len(bad_perms) > 0:
module.fail_json(msg='bad permissions: %s' % str(bad_perms)) module.fail_json(msg='bad permissions: %s' % str(bad_perms))
@ -357,7 +377,7 @@ def create_instances(module, gce, instance_names):
# These variables all have default values but check just in case # These variables all have default values but check just in case
if not lc_image or not lc_network or not lc_machine_type or not lc_zone: if not lc_image or not lc_network or not lc_machine_type or not lc_zone:
module.fail_json(msg='Missing required create instance variable', module.fail_json(msg='Missing required create instance variable',
changed=False) changed=False)
for name in instance_names: for name in instance_names:
pd = None pd = None
@ -370,16 +390,19 @@ def create_instances(module, gce, instance_names):
pd = gce.ex_get_volume("%s" % name, lc_zone) pd = gce.ex_get_volume("%s" % name, lc_zone)
inst = None inst = None
try: try:
inst = gce.create_node(name, lc_machine_type, lc_image, inst = gce.create_node(
location=lc_zone, ex_network=network, ex_tags=tags, name, lc_machine_type, lc_image, location=lc_zone,
ex_metadata=metadata, ex_boot_disk=pd, ex_can_ip_forward=ip_forward, ex_network=network, ex_tags=tags, ex_metadata=metadata,
external_ip=external_ip, ex_disk_auto_delete=disk_auto_delete, ex_service_accounts=ex_sa_perms) ex_boot_disk=pd, ex_can_ip_forward=ip_forward,
external_ip=external_ip, ex_disk_auto_delete=disk_auto_delete,
ex_service_accounts=ex_sa_perms
)
changed = True changed = True
except ResourceExistsError: except ResourceExistsError:
inst = gce.ex_get_node(name, lc_zone) inst = gce.ex_get_node(name, lc_zone)
except GoogleBaseError, e: except GoogleBaseError as e:
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): for i, lc_disk in enumerate(lc_disks):
# Check whether the disk is already attached # Check whether the disk is already attached
@ -435,7 +458,7 @@ def terminate_instances(module, gce, instance_names, zone_name):
inst = gce.ex_get_node(name, zone_name) inst = gce.ex_get_node(name, zone_name)
except ResourceNotFoundError: except ResourceNotFoundError:
pass pass
except Exception, e: except Exception as e:
module.fail_json(msg=unexpected_error_msg(e), changed=False) module.fail_json(msg=unexpected_error_msg(e), changed=False)
if inst: if inst:
gce.destroy_node(inst) gce.destroy_node(inst)
@ -447,27 +470,27 @@ def terminate_instances(module, gce, instance_names, zone_name):
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec=dict(
image = dict(default='debian-7'), image=dict(default='debian-7'),
instance_names = dict(), instance_names=dict(),
machine_type = dict(default='n1-standard-1'), machine_type=dict(default='n1-standard-1'),
metadata = dict(), metadata=dict(),
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'), 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'),
zone = dict(default='us-central1-a'), zone=dict(default='us-central1-a'),
service_account_email = dict(), service_account_email=dict(),
service_account_permissions = dict(type='list'), service_account_permissions=dict(type='list'),
pem_file = dict(), pem_file=dict(),
project_id = dict(), project_id=dict(),
ip_forward = dict(type='bool', default=False), ip_forward=dict(type='bool', default=False),
external_ip = dict(choices=['ephemeral', 'none'], external_ip=dict(choices=['ephemeral', 'none'],
default='ephemeral'), default='ephemeral'),
disk_auto_delete = dict(type='bool', default=True), disk_auto_delete=dict(type='bool', default=True),
) )
) )
@ -500,15 +523,15 @@ def main():
inames.append(name) inames.append(name)
if not inames: if not inames:
module.fail_json(msg='Must specify a "name" or "instance_names"', module.fail_json(msg='Must specify a "name" or "instance_names"',
changed=False) changed=False)
if not zone: if not zone:
module.fail_json(msg='Must specify a "zone"', changed=False) module.fail_json(msg='Must specify a "zone"', changed=False)
json_output = {'zone': zone} json_output = {'zone': zone}
if state in ['absent', 'deleted']: if state in ['absent', 'deleted']:
json_output['state'] = 'absent' json_output['state'] = 'absent'
(changed, terminated_instance_names) = terminate_instances(module, (changed, terminated_instance_names) = terminate_instances(
gce, inames, zone) module, gce, inames, zone)
# based on what user specified, return the same variable, although # based on what user specified, return the same variable, although
# value could be different if an instance could not be destroyed # value could be different if an instance could not be destroyed
@ -519,15 +542,14 @@ def main():
elif state in ['active', 'present']: elif state in ['active', 'present']:
json_output['state'] = 'present' json_output['state'] = 'present'
(changed, instance_data,instance_name_list) = create_instances( (changed, instance_data, instance_name_list) = create_instances(
module, gce, inames) module, gce, inames)
json_output['instance_data'] = instance_data json_output['instance_data'] = instance_data
if instance_names: if instance_names:
json_output['instance_names'] = instance_name_list json_output['instance_names'] = instance_name_list
elif name: elif name:
json_output['name'] = name json_output['name'] = name
json_output['changed'] = changed json_output['changed'] = changed
module.exit_json(**json_output) module.exit_json(**json_output)

Loading…
Cancel
Save