'Extend resources with additional resources or attributes.
:param attr_map: the existing mapping from resource name to
attrs definition.
After this function, we will extend the attr_map if an extension
wants to extend this map.'

def extend_resources(self, version, attr_map):

    processed_exts = {}
    exts_to_process = self.extensions.copy()
    check_optionals = True
    while exts_to_process:
        processed_ext_count = len(processed_exts)
        for (ext_name, ext) in list(exts_to_process.items()):
            required_exts_set = set(ext.get_required_extensions())
            if (required_exts_set - set(processed_exts)):
                continue
            optional_exts_set = set(ext.get_optional_extensions())
            if (check_optionals and (optional_exts_set - set(processed_exts))):
                continue
            extended_attrs = ext.get_extended_resources(version)
            for (res, resource_attrs) in extended_attrs.items():
                attr_map.setdefault(res, {}).update(resource_attrs)
            processed_exts[ext_name] = ext
            del exts_to_process[ext_name]
        if (len(processed_exts) == processed_ext_count):
            if check_optionals:
                check_optionals = False
                continue
            break
    if exts_to_process:
        unloadable_extensions = set(exts_to_process.keys())
        LOG.error(_LE('Unable    to    process    extensions    (%s)    because    the    configured    plugins    do    not    satisfy    their    requirements.    Some    features    will    not    work    as    expected.'), ',    '.join(unloadable_extensions))
        self._check_faulty_extensions(unloadable_extensions)
    for ext in processed_exts.values():
        ext.update_attributes_map(attr_map)
