Create a single Linode VM.

def create(vm_):
    '''
    Create a single Linode VM.
    '''
    name = vm_['name']
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'linode',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    if _validate_name(name) is False:
        return False

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

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

    data = {}
    kwargs = {'name': name}

    plan_id = None
    size = vm_.get('size')
    if size:
        kwargs['size'] = size
        plan_id = get_plan_id(kwargs={'label': size})

    datacenter_id = None
    location = vm_.get('location')
    if location:
        try:
            datacenter_id = get_datacenter_id(location)
        except KeyError:
            # Linode's default datacenter is Dallas, but we still have to set one to
            # use the create function from Linode's API. Dallas's datacenter id is 2.
            datacenter_id = 2

    clonefrom_name = vm_.get('clonefrom')
    cloning = True if clonefrom_name else False
    if cloning:
        linode_id = get_linode_id_from_name(clonefrom_name)
        clone_source = get_linode(kwargs={'linode_id': linode_id})

        kwargs = {
            'clonefrom': clonefrom_name,
            'image': 'Clone of {0}'.format(clonefrom_name),
        }

        if size is None:
            size = clone_source['TOTALRAM']
            kwargs['size'] = size
            plan_id = clone_source['PLANID']

        if location is None:
            datacenter_id = clone_source['DATACENTERID']

        # Create new Linode from cloned Linode
        try:
            result = clone(kwargs={'linode_id': linode_id,
                                   'datacenter_id': datacenter_id,
                                   'plan_id': plan_id})
        except Exception as err:
            log.error(
                'Error cloning \'%s\' on Linode.\n\n'
                'The following exception was thrown by Linode when trying to '
                'clone the specified machine:\n%s',
                clonefrom_name, err, exc_info_on_loglevel=logging.DEBUG
            )
            return False
    else:
        kwargs['image'] = vm_['image']

        # Create Linode
        try:
            result = _query('linode', 'create', args={
                'PLANID': plan_id,
                'DATACENTERID': datacenter_id
            })
        except Exception as err:
            log.error(
                'Error creating %s on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'run the initial deployment:\n%s',
                name, err, exc_info_on_loglevel=logging.DEBUG
            )
            return False

    if 'ERRORARRAY' in result:
        for error_data in result['ERRORARRAY']:
            log.error(
                'Error creating %s on Linode\n\n'
                'The Linode API returned the following: %s\n',
                name, error_data['ERRORMESSAGE']
            )
            return False

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

    node_id = _clean_data(result)['LinodeID']
    data['id'] = node_id

    if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))):
        log.error(
            'Error creating %s on LINODE\n\n'
            'while waiting for initial ready status',
            name, exc_info_on_loglevel=logging.DEBUG
        )

    # Update the Linode's Label to reflect the given VM name
    update_linode(node_id, update_args={'Label': name})
    log.debug('Set name for %s - was linode%s.', name, node_id)

    # Add private IP address if requested
    private_ip_assignment = get_private_ip(vm_)
    if private_ip_assignment:
        create_private_ip(node_id)

    # Define which ssh_interface to use
    ssh_interface = _get_ssh_interface(vm_)

    # If ssh_interface is set to use private_ips, but assign_private_ip
    # wasn't set to True, let's help out and create a private ip.
    if ssh_interface == 'private_ips' and private_ip_assignment is False:
        create_private_ip(node_id)
        private_ip_assignment = True

    if cloning:
        config_id = get_config_id(kwargs={'linode_id': node_id})['config_id']
    else:
        # Create disks and get ids
        log.debug('Creating disks for %s', name)
        root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID']
        swap_disk_id = create_swap_disk(vm_, node_id)['DiskID']

        # Create a ConfigID using disk ids
        config_id = create_config(kwargs={'name': name,
                                          'linode_id': node_id,
                                          'root_disk_id': root_disk_id,
                                          'swap_disk_id': swap_disk_id})['ConfigID']

    # Boot the Linode
    boot(kwargs={'linode_id': node_id,
                 'config_id': config_id,
                 'check_running': False})

    node_data = get_linode(kwargs={'linode_id': node_id})
    ips = get_ips(node_id)
    state = int(node_data['STATUS'])

    data['image'] = kwargs['image']
    data['name'] = name
    data['size'] = size
    data['state'] = _get_status_descr_by_id(state)
    data['private_ips'] = ips['private_ips']
    data['public_ips'] = ips['public_ips']

    # Pass the correct IP address to the bootstrap ssh_host key
    if ssh_interface == 'private_ips':
        vm_['ssh_host'] = data['private_ips'][0]
    else:
        vm_['ssh_host'] = data['public_ips'][0]

    # If a password wasn't supplied in the profile or provider config, set it now.
    vm_['password'] = get_password(vm_)

    # Make public_ips and private_ips available to the bootstrap script.
    vm_['public_ips'] = ips['public_ips']
    vm_['private_ips'] = ips['private_ips']

    # Send event that the instance has booted.
    __utils__['cloud.fire_event'](
        'event',
        'waiting for ssh',
        'salt/cloud/{0}/waiting_for_ssh'.format(name),
        sock_dir=__opts__['sock_dir'],
        args={'ip_address': vm_['ssh_host']},
        transport=__opts__['transport']
    )

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

    ret.update(data)

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

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

    return ret