Configures portgroups on a DVS.

    Creates/updates/removes portgroups in a provided DVS

    dvs
        Name of the DVS

    portgroups
        Portgroup dict representations (see module sysdocs)

def portgroups_configured(name, dvs, portgroups):
    '''
    Configures portgroups on a DVS.

    Creates/updates/removes portgroups in a provided DVS

    dvs
        Name of the DVS

    portgroups
        Portgroup dict representations (see module sysdocs)
    '''
    datacenter = _get_datacenter_name()
    log.info('Running state %s on DVS \'%s\', datacenter \'%s\'',
             name, dvs, datacenter)
    changes_required = False
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': None}
    comments = []
    changes = {}
    changes_required = False

    try:
        #TODO portroups validation
        si = __salt__['vsphere.get_service_instance_via_proxy']()
        current_pgs = __salt__['vsphere.list_dvportgroups'](
            dvs=dvs, service_instance=si)
        expected_pg_names = []
        for pg in portgroups:
            pg_name = pg['name']
            expected_pg_names.append(pg_name)
            del pg['name']
            log.info('Checking pg \'%s\'', pg_name)
            filtered_current_pgs = \
                    [p for p in current_pgs if p.get('name') == pg_name]
            if not filtered_current_pgs:
                changes_required = True
                if __opts__['test']:
                    comments.append('State {0} will create a new portgroup '
                                    '\'{1}\' in DVS \'{2}\', datacenter '
                                    '\'{3}\''.format(name, pg_name, dvs,
                                                     datacenter))
                else:
                    __salt__['vsphere.create_dvportgroup'](
                        portgroup_dict=pg, portgroup_name=pg_name, dvs=dvs,
                        service_instance=si)
                    comments.append('Created a new portgroup \'{0}\' in DVS '
                                    '\'{1}\', datacenter \'{2}\''
                                    ''.format(pg_name, dvs, datacenter))
                log.info(comments[-1])
                changes.update({pg_name: {'new': pg}})
            else:
                # Porgroup already exists. Checking the config
                log.trace('Portgroup \'%s\' found in DVS \'%s\', datacenter '
                          '\'%s\'. Checking for any updates.',
                          pg_name, dvs, datacenter)
                current_pg = filtered_current_pgs[0]
                diff_dict = _get_diff_dict(current_pg, pg)

                if diff_dict:
                    changes_required = True
                    if __opts__['test']:
                        changes_strings = \
                                _get_changes_from_diff_dict(diff_dict)
                        log.trace('changes_strings = %s', changes_strings)
                        comments.append(
                            'State {0} will update portgroup \'{1}\' in '
                            'DVS \'{2}\', datacenter \'{3}\':\n{4}'
                            ''.format(name, pg_name, dvs, datacenter,
                                      '\n'.join(['\t{0}'.format(c) for c in
                                                 changes_strings])))
                    else:
                        __salt__['vsphere.update_dvportgroup'](
                            portgroup_dict=pg, portgroup=pg_name, dvs=dvs,
                            service_instance=si)
                        comments.append('Updated portgroup \'{0}\' in DVS '
                                        '\'{1}\', datacenter \'{2}\''
                                        ''.format(pg_name, dvs, datacenter))
                    log.info(comments[-1])
                    changes.update(
                        {pg_name: {'new':
                                   _get_val2_dict_from_diff_dict(diff_dict),
                                   'old':
                                   _get_val1_dict_from_diff_dict(diff_dict)}})
        # Add the uplink portgroup to the expected pg names
        uplink_pg = __salt__['vsphere.list_uplink_dvportgroup'](
            dvs=dvs, service_instance=si)
        expected_pg_names.append(uplink_pg['name'])
        # Remove any extra portgroups
        for current_pg in current_pgs:
            if current_pg['name'] not in expected_pg_names:
                changes_required = True
                if __opts__['test']:
                    comments.append('State {0} will remove '
                                    'the portgroup \'{1}\' from DVS \'{2}\', '
                                    'datacenter \'{3}\''
                                    ''.format(name, current_pg['name'], dvs,
                                              datacenter))
                else:
                    __salt__['vsphere.remove_dvportgroup'](
                        portgroup=current_pg['name'], dvs=dvs,
                        service_instance=si)
                    comments.append('Removed the portgroup \'{0}\' from DVS '
                                    '\'{1}\', datacenter \'{2}\''
                                    ''.format(current_pg['name'], dvs,
                                              datacenter))
                log.info(comments[-1])
                changes.update({current_pg['name']:
                                {'old': current_pg}})
        __salt__['vsphere.disconnect'](si)
    except salt.exceptions.CommandExecutionError as exc:
        log.exception('Encountered error')
        if si:
            __salt__['vsphere.disconnect'](si)
        if not __opts__['test']:
            ret['result'] = False
        ret.update({'comment': exc.strerror,
                    'result': False if not __opts__['test'] else None})
        return ret
    if not changes_required:
        # We have no changes
        ret.update({'comment': ('All portgroups in DVS \'{0}\', datacenter '
                                '\'{1}\' exist and are correctly configured. '
                                'Nothing to be done.'.format(dvs, datacenter)),
                    'result': True})
    else:
        ret.update({
            'comment': '\n'.join(comments),
            'changes': changes,
            'result': None if __opts__['test'] else True,
        })
    return ret