Create a single VM from a data dict

def create(vm_):
    '''
    Create a single VM from a data dict
    '''
    if 'driver' not in vm_:
        vm_['driver'] = vm_['provider']

    private_networking = config.get_cloud_config_value(
        'enable_private_network', vm_, __opts__, search_global=False, default=False,
    )

    startup_script = config.get_cloud_config_value(
        'startup_script_id', vm_, __opts__, search_global=False, default=None,
    )

    if startup_script and str(startup_script) not in avail_scripts():
        log.error('Your Vultr account does not have a startup script with ID %s', str(startup_script))
        return False

    if private_networking is not None:
        if not isinstance(private_networking, bool):
            raise SaltCloudConfigError("'private_networking' should be a boolean value.")
    if private_networking is True:
        enable_private_network = 'yes'
    else:
        enable_private_network = 'no'

    __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']
    )

    osid = _lookup_vultrid(vm_['image'], 'avail_images', 'OSID')
    if not osid:
        log.error('Vultr does not have an image with id or name %s', vm_['image'])
        return False

    vpsplanid = _lookup_vultrid(vm_['size'], 'avail_sizes', 'VPSPLANID')
    if not vpsplanid:
        log.error('Vultr does not have a size with id or name %s', vm_['size'])
        return False

    dcid = _lookup_vultrid(vm_['location'], 'avail_locations', 'DCID')
    if not dcid:
        log.error('Vultr does not have a location with id or name %s', vm_['location'])
        return False

    kwargs = {
        'label': vm_['name'],
        'OSID': osid,
        'VPSPLANID': vpsplanid,
        'DCID': dcid,
        'hostname': vm_['name'],
        'enable_private_network': enable_private_network,
    }
    if startup_script:
        kwargs['SCRIPTID'] = startup_script

    log.info('Creating Cloud VM %s', vm_['name'])

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

    try:
        data = _query('server/create', method='POST', data=_urlencode(kwargs))
        if int(data.get('status', '200')) >= 300:
            log.error(
                'Error creating %s on Vultr\n\n'
                'Vultr API returned %s\n', vm_['name'], data
            )
            log.error('Status 412 may mean that you are requesting an\n'
                      'invalid location, image, or size.')

            __utils__['cloud.fire_event'](
                'event',
                'instance request failed',
                'salt/cloud/{0}/requesting/failed'.format(vm_['name']),
                args={'kwargs': kwargs},
                sock_dir=__opts__['sock_dir'],
                transport=__opts__['transport'],
            )
            return False
    except Exception as exc:
        log.error(
            'Error creating %s on Vultr\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment:\n%s',
            vm_['name'], exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        __utils__['cloud.fire_event'](
            'event',
            'instance request failed',
            'salt/cloud/{0}/requesting/failed'.format(vm_['name']),
            args={'kwargs': kwargs},
            sock_dir=__opts__['sock_dir'],
            transport=__opts__['transport'],
        )
        return False

    def wait_for_hostname():
        '''
        Wait for the IP address to become available
        '''
        data = show_instance(vm_['name'], call='action')
        main_ip = six.text_type(data.get('main_ip', '0'))
        if main_ip.startswith('0'):
            time.sleep(3)
            return False
        return data['main_ip']

    def wait_for_default_password():
        '''
        Wait for the IP address to become available
        '''
        data = show_instance(vm_['name'], call='action')
        # print("Waiting for default password")
        # pprint.pprint(data)
        if six.text_type(data.get('default_password', '')) == '':
            time.sleep(1)
            return False
        return data['default_password']

    def wait_for_status():
        '''
        Wait for the IP address to become available
        '''
        data = show_instance(vm_['name'], call='action')
        # print("Waiting for status normal")
        # pprint.pprint(data)
        if six.text_type(data.get('status', '')) != 'active':
            time.sleep(1)
            return False
        return data['default_password']

    def wait_for_server_state():
        '''
        Wait for the IP address to become available
        '''
        data = show_instance(vm_['name'], call='action')
        # print("Waiting for server state ok")
        # pprint.pprint(data)
        if six.text_type(data.get('server_state', '')) != 'ok':
            time.sleep(1)
            return False
        return data['default_password']

    vm_['ssh_host'] = __utils__['cloud.wait_for_fun'](
        wait_for_hostname,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    vm_['password'] = __utils__['cloud.wait_for_fun'](
        wait_for_default_password,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    __utils__['cloud.wait_for_fun'](
        wait_for_status,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    __utils__['cloud.wait_for_fun'](
        wait_for_server_state,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )

    __opts__['hard_timeout'] = config.get_cloud_config_value(
        'hard_timeout',
        get_configured_provider(),
        __opts__,
        search_global=False,
        default=None,
    )

    # Bootstrap
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(show_instance(vm_['name'], call='action'))

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

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

    return ret