def main(): module = AnsibleModule(argument_spec=dict( state=dict(choices=['present', 'absent'], default='present'), name=dict(require=True, aliases=['base_name']), size=dict(default='f1-micro'), source=dict(), image=dict(), image_family=dict(default='debian-8'), disk_type=dict(choices=['pd-standard', 'pd-ssd'], default='pd-standard', type='str'), disk_auto_delete=dict(type='bool', default=True), network=dict(default='default'), subnetwork=dict(), can_ip_forward=dict(type='bool', default=False), external_ip=dict(default='ephemeral'), service_account_email=dict(), service_account_permissions=dict(type='list'), automatic_restart=dict(type='bool', default=None), preemptible=dict(type='bool', default=None), tags=dict(type='list'), metadata=dict(), description=dict(), disks=dict(type='list'), nic_gce_struct=dict(type='list'), project_id=dict(), pem_file=dict(type='path'), credentials_file=dict(type='path'), subnetwork_region=dict(), disks_gce_struct=dict(type='list')), mutually_exclusive=[['source', 'image']], required_one_of=[['image', 'image_family']], supports_check_mode=True) if not HAS_PYTHON26: module.fail_json( msg="GCE module requires python's 'ast' module, python v2.6+") if not HAS_LIBCLOUD: module.fail_json( msg='libcloud with GCE support (0.17.0+) required for this module') try: gce = gce_connect(module) except GoogleBaseError as e: module.fail_json(msg='GCE Connexion failed %s' % to_native(e), exception=traceback.format_exc()) if module.check_mode: (changed, output) = check_if_system_state_would_be_changed(module, gce) module.exit_json(changed=changed, msg=output) else: module_controller(module, gce)
def main(): module = AnsibleModule(argument_spec=dict( name=dict(required=True), family=dict(), description=dict(), source=dict(), state=dict(default='present', choices=['present', 'absent']), zone=dict(default='us-central1-a'), service_account_email=dict(), pem_file=dict(type='path'), project_id=dict(), timeout=dict(type='int', default=180))) if not has_libcloud: module.fail_json(msg='libcloud with GCE support is required.') gce = gce_connect(module) name = module.params.get('name') state = module.params.get('state') family = module.params.get('family') changed = False if family is not None and hasattr( libcloud, '__version__') and libcloud.__version__ <= '0.20.1': module.fail_json( msg="Apache Libcloud 1.0.0+ is required to use 'family' option", changed=False) # user wants to create an image. if state == 'present': changed = create_image(gce, name, module) # user wants to delete the image. if state == 'absent': changed = delete_image(gce, name, module) module.exit_json(changed=changed, name=name)
def main(): module = AnsibleModule(argument_spec=dict( instance_name=dict(required=True), snapshot_name=dict(required=True), state=dict(choices=['present', 'absent'], default='present'), disks=dict(default=None, type='list'), service_account_email=dict(type='str'), credentials_file=dict(type='path'), project_id=dict(type='str'))) if not HAS_LIBCLOUD: module.fail_json( msg= 'libcloud with GCE support (0.19.0+) is required for this module') gce = gce_connect(module) instance_name = module.params.get('instance_name') snapshot_name = module.params.get('snapshot_name') disks = module.params.get('disks') state = module.params.get('state') json_output = dict(changed=False, snapshots_created=[], snapshots_deleted=[], snapshots_existing=[], snapshots_absent=[]) snapshot = None instance = gce.ex_get_node(instance_name, 'all') instance_disks = instance.extra['disks'] for instance_disk in instance_disks: disk_snapshot_name = snapshot_name disk_info = gce._get_components_from_path(instance_disk['source']) device_name = disk_info['name'] device_zone = disk_info['zone'] if disks is None or device_name in disks: volume_obj = gce.ex_get_volume(device_name, device_zone) # If we have more than one disk to snapshot, prepend the disk name if len(instance_disks) > 1: disk_snapshot_name = device_name + "-" + disk_snapshot_name snapshot = find_snapshot(volume_obj, disk_snapshot_name) if snapshot and state == 'present': json_output['snapshots_existing'].append(disk_snapshot_name) elif snapshot and state == 'absent': snapshot.destroy() json_output['changed'] = True json_output['snapshots_deleted'].append(disk_snapshot_name) elif not snapshot and state == 'present': volume_obj.snapshot(disk_snapshot_name) json_output['changed'] = True json_output['snapshots_created'].append(disk_snapshot_name) elif not snapshot and state == 'absent': json_output['snapshots_absent'].append(disk_snapshot_name) module.exit_json(**json_output)
def main(): module = AnsibleModule(argument_spec=dict( allowed=dict(), ipv4_range=dict(), fwname=dict(), name=dict(), src_range=dict(default=[], type='list'), src_tags=dict(default=[], type='list'), target_tags=dict(default=[], type='list'), state=dict(default='present'), service_account_email=dict(), pem_file=dict(type='path'), credentials_file=dict(type='path'), project_id=dict(), mode=dict(default='legacy', choices=['legacy', 'auto', 'custom']), subnet_name=dict(), subnet_region=dict(), subnet_desc=dict(), )) if not HAS_LIBCLOUD: module.fail_json( msg='libcloud with GCE support (0.17.0+) required for this module') gce = gce_connect(module) allowed = module.params.get('allowed') ipv4_range = module.params.get('ipv4_range') fwname = module.params.get('fwname') name = module.params.get('name') src_range = module.params.get('src_range') src_tags = module.params.get('src_tags') target_tags = module.params.get('target_tags') state = module.params.get('state') mode = module.params.get('mode') subnet_name = module.params.get('subnet_name') subnet_region = module.params.get('subnet_region') subnet_desc = module.params.get('subnet_desc') changed = False json_output = {'state': state} if state in ['active', 'present']: network = None subnet = None try: network = gce.ex_get_network(name) json_output['name'] = name if mode == 'legacy': json_output['ipv4_range'] = network.cidr if network and mode == 'custom' and subnet_name: if not hasattr(gce, 'ex_get_subnetwork'): module.fail_json( msg= "Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False) subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) json_output['subnet_name'] = subnet_name json_output['ipv4_range'] = subnet.cidr except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) # user wants to create a new network that doesn't yet exist if name and not network: if not ipv4_range and mode != 'auto': module.fail_json( msg="Network '" + name + "' is not found. To create network in legacy or custom mode, 'ipv4_range' parameter is required", changed=False) args = [ipv4_range if mode == 'legacy' else None] kwargs = {} if mode != 'legacy': kwargs['mode'] = mode try: network = gce.ex_create_network(name, *args, **kwargs) json_output['name'] = name json_output['ipv4_range'] = ipv4_range changed = True except TypeError: module.fail_json( msg= "Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if (subnet_name or ipv4_range) and not subnet and mode == 'custom': if not hasattr(gce, 'ex_create_subnetwork'): module.fail_json( msg= 'Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed) if not subnet_name or not ipv4_range or not subnet_region: module.fail_json( msg= "subnet_name, ipv4_range, and subnet_region required for custom mode", changed=changed) try: subnet = gce.ex_create_subnetwork(subnet_name, cidr=ipv4_range, network=name, region=subnet_region, description=subnet_desc) json_output['subnet_name'] = subnet_name json_output['ipv4_range'] = ipv4_range changed = True except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=changed) if fwname: # user creating a firewall rule if not allowed and not src_range and not src_tags: if changed and network: module.fail_json( msg="Network created, but missing required " + "firewall rule parameter(s)", changed=True) module.fail_json( msg="Missing required firewall rule parameter(s)", changed=False) allowed_list = format_allowed(allowed) # Fetch existing rule and if it exists, compare attributes # update if attributes changed. Create if doesn't exist. try: fw_changed = False fw = gce.ex_get_firewall(fwname) # If old and new attributes are different, we update the firewall rule. # This implicitly lets us clear out attributes as well. # allowed_list is required and must not be None for firewall rules. if allowed_list and (sorted_allowed_list(allowed_list) != sorted_allowed_list(fw.allowed)): fw.allowed = allowed_list fw_changed = True # source_ranges might not be set in the project; cast it to an empty list fw.source_ranges = fw.source_ranges or [] # If these attributes are lists, we sort them first, then compare. # Otherwise, we update if they differ. if fw.source_ranges != src_range: if isinstance(src_range, list): if sorted(fw.source_ranges) != sorted(src_range): fw.source_ranges = src_range fw_changed = True else: fw.source_ranges = src_range fw_changed = True # source_tags might not be set in the project; cast it to an empty list fw.source_tags = fw.source_tags or [] if fw.source_tags != src_tags: if isinstance(src_tags, list): if sorted(fw.source_tags) != sorted(src_tags): fw.source_tags = src_tags fw_changed = True else: fw.source_tags = src_tags fw_changed = True # target_tags might not be set in the project; cast it to an empty list fw.target_tags = fw.target_tags or [] if fw.target_tags != target_tags: if isinstance(target_tags, list): if sorted(fw.target_tags) != sorted(target_tags): fw.target_tags = target_tags fw_changed = True else: fw.target_tags = target_tags fw_changed = True if fw_changed is True: try: gce.ex_update_firewall(fw) changed = True except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) # Firewall rule not found so we try to create it. except ResourceNotFoundError: try: gce.ex_create_firewall(fwname, allowed_list, network=name, source_ranges=src_range, source_tags=src_tags, target_tags=target_tags) changed = True except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) json_output['fwname'] = fwname json_output['allowed'] = allowed json_output['src_range'] = src_range json_output['src_tags'] = src_tags json_output['target_tags'] = target_tags if state in ['absent', 'deleted']: if fwname: json_output['fwname'] = fwname fw = None try: fw = gce.ex_get_firewall(fwname) except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if fw: gce.ex_destroy_firewall(fw) changed = True elif subnet_name: if not hasattr(gce, 'ex_get_subnetwork') or not hasattr( gce, 'ex_destroy_subnetwork'): module.fail_json( msg= 'Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed) json_output['name'] = subnet_name subnet = None try: subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if subnet: gce.ex_destroy_subnetwork(subnet) changed = True elif name: json_output['name'] = name network = None try: network = gce.ex_get_network(name) except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if network: try: gce.ex_destroy_network(network) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) changed = True json_output['changed'] = changed module.exit_json(**json_output)
def main(): module = AnsibleModule(argument_spec=dict( image=dict(default='debian-8'), image_family=dict(), external_projects=dict(type='list'), instance_names=dict(), machine_type=dict(default='n1-standard-1'), metadata=dict(), name=dict(aliases=['base_name']), num_instances=dict(type='int'), network=dict(default='default'), subnetwork=dict(), persistent_boot_disk=dict(type='bool', default=False), disks=dict(type='list'), state=dict(choices=[ 'active', 'present', 'absent', 'deleted', 'started', 'stopped', 'terminated' ], default='present'), tags=dict(type='list'), zone=dict(default='us-central1-a'), service_account_email=dict(), service_account_permissions=dict(type='list'), pem_file=dict(type='path'), credentials_file=dict(type='path'), project_id=dict(), ip_forward=dict(type='bool', default=False), external_ip=dict(default='ephemeral'), disk_auto_delete=dict(type='bool', default=True), disk_size=dict(type='int', default=10), preemptible=dict(type='bool', default=None), ), mutually_exclusive=[('instance_names', 'name')]) if not HAS_PYTHON26: module.fail_json( msg="GCE module requires python's 'ast' module, python v2.6+") if not HAS_LIBCLOUD: module.fail_json( msg='libcloud with GCE support (0.17.0+) required for this module') gce = gce_connect(module) image = module.params.get('image') image_family = module.params.get('image_family') external_projects = module.params.get('external_projects') instance_names = module.params.get('instance_names') name = module.params.get('name') number = module.params.get('num_instances') subnetwork = module.params.get('subnetwork') state = module.params.get('state') zone = module.params.get('zone') preemptible = module.params.get('preemptible') changed = False inames = None if isinstance(instance_names, list): inames = instance_names elif isinstance(instance_names, str): inames = instance_names.split(',') if name: inames = name if not inames: module.fail_json(msg='Must specify a "name" or "instance_names"', changed=False) if not zone: module.fail_json(msg='Must specify a "zone"', changed=False) lc_zone = get_valid_location(module, gce, zone) if preemptible is not None and hasattr( libcloud, '__version__') and libcloud.__version__ < '0.20': module.fail_json( msg= "Apache Libcloud 0.20.0+ is required to use 'preemptible' option", changed=False) if subnetwork is not None and not hasattr(gce, 'ex_get_subnetwork'): module.fail_json( msg="Apache Libcloud 1.0.0+ is required to use 'subnetwork' option", changed=False) json_output = {'zone': zone} if state in ['absent', 'deleted', 'started', 'stopped', 'terminated']: json_output['state'] = state (changed, state_instance_names) = change_instance_state(module, gce, inames, number, lc_zone, state) # based on what user specified, return the same variable, although # value could be different if an instance could not be destroyed if instance_names or name and number: json_output['instance_names'] = state_instance_names elif name: json_output['name'] = name elif state in ['active', 'present']: json_output['state'] = 'present' (changed, instance_data, instance_name_list) = create_instances(module, gce, inames, number, lc_zone) json_output['instance_data'] = instance_data if instance_names: json_output['instance_names'] = instance_name_list elif name: json_output['name'] = name json_output['changed'] = changed module.exit_json(**json_output)
def main(): module = AnsibleModule(argument_spec=dict( backends=dict(type='list', required=True), backend_service_name=dict(required=True), healthchecks=dict(type='list', required=True), service_account_email=dict(), service_account_permissions=dict(type='list'), enable_cdn=dict(type='bool'), port_name=dict(type='str'), protocol=dict(type='str', default='TCP', choices=['HTTP', 'HTTPS', 'SSL', 'TCP']), timeout=dict(type='int'), state=dict(choices=['absent', 'present'], default='present'), pem_file=dict(), credentials_file=dict(), project_id=dict(), ), ) if not HAS_PYTHON26: module.fail_json( msg="GCE module requires python's 'ast' module, python v2.6+") if not HAS_LIBCLOUD: module.fail_json( msg= 'libcloud with GCE Backend Service support (1.3+) required for this module.' ) gce = gce_connect(module) if not hasattr(gce, 'ex_create_instancegroupmanager'): module.fail_json( msg= 'libcloud with GCE Backend Service support (1.3+) required for this module.', changed=False) params = {} params['state'] = module.params.get('state') params['backend_service_name'] = module.params.get('backend_service_name') params['backends'] = module.params.get('backends') params['healthchecks'] = module.params.get('healthchecks') params['enable_cdn'] = module.params.get('enable_cdn', None) params['port_name'] = module.params.get('port_name', None) params['protocol'] = module.params.get('protocol', None) params['timeout'] = module.params.get('timeout', None) try: _validate_params(params) except Exception as e: module.fail_json(msg=e.message, changed=False) changed = False json_output = {'state': params['state']} bes = get_backend_service(gce, params['backend_service_name']) if not bes: if params['state'] == 'absent': # Doesn't exist and state==absent. changed = False module.fail_json(msg="Cannot delete unknown backend service: %s" % (params['backend_service_name'])) else: # Create (changed, json_output['backend_service_created']) = create_backend_service( gce, params) elif params['state'] == 'absent': # Delete (changed, json_output['backend_service_deleted']) = delete_backend_service(bes) else: # TODO(supertom): Add update support when it is available in libcloud. changed = False json_output['changed'] = changed json_output.update(params) module.exit_json(**json_output)
def main(): module = AnsibleModule( argument_spec=dict( instance_name=dict(type='str'), instance_pattern=dict(type='str'), tags=dict(type='list', required=True), state=dict(type='str', default='present', choices=['absent', 'present']), zone=dict(type='str', default='us-central1-a'), service_account_email=dict(type='str'), pem_file=dict(type='path'), project_id=dict(type='str'), ), mutually_exclusive=[ ['instance_name', 'instance_pattern'] ], required_one_of=[ ['instance_name', 'instance_pattern'] ], ) instance_name = module.params.get('instance_name') instance_pattern = module.params.get('instance_pattern') state = module.params.get('state') tags = module.params.get('tags') zone = module.params.get('zone') changed = False if not HAS_LIBCLOUD: module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module') gce = gce_connect(module) # Create list of nodes to operate on matching_nodes = [] try: if instance_pattern: instances = gce.list_nodes(ex_zone=zone) # no instances in zone if not instances: module.exit_json(changed=False, tags=tags, zone=zone, instances_updated=[]) try: # Python regex fully supported: https://docs.python.org/2/library/re.html p = re.compile(instance_pattern) matching_nodes = [i for i in instances if p.search(i.name) is not None] except re.error as e: module.fail_json(msg='Regex error for pattern %s: %s' % (instance_pattern, e), changed=False) else: matching_nodes = [gce.ex_get_node(instance_name, zone=zone)] except ResourceNotFoundError: module.fail_json(msg='Instance %s not found in zone %s' % (instance_name, zone), changed=False) except GoogleBaseError as e: module.fail_json(msg=str(e), changed=False, exception=traceback.format_exc()) # Tag nodes instance_pattern_matches = [] tags_changed = [] for node in matching_nodes: changed, tags_changed = modify_tags(gce, module, node, tags, state) if changed: instance_pattern_matches.append({'instance_name': node.name, 'tags_changed': tags_changed}) if instance_pattern: module.exit_json(changed=changed, instance_pattern=instance_pattern, tags=tags_changed, zone=zone, instances_updated=instance_pattern_matches) else: module.exit_json(changed=changed, instance_name=instance_name, tags=tags_changed, zone=zone)
def main(): module = AnsibleModule(argument_spec=dict( httphealthcheck_name=dict(), httphealthcheck_port=dict(default=80, type='int'), httphealthcheck_path=dict(default='/'), httphealthcheck_interval=dict(default=5, type='int'), httphealthcheck_timeout=dict(default=5, type='int'), httphealthcheck_unhealthy_count=dict(default=2, type='int'), httphealthcheck_healthy_count=dict(default=2, type='int'), httphealthcheck_host=dict(), name=dict(), protocol=dict(default='tcp'), region=dict(), external_ip=dict(), port_range=dict(), members=dict(type='list'), state=dict(default='present'), service_account_email=dict(), pem_file=dict(type='path'), credentials_file=dict(type='path'), project_id=dict(), )) if not HAS_LIBCLOUD: module.fail_json( msg='libcloud with GCE support (0.13.3+) required for this module.' ) gce = gce_connect(module) httphealthcheck_name = module.params.get('httphealthcheck_name') httphealthcheck_port = module.params.get('httphealthcheck_port') httphealthcheck_path = module.params.get('httphealthcheck_path') httphealthcheck_interval = module.params.get('httphealthcheck_interval') httphealthcheck_timeout = module.params.get('httphealthcheck_timeout') httphealthcheck_unhealthy_count = module.params.get( 'httphealthcheck_unhealthy_count') httphealthcheck_healthy_count = module.params.get( 'httphealthcheck_healthy_count') httphealthcheck_host = module.params.get('httphealthcheck_host') name = module.params.get('name') protocol = module.params.get('protocol') region = module.params.get('region') external_ip = module.params.get('external_ip') port_range = module.params.get('port_range') members = module.params.get('members') state = module.params.get('state') try: gcelb = get_driver_lb(Provider_lb.GCE)(gce_driver=gce) gcelb.connection.user_agent_append( "%s/%s" % (USER_AGENT_PRODUCT, USER_AGENT_VERSION)) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) changed = False json_output = {'name': name, 'state': state} if not name and not httphealthcheck_name: module.fail_json(msg='Nothing to do, please specify a "name" ' + 'or "httphealthcheck_name" parameter', changed=False) if state in ['active', 'present']: # first, create the httphealthcheck if requested hc = None if httphealthcheck_name: json_output['httphealthcheck_name'] = httphealthcheck_name try: hc = gcelb.ex_create_healthcheck( httphealthcheck_name, host=httphealthcheck_host, path=httphealthcheck_path, port=httphealthcheck_port, interval=httphealthcheck_interval, timeout=httphealthcheck_timeout, unhealthy_threshold=httphealthcheck_unhealthy_count, healthy_threshold=httphealthcheck_healthy_count) changed = True except ResourceExistsError: hc = gce.ex_get_healthcheck(httphealthcheck_name) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if hc is not None: json_output['httphealthcheck_host'] = hc.extra['host'] json_output['httphealthcheck_path'] = hc.path json_output['httphealthcheck_port'] = hc.port json_output['httphealthcheck_interval'] = hc.interval json_output['httphealthcheck_timeout'] = hc.timeout json_output[ 'httphealthcheck_unhealthy_count'] = hc.unhealthy_threshold json_output[ 'httphealthcheck_healthy_count'] = hc.healthy_threshold # create the forwarding rule (and target pool under the hood) lb = None if name: if not region: module.fail_json(msg='Missing required region name', changed=False) nodes = [] output_nodes = [] json_output['name'] = name # members is a python list of 'zone/inst' strings if members: for node in members: try: zone, node_name = node.split('/') nodes.append(gce.ex_get_node(node_name, zone)) output_nodes.append(node) except Exception: # skip nodes that are badly formatted or don't exist pass try: if hc is not None: lb = gcelb.create_balancer(name, port_range, protocol, None, nodes, ex_region=region, ex_healthchecks=[hc], ex_address=external_ip) else: lb = gcelb.create_balancer(name, port_range, protocol, None, nodes, ex_region=region, ex_address=external_ip) changed = True except ResourceExistsError: lb = gcelb.get_balancer(name) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if lb is not None: json_output['members'] = output_nodes json_output['protocol'] = protocol json_output['region'] = region json_output['external_ip'] = lb.ip json_output['port_range'] = lb.port hc_names = [] if 'healthchecks' in lb.extra: for hc in lb.extra['healthchecks']: hc_names.append(hc.name) json_output['httphealthchecks'] = hc_names if state in ['absent', 'deleted']: # first, delete the load balancer (forwarding rule and target pool) # if specified. if name: json_output['name'] = name try: lb = gcelb.get_balancer(name) gcelb.destroy_balancer(lb) changed = True except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) # destroy the health check if specified if httphealthcheck_name: json_output['httphealthcheck_name'] = httphealthcheck_name try: hc = gce.ex_get_healthcheck(httphealthcheck_name) gce.ex_destroy_healthcheck(hc) changed = True except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) json_output['changed'] = changed module.exit_json(**json_output)
def main(): module = AnsibleModule( argument_spec=dict( delete_on_termination=dict(type='bool'), detach_only=dict(type='bool'), instance_name=dict(), mode=dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']), name=dict(required=True), size_gb=dict(default=10), disk_type=dict(default='pd-standard'), image=dict(), image_family=dict(), external_projects=dict(type='list'), snapshot=dict(), state=dict(default='present'), zone=dict(default='us-central1-b'), service_account_email=dict(), pem_file=dict(type='path'), credentials_file=dict(type='path'), project_id=dict(), ) ) if not HAS_LIBCLOUD: module.fail_json(msg='libcloud with GCE support (0.17.0+) is required for this module') gce = gce_connect(module) delete_on_termination = module.params.get('delete_on_termination') detach_only = module.params.get('detach_only') instance_name = module.params.get('instance_name') mode = module.params.get('mode') name = module.params.get('name') size_gb = module.params.get('size_gb') disk_type = module.params.get('disk_type') image = module.params.get('image') image_family = module.params.get('image_family') external_projects = module.params.get('external_projects') snapshot = module.params.get('snapshot') state = module.params.get('state') zone = module.params.get('zone') if delete_on_termination and not instance_name: module.fail_json( msg='Must specify an instance name when requesting delete on termination', changed=False) if detach_only and not instance_name: module.fail_json( msg='Must specify an instance name when detaching a disk', changed=False) disk = inst = None changed = is_attached = False json_output = {'name': name, 'zone': zone, 'state': state, 'disk_type': disk_type} if detach_only: json_output['detach_only'] = True json_output['detached_from_instance'] = instance_name if instance_name: # user wants to attach/detach from an existing instance try: inst = gce.ex_get_node(instance_name, zone) # is the disk attached? for d in inst.extra['disks']: if d['deviceName'] == name: is_attached = True json_output['attached_mode'] = d['mode'] json_output['attached_to_instance'] = inst.name except Exception: pass # find disk if it already exists try: disk = gce.ex_get_volume(name) json_output['size_gb'] = int(disk.size) except ResourceNotFoundError: pass except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) # user wants a disk to exist. If "instance_name" is supplied the user # also wants it attached if state in ['active', 'present']: if not size_gb: module.fail_json(msg="Must supply a size_gb", changed=False) try: size_gb = int(round(float(size_gb))) if size_gb < 1: raise Exception except Exception: module.fail_json(msg="Must supply a size_gb larger than 1 GB", changed=False) if instance_name and inst is None: module.fail_json(msg='Instance %s does not exist in zone %s' % ( 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_family is not None: lc_image = gce.ex_get_image_from_family(image_family, ex_project_list=external_projects) elif image is not None: lc_image = gce.ex_get_image(image, ex_project_list=external_projects) elif snapshot is not None: lc_snapshot = gce.ex_get_snapshot(snapshot) try: disk = gce.create_volume( size_gb, name, location=zone, image=lc_image, snapshot=lc_snapshot, ex_disk_type=disk_type) except ResourceExistsError: pass except QuotaExceededError: module.fail_json(msg='Requested disk size exceeds quota', changed=False) except Exception as 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: gce.attach_volume(inst, disk, device=name, ex_mode=mode, ex_auto_delete=delete_on_termination) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) json_output['attached_to_instance'] = inst.name json_output['attached_mode'] = mode if delete_on_termination: json_output['delete_on_termination'] = True changed = True # user wants to delete a disk (or perhaps just detach it). if state in ['absent', 'deleted'] and disk: if inst and is_attached: try: gce.detach_volume(disk, ex_node=inst) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) changed = True if not detach_only: try: gce.destroy_volume(disk) except ResourceInUseError as e: module.fail_json(msg=str(e.value), changed=False) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) changed = True json_output['changed'] = changed module.exit_json(**json_output)
def main(): module = AnsibleModule( argument_spec=dict( name=dict(required=True), template=dict(), recreate_instances=dict(type='bool', default=False), # Do not set a default size here. For Create and some update # operations, it is required and should be explicitly set. # Below, we set it to the existing value if it has not been set. size=dict(type='int'), state=dict(choices=['absent', 'present'], default='present'), zone=dict(required=True), autoscaling=dict(type='dict', default=None), named_ports=dict(type='list', default=None), service_account_email=dict(), service_account_permissions=dict(type='list'), pem_file=dict(type='path'), credentials_file=dict(type='path'), project_id=dict(), ), ) if not HAS_PYTHON26: module.fail_json( msg="GCE module requires python's 'ast' module, python v2.6+") if not HAS_LIBCLOUD: module.fail_json( msg= 'libcloud with GCE Managed Instance Group support (1.2+) required for this module.' ) gce = gce_connect(module) if not hasattr(gce, 'ex_create_instancegroupmanager'): module.fail_json( msg= 'libcloud with GCE Managed Instance Group support (1.2+) required for this module.', changed=False) params = {} params['state'] = module.params.get('state') params['zone'] = module.params.get('zone') params['name'] = module.params.get('name') params['size'] = module.params.get('size') params['template'] = module.params.get('template') params['recreate_instances'] = module.params.get('recreate_instances') params['autoscaling'] = module.params.get('autoscaling', None) params['named_ports'] = module.params.get('named_ports', None) (valid_autoscaling, as_msg) = _validate_autoscaling_params(params) if not valid_autoscaling: module.fail_json(msg=as_msg, changed=False) if params['named_ports'] is not None and not hasattr( gce, 'ex_instancegroup_set_named_ports'): module.fail_json( msg= "Apache Libcloud 1.3.0+ is required to use 'named_ports' option", changed=False) (valid_named_ports, np_msg) = _validate_named_port_params(params) if not valid_named_ports: module.fail_json(msg=np_msg, changed=False) changed = False json_output = {'state': params['state'], 'zone': params['zone']} mig = get_mig(gce, params['name'], params['zone']) if not mig: if params['state'] == 'absent': # Doesn't exist in GCE, and state==absent. changed = False module.fail_json( msg="Cannot delete unknown managed instance group: %s" % (params['name'])) else: # Create MIG req_create_fields = [ {'name': 'template', 'required': True, 'type': str}, {'name': 'size', 'required': True, 'type': int} ] # yapf: disable (valid_create_fields, valid_create_msg) = _check_params(params, req_create_fields) if not valid_create_fields: module.fail_json(msg=valid_create_msg, changed=False) (changed, json_output['created_instances']) = create_mig(gce, params) if params['autoscaling'] and params['autoscaling'][ 'enabled'] is True: # Fetch newly-created MIG and create Autoscaler for it. mig = get_mig(gce, params['name'], params['zone']) if not mig: module.fail_json( msg='Unable to fetch created MIG %s to create \ autoscaler in zone: %s' % (params['name'], params['zone']), changed=False) if not create_autoscaler(gce, mig, params['autoscaling']): module.fail_json( msg='Unable to fetch MIG %s to create autoscaler \ in zone: %s' % (params['name'], params['zone']), changed=False) json_output['created_autoscaler'] = True # Add named ports if available if params['named_ports']: mig = get_mig(gce, params['name'], params['zone']) if not mig: module.fail_json( msg='Unable to fetch created MIG %s to create \ autoscaler in zone: %s' % (params['name'], params['zone']), changed=False) json_output['set_named_ports'] = update_named_ports( mig, params['named_ports']) if json_output['set_named_ports']: json_output['named_ports'] = params['named_ports'] elif params['state'] == 'absent': # Delete MIG # First, check and remove the autoscaler, if present. # Note: multiple autoscalers can be associated to a single MIG. We # only handle the one that is named, but we might want to think about this. if params['autoscaling']: autoscaler = get_autoscaler(gce, params['autoscaling']['name'], params['zone']) if not autoscaler: module.fail_json(msg='Unable to fetch autoscaler %s to delete \ in zone: %s' % (params['autoscaling']['name'], params['zone']), changed=False) changed = delete_autoscaler(autoscaler) json_output['deleted_autoscaler'] = changed # Now, delete the MIG. (changed, json_output['deleted_instances']) = delete_mig(mig) else: # Update MIG # If we're going to update a MIG, we need a size and template values. # If not specified, we use the values from the existing MIG. if not params['size']: params['size'] = mig.size if not params['template']: params['template'] = mig.template.name if params['template'] != mig.template.name: # Update Instance Template. new_template = gce.ex_get_instancetemplate(params['template']) mig.set_instancetemplate(new_template) json_output['updated_instancetemplate'] = True changed = True if params['recreate_instances'] is True: # Recreate Instances. (changed, json_output['recreated_instances'] ) = recreate_instances_in_mig(mig) if params['size'] != mig.size: # Resize MIG. keystr = 'created' if params['size'] > mig.size else 'deleted' (changed, json_output['resize_%s_instances' % (keystr)]) = resize_mig(mig, params['size']) # Update Autoscaler if params['autoscaling']: autoscaler = get_autoscaler(gce, params['autoscaling']['name'], params['zone']) if not autoscaler: # Try to create autoscaler. # Note: this isn't perfect, if the autoscaler name has changed # we wouldn't know that here. if not create_autoscaler(gce, mig, params['autoscaling']): module.fail_json( msg='Unable to create autoscaler %s for existing MIG %s\ in zone: %s' % (params['autoscaling']['name'], params['name'], params['zone']), changed=False) json_output['created_autoscaler'] = True changed = True else: if params['autoscaling']['enabled'] is False: # Delete autoscaler changed = delete_autoscaler(autoscaler) json_output['delete_autoscaler'] = changed else: # Update policy, etc. changed = update_autoscaler(gce, autoscaler, params['autoscaling']) json_output['updated_autoscaler'] = changed named_ports = params['named_ports'] or [] json_output['updated_named_ports'] = update_named_ports( mig, named_ports) if json_output['updated_named_ports']: json_output['named_ports'] = named_ports json_output['changed'] = changed json_output.update(params) module.exit_json(**json_output)