Create a single VM from a data dict

def create(vm_):
    '''
    Create a single VM from a data dict
    '''
    deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
    key_filename = config.get_cloud_config_value(
        'ssh_key_file', vm_, __opts__, search_global=False, default=None
    )
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined ssh_key_file \'{0}\' does not exist'.format(
                key_filename
            )
        )

    vm_['key_filename'] = key_filename

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        '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()

    if 'instance_id' in vm_:
        # This was probably created via another process, and doesn't have
        # things like salt keys created yet, so let's create them now.
        if 'pub_key' not in vm_ and 'priv_key' not in vm_:
            log.debug('Generating minion keys for \'%s\'', vm_['name'])
            vm_['priv_key'], vm_['pub_key'] = __utils__['cloud.gen_keys'](
                config.get_cloud_config_value(
                    'keysize',
                    vm_,
                    __opts__
                )
            )
    else:
        # Put together all of the information required to request the instance,
        # and then fire off the request for it
        request_instance(conn=conn, call='action', vm_=vm_)
    data = show_instance(vm_.get('instance_id', vm_['name']), conn=conn, call='action')
    log.debug('VM is now running')

    def __query_node(vm_):
        data = show_instance(vm_['name'], conn=conn, call='action')
        if 'wait_for_metadata' in vm_:
            for key, value in six.iteritems(vm_.get('wait_for_metadata', {})):
                log.debug('Waiting for metadata: %s=%s', key, value)
                if data['metadata'].get(key, None) != value:
                    log.debug('Metadata is not ready: %s=%s', key, data['metadata'].get(key))
                    return False
        return preferred_ip(vm_, data[ssh_interface(vm_)])
    try:
        ip_address = __utils__['cloud.wait_for_fun'](
            __query_node,
            vm_=vm_
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(six.text_type(exc))
    log.debug('Using IP address %s', ip_address)

    salt_interface = __utils__['cloud.get_salt_interface'](vm_, __opts__)
    salt_ip_address = preferred_ip(vm_, data[salt_interface])
    log.debug('Salt interface set to: %s', salt_ip_address)

    if not ip_address:
        raise SaltCloudSystemExit('A valid IP address was not found')

    vm_['ssh_host'] = ip_address
    vm_['salt_host'] = salt_ip_address

    ret = __utils__['cloud.bootstrap'](vm_, __opts__)
    ret.update(data)

    log.info('Created Cloud VM \'%s\'', vm_['name'])
    log.debug(
        '\'%s\' VM creation details:\n%s',
        vm_['name'], pprint.pformat(data)
    )

    event_data = {
        'name': vm_['name'],
        'profile': vm_['profile'],
        'provider': vm_['driver'],
        'instance_id': data['id'],
        'floating_ips': data['floating_ips'],
        'fixed_ips': data['fixed_ips'],
        'private_ips': data['private_ips'],
        'public_ips': data['public_ips'],
    }

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args=__utils__['cloud.filter_event']('created', event_data, list(event_data)),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )
    __utils__['cloud.cachedir_index_add'](vm_['name'], vm_['profile'], 'nova', vm_['driver'])
    return ret