def validate_resource_attributes(resource, attributes, template, check_unit
    =True, exact_match=False):
    """
        Validate that the resource provided matches the template.
        Only passes if the resource contains ONLY the attributes specified
        in the template.

        The template should take the form of a dictionary, as should the
        resources.

        *check_unit*:  Make sure that if a unit is specified in the template, it
                     is the same in the data
        *exact_match*: Enure that all the attributes in the template are in
                     the data also. By default this is false, meaning a subset
                     of the template attributes may be specified in the data.
                     An attribute specified in the data *must* be defined in
                     the template.

        @returns a list of error messages. An empty list indicates no
        errors were found.
    """
    errors = []
    res_type = 'GROUP'
    if resource.get('x') is not None:
        res_type = 'NODE'
    elif resource.get('node_1_id') is not None:
        res_type = 'LINK'
    elif resource.get('nodes') is not None:
        res_type = 'NETWORK'
    tmpl_res = template['resources'][res_type]
    res_user_type = resource.get('type')
    if res_user_type is None:
        errors.append('No type specified on resource %s' % resource['name'])
    elif tmpl_res.get(res_user_type) is None:
        errors.append(
            'Resource %s is defined as having type %s but this type is not specified in the template.'
             % (resource['name'], res_user_type))
    tmpl_attrs = tmpl_res.get(res_user_type)['attributes']
    attrs = {}
    for a in attributes.values():
        attrs[a['id']] = a
    for a in tmpl_attrs.values():
        if a.get('id') is not None:
            attrs[a['id']] = {'name': a['name'], 'unit': a.get('unit'),
                'dimen': a.get('dimension')}
    if exact_match is True:
        tmpl_attr_names = set(tmpl_attrs.keys())
        resource_attr_names = []
        for ra in resource['attributes']:
            attr_name = attrs[ra['attr_id']]['name']
            resource_attr_names.append(attr_name)
        resource_attr_names = set(resource_attr_names)
        in_tmpl_not_in_resource = tmpl_attr_names - resource_attr_names
        in_resource_not_in_tmpl = resource_attr_names - tmpl_attr_names
        if len(in_tmpl_not_in_resource) > 0:
            errors.append(
                'Template has defined attributes %s for type %s but they are not specified in the Data.'
                 % (','.join(in_tmpl_not_in_resource), res_user_type))
        if len(in_resource_not_in_tmpl) > 0:
            errors.append(
                'Resource %s (type %s) has defined attributes %s but this is not specified in the Template.'
                 % (resource['name'], res_user_type, ','.join(
                in_resource_not_in_tmpl)))
    for res_attr in resource['attributes']:
        attr = attrs.get(res_attr['attr_id'])
        if attr is None:
            errors.append(
                'An attribute mismatch has occurred. Attr %s is not defined in the data but is present on resource %s'
                 % (res_attr['attr_id'], resource['name']))
            continue
        if tmpl_attrs.get(attr['name']) is None:
            errors.append(
                'Resource %s has defined attribute %s but this is not specified in the Template.'
                 % (resource['name'], attr['name']))
        else:
            tmpl_attr = tmpl_attrs[attr['name']]
            if tmpl_attr.get('data_type') is not None:
                if res_attr.get('type') is not None:
                    if tmpl_attr.get('data_type') != res_attr.get('type'):
                        errors.append(
                            'Error in data. Template says that %s on %s is a %s, but data suggests it is a %s'
                             % (attr['name'], resource['name'], tmpl_attr.
                            get('data_type'), res_attr.get('type')))
            attr_dimension = 'dimensionless' if attr.get('dimension'
                ) is None else attr.get('dimension')
            tmpl_attr_dimension = 'dimensionless' if tmpl_attr.get('dimension'
                ) is None else tmpl_attr.get('dimension')
            if attr_dimension.lower() != tmpl_attr_dimension.lower():
                errors.append(
                    'Dimension mismatch on resource %s for attribute %s (template says %s on type %s, data says %s)'
                     % (resource['name'], attr.get('name'), tmpl_attr.get(
                    'dimension'), res_user_type, attr_dimension))
            if check_unit is True:
                if tmpl_attr.get('unit') is not None:
                    if attr.get('unit') != tmpl_attr.get('unit'):
                        errors.append(
                            'Unit mismatch for resource %s with unit %s (template says %s for type %s)'
                             % (resource['name'], attr.get('unit'),
                            tmpl_attr.get('unit'), res_user_type))
    return errors
