internal handler for filesystem_present/volume_present

    dataset_type : string
        volume or filesystem
    name : string
        name of volume
    volume_size : string
        size of volume
    sparse : boolean
        create sparse volume
    create_parent : boolean
        creates all the non-existing parent datasets.
        any property specified on the command line using the -o option is ignored.
    cloned_from : string
        name of snapshot to clone
    properties : dict
        additional zfs properties (-o)

    .. note::
        ``cloned_from`` is only use if the volume does not exist yet,
        when ``cloned_from`` is set after the volume exists it will be ignored.

    .. note::
        Properties do not get cloned, if you specify the properties in the state file
        they will be applied on a subsequent run.

        ``volume_size`` is considered a property, so the volume's size will be
        corrected when the properties get updated if it differs from the
        original volume.

        The sparse parameter is ignored when using ``cloned_from``.

def _dataset_present(dataset_type, name, volume_size=None, sparse=False, create_parent=False, properties=None, cloned_from=None):
    '''
    internal handler for filesystem_present/volume_present

    dataset_type : string
        volume or filesystem
    name : string
        name of volume
    volume_size : string
        size of volume
    sparse : boolean
        create sparse volume
    create_parent : boolean
        creates all the non-existing parent datasets.
        any property specified on the command line using the -o option is ignored.
    cloned_from : string
        name of snapshot to clone
    properties : dict
        additional zfs properties (-o)

    .. note::
        ``cloned_from`` is only use if the volume does not exist yet,
        when ``cloned_from`` is set after the volume exists it will be ignored.

    .. note::
        Properties do not get cloned, if you specify the properties in the state file
        they will be applied on a subsequent run.

        ``volume_size`` is considered a property, so the volume's size will be
        corrected when the properties get updated if it differs from the
        original volume.

        The sparse parameter is ignored when using ``cloned_from``.

    '''
    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': ''}

    ## fallback dataset_type to filesystem if out of range
    if dataset_type not in ['filesystem', 'volume']:
        dataset_type = 'filesystem'

    ## ensure properties are zfs values
    if volume_size:
        volume_size = __utils__['zfs.from_size'](volume_size)
    if properties:
        properties = __utils__['zfs.from_auto_dict'](properties)
    elif properties is None:
        properties = {}

    ## log configuration
    log.debug('zfs.%s_present::%s::config::volume_size = %s',
              dataset_type, name, volume_size)
    log.debug('zfs.%s_present::%s::config::sparse = %s',
              dataset_type, name, sparse)
    log.debug('zfs.%s_present::%s::config::create_parent = %s',
              dataset_type, name, create_parent)
    log.debug('zfs.%s_present::%s::config::cloned_from = %s',
              dataset_type, name, cloned_from)
    log.debug('zfs.%s_present::%s::config::properties = %s',
              dataset_type, name, properties)

    ## check we have valid filesystem name/volume name/clone snapshot
    if not __utils__['zfs.is_dataset'](name):
        ret['result'] = False
        ret['comment'] = 'invalid dataset name: {0}'.format(name)
        return ret

    if cloned_from and not __utils__['zfs.is_snapshot'](cloned_from):
        ret['result'] = False
        ret['comment'] = '{0} is not a snapshot'.format(cloned_from)
        return ret

    ## ensure dataset is in correct state
    ## NOTE: update the dataset
    if __salt__['zfs.exists'](name, **{'type': dataset_type}):
        ## NOTE: fetch current volume properties
        properties_current = __salt__['zfs.get'](
            name,
            type=dataset_type,
            fields='value',
            depth=0,
            parsable=True,
        ).get(name, OrderedDict())

        ## NOTE: add volsize to properties
        if volume_size:
            properties['volsize'] = volume_size

        ## NOTE: build list of properties to update
        properties_update = []
        for prop in properties:
            ## NOTE: skip unexisting properties
            if prop not in properties_current:
                log.warning('zfs.%s_present::%s::update - unknown property: %s',
                    dataset_type, name, prop)
                continue

            ## NOTE: compare current and wanted value
            if properties_current[prop]['value'] != properties[prop]:
                properties_update.append(prop)

        ## NOTE: update pool properties
        for prop in properties_update:
            if not __opts__['test']:
                mod_res = __salt__['zfs.set'](name, **{prop: properties[prop]})
            else:
                mod_res = OrderedDict([('set', True)])

            if mod_res['set']:
                if name not in ret['changes']:
                    ret['changes'][name] = {}
                ret['changes'][name][prop] = properties[prop]
            else:
                ret['result'] = False
                if ret['comment'] == '':
                    ret['comment'] = 'The following properties were not updated:'
                ret['comment'] = '{0} {1}'.format(ret['comment'], prop)

        ## NOTE: update comment
        if ret['result'] and name in ret['changes']:
            ret['comment'] = '{0} {1} was updated'.format(dataset_type, name)
        elif ret['result']:
            ret['comment'] = '{0} {1} is uptodate'.format(dataset_type, name)
        else:
            ret['comment'] = '{0} {1} failed to be updated'.format(dataset_type, name)

    ## NOTE: create or clone the dataset
    else:
        mod_res_action = 'cloned' if cloned_from else 'created'
        if __opts__['test']:
            ## NOTE: pretend to create/clone
            mod_res = OrderedDict([
                (mod_res_action, True),
            ])
        elif cloned_from:
            ## NOTE: add volsize to properties
            if volume_size:
                properties['volsize'] = volume_size

            ## NOTE: clone the dataset
            mod_res = __salt__['zfs.clone'](cloned_from, name, **{
                'create_parent': create_parent,
                'properties': properties,
            })
        else:
            ## NOTE: create the dataset
            mod_res = __salt__['zfs.create'](name, **{
                'create_parent': create_parent,
                'properties': properties,
                'volume_size': volume_size,
                'sparse': sparse,
            })

        ret['result'] = mod_res[mod_res_action]
        if ret['result']:
            ret['changes'][name] = mod_res_action
            if properties:
                ret['changes'][name] = properties
            ret['comment'] = '{0} {1} was {2}'.format(
                dataset_type,
                name,
                mod_res_action,
            )
        else:
            ret['comment'] = 'failed to {0} {1} {2}'.format(
                mod_res_action[:-1],
                dataset_type,
                name,
            )
            if 'error' in mod_res:
                ret['comment'] = mod_res['error']

    return ret