Verify that the raid is present

    .. versionchanged:: 2014.7.0

    name
        The name of raid device to be created

    level
                The RAID level to use when creating the raid.

    devices
        A list of devices used to build the array.

    kwargs
        Optional arguments to be passed to mdadm.

    Example:

    .. code-block:: yaml

        /dev/md0:
          raid.present:
            - level: 5
            - devices:
              - /dev/xvdd
              - /dev/xvde
              - /dev/xvdf
            - chunk: 256
            - run: True

def present(name,
            level,
            devices,
            **kwargs):
    '''
    Verify that the raid is present

    .. versionchanged:: 2014.7.0

    name
        The name of raid device to be created

    level
                The RAID level to use when creating the raid.

    devices
        A list of devices used to build the array.

    kwargs
        Optional arguments to be passed to mdadm.

    Example:

    .. code-block:: yaml

        /dev/md0:
          raid.present:
            - level: 5
            - devices:
              - /dev/xvdd
              - /dev/xvde
              - /dev/xvdf
            - chunk: 256
            - run: True
    '''
    ret = {'changes': {},
           'comment': '',
           'name': name,
           'result': True}

    # Device exists
    raids = __salt__['raid.list']()
    present = raids.get(name)

    # Decide whether to create or assemble
    missing = []
    uuid_dict = {}
    new_devices = []

    for dev in devices:
        if dev == 'missing' or not __salt__['file.access'](dev, 'f'):
            missing.append(dev)
            continue
        superblock = __salt__['raid.examine'](dev, quiet=True)

        if 'MD_UUID' in superblock:
            uuid = superblock['MD_UUID']
            if uuid not in uuid_dict:
                uuid_dict[uuid] = []
            uuid_dict[uuid].append(dev)
        else:
            new_devices.append(dev)

    if len(uuid_dict) > 1:
        ret['comment'] = 'Devices are a mix of RAID constituents with multiple MD_UUIDs: {0}.'.format(
                         sorted(uuid_dict.keys()))
        ret['result'] = False
        return ret
    elif len(uuid_dict) == 1:
        uuid = list(uuid_dict.keys())[0]
        if present and present['uuid'] != uuid:
            ret['comment'] = 'Devices MD_UUIDs: {0} differs from present RAID uuid {1}.'.format(uuid, present['uuid'])
            ret['result'] = False
            return ret

        devices_with_superblock = uuid_dict[uuid]
    else:
        devices_with_superblock = []

    if present:
        do_assemble = False
        do_create = False
    elif devices_with_superblock:
        do_assemble = True
        do_create = False
        verb = 'assembled'
    else:
        if not new_devices:
            ret['comment'] = 'All devices are missing: {0}.'.format(missing)
            ret['result'] = False
            return ret
        do_assemble = False
        do_create = True
        verb = 'created'

    # If running with test use the test_mode with create or assemble
    if __opts__['test']:
        if do_assemble:
            res = __salt__['raid.assemble'](name,
                                            devices_with_superblock,
                                            test_mode=True,
                                            **kwargs)
        elif do_create:
            res = __salt__['raid.create'](name,
                                          level,
                                          new_devices + ['missing'] * len(missing),
                                          test_mode=True,
                                          **kwargs)

        if present:
            ret['comment'] = 'Raid {0} already present.'.format(name)

        if do_assemble or do_create:
            ret['comment'] = 'Raid will be {0} with: {1}'.format(verb, res)
            ret['result'] = None

        if (do_assemble or present) and new_devices:
            ret['comment'] += ' New devices will be added: {0}'.format(new_devices)
            ret['result'] = None

        if missing:
            ret['comment'] += ' Missing devices: {0}'.format(missing)

        return ret

    # Attempt to create or assemble the array
    if do_assemble:
        __salt__['raid.assemble'](name,
                                  devices_with_superblock,
                                  **kwargs)
    elif do_create:
        __salt__['raid.create'](name,
                                level,
                                new_devices + ['missing'] * len(missing),
                                **kwargs)

    if not present:
        raids = __salt__['raid.list']()
        changes = raids.get(name)
        if changes:
            ret['comment'] = 'Raid {0} {1}.'.format(name, verb)
            ret['changes'] = changes
            # Saving config
            __salt__['raid.save_config']()
        else:
            ret['comment'] = 'Raid {0} failed to be {1}.'.format(name, verb)
            ret['result'] = False
    else:
        ret['comment'] = 'Raid {0} already present.'.format(name)

    if (do_assemble or present) and new_devices and ret['result']:
        for d in new_devices:
            res = __salt__['raid.add'](name, d)
            if not res:
                ret['comment'] += ' Unable to add {0} to {1}.\n'.format(d, name)
                ret['result'] = False
            else:
                ret['comment'] += ' Added new device {0} to {1}.\n'.format(d, name)
        if ret['result']:
            ret['changes']['added'] = new_devices

    if missing:
        ret['comment'] += ' Missing devices: {0}'.format(missing)

    return ret