Request a single GCE instance from a data dict.

    .. versionchanged: 2017.7.0

def request_instance(vm_):
    '''
    Request a single GCE instance from a data dict.

    .. versionchanged: 2017.7.0
    '''
    if not GCE_VM_NAME_REGEX.match(vm_['name']):
        raise SaltCloudSystemExit(
            'VM names must start with a letter, only contain letters, numbers, or dashes '
            'and cannot end in a dash.'
        )

    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'gce',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    __utils__['cloud.fire_event'](
        'event',
        'create instance',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args=__utils__['cloud.filter_event']('creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    conn = get_conn()

    kwargs = {
        'name': vm_['name'],
        'size': __get_size(conn, vm_),
        'image': __get_image(conn, vm_),
        'location': __get_location(conn, vm_),
        'ex_network': __get_network(conn, vm_),
        'ex_subnetwork': __get_subnetwork(vm_),
        'ex_tags': __get_tags(vm_),
        'ex_metadata': __get_metadata(vm_),
    }
    external_ip = config.get_cloud_config_value(
        'external_ip', vm_, __opts__, default='ephemeral'
    )

    if external_ip.lower() == 'ephemeral':
        external_ip = 'ephemeral'
        vm_['external_ip'] = external_ip
    elif external_ip == 'None':
        external_ip = None
        vm_['external_ip'] = external_ip
    else:
        region = __get_region(conn, vm_)
        external_ip = __create_orget_address(conn, external_ip, region)
        vm_['external_ip'] = {
            'name': external_ip.name,
            'address': external_ip.address,
            'region': external_ip.region.name
        }
    kwargs['external_ip'] = external_ip

    if LIBCLOUD_VERSION_INFO > (0, 15, 1):

        kwargs.update({
            'ex_disk_type': config.get_cloud_config_value(
                'ex_disk_type', vm_, __opts__, default='pd-standard'),
            'ex_disk_auto_delete': config.get_cloud_config_value(
                'ex_disk_auto_delete', vm_, __opts__, default=True),
            'ex_disks_gce_struct': config.get_cloud_config_value(
                'ex_disks_gce_struct', vm_, __opts__, default=None),
            'ex_service_accounts': config.get_cloud_config_value(
                'ex_service_accounts', vm_, __opts__, default=None),
            'ex_can_ip_forward': config.get_cloud_config_value(
                'ip_forwarding', vm_, __opts__, default=False),
            'ex_preemptible': config.get_cloud_config_value(
                'preemptible', vm_, __opts__, default=False)
        })
        if kwargs.get('ex_disk_type') not in ('pd-standard', 'pd-ssd'):
            raise SaltCloudSystemExit(
                'The value of \'ex_disk_type\' needs to be one of: '
                '\'pd-standard\', \'pd-ssd\''
            )

    # GCE accelerator options are only supported as of libcloud >= 2.3.0
    # and Python 3+ is required so that libcloud will detect a type of
    # 'string' rather than 'unicode'
    if LIBCLOUD_VERSION_INFO >= (2, 3, 0) and isinstance(u'test', str):

        kwargs.update({
            'ex_accelerator_type': config.get_cloud_config_value(
                'ex_accelerator_type', vm_, __opts__, default=None),
            'ex_accelerator_count': config.get_cloud_config_value(
                'ex_accelerator_count', vm_, __opts__, default=None)
        })
        if kwargs.get('ex_accelerator_type'):
            log.warning(
                'An accelerator is being attached to this instance, '
                'the ex_on_host_maintenance setting is being set to '
                '\'TERMINATE\' as a result'
            )
            kwargs.update({
                'ex_on_host_maintenance': 'TERMINATE'
            })

    log.info(
        'Creating GCE instance %s in %s',
        vm_['name'], kwargs['location'].name
    )
    log.debug('Create instance kwargs %s', kwargs)

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args=__utils__['cloud.filter_event']('requesting', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        node_data = conn.create_node(**kwargs)
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating %s on GCE\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n%s',
            vm_['name'], exc, exc_info_on_loglevel=logging.DEBUG
        )
        return False

    volumes = config.get_cloud_config_value(
        'volumes', vm_, __opts__, search_global=True
    )

    if volumes:
        __utils__['cloud.fire_event'](
            'event',
            'attaching volumes',
            'salt/cloud/{0}/attaching_volumes'.format(vm_['name']),
            args={'volumes': volumes},
            sock_dir=__opts__['sock_dir'],
            transport=__opts__['transport']
        )

        log.info('Create and attach volumes to node %s', vm_['name'])
        create_attach_volumes(
            vm_['name'],
            {
                'volumes': volumes,
                'node': node_data
            },
            call='action'
        )

    try:
        node_dict = show_instance(node_data['name'], 'action')
    except TypeError:
        # node_data is a libcloud Node which is unsubscriptable
        node_dict = show_instance(node_data.name, 'action')

    return node_dict, node_data