Compares configured endpoints with the expected configuration and returns the differences.

def _compute_diff(expected_endpoints, configured_endpoints):
    '''
    Compares configured endpoints with the expected configuration and returns the differences.
    '''
    new_endpoints = []
    update_endpoints = []
    remove_endpoints = []

    ret = _compute_diff_ret()

    # noth configured => configure with expected endpoints
    if not configured_endpoints:
        ret.update({
            'add': expected_endpoints
        })
        return ret

    # noting expected => remove everything
    if not expected_endpoints:
        ret.update({
            'remove': configured_endpoints
        })
        return ret

    expected_endpoints_clear = _clear_ignore_list(expected_endpoints)
    configured_endpoints_clear = _clear_ignore_list(configured_endpoints)

    for expected_endpoint_clear in expected_endpoints_clear:
        if expected_endpoint_clear not in configured_endpoints_clear:
            # none equal => add or update
            matching_ele = _find_match(expected_endpoint_clear, configured_endpoints_clear)
            if not matching_ele:
                # new element => add
                new_endpoints.append(expected_endpoint_clear)
            else:
                # element matched, but some fields are different
                update_fields = _update_on_fields(matching_ele, expected_endpoint_clear)
                if update_fields:
                    update_endpoints.append(update_fields)
    for configured_endpoint_clear in configured_endpoints_clear:
        if configured_endpoint_clear not in expected_endpoints_clear:
            matching_ele = _find_match(configured_endpoint_clear, expected_endpoints_clear)
            if not matching_ele:
                #  no match found => remove
                remove_endpoints.append(configured_endpoint_clear)

    return {
        'add': new_endpoints,
        'update': update_endpoints,
        'remove': remove_endpoints
    }