def __init__(self): self._categories = OrderedDict() self._locations = {} # Always register OCCI Core types self.register(EntityKind) self.register(ResourceKind) self.register(LinkKind)
class Category(object): """The OCCI Category type.""" class CategoryError(Exception): pass class Invalid(CategoryError): pass class DoesNotExist(CategoryError): pass def __init__(self, term, scheme, title=None, related=None, attributes=None, defaults=None): self.term = term self.scheme = scheme self.title = title self.related = related self.attributes = OrderedDict() self.unique_attributes = OrderedDict() self.defaults = defaults or OrderedDict() # Attribute definitions if related: self.attributes = related.attributes.copy() for attr in attributes or (): self.unique_attributes[attr.name] = attr self.attributes.update(self.unique_attributes) # Attribute defaults def __repr__(self): return "%s('%s', '%s')" % (self.__class__.__name__, self.term, self.scheme) def __str__(self): return self.scheme + self.term def __cmp__(self, other): return cmp(str(self), str(other)) def is_related(self, category): current = self while current: if category == current: return True current = current.related return False
def __init__(self, term, scheme, title=None, related=None, attributes=None, defaults=None): self.term = term self.scheme = scheme self.title = title self.related = related self.attributes = OrderedDict() self.unique_attributes = OrderedDict() self.defaults = defaults or OrderedDict() # Attribute definitions if related: self.attributes = related.attributes.copy() for attr in attributes or (): self.unique_attributes[attr.name] = attr self.attributes.update(self.unique_attributes)
def _json_obj(self, obj): """Render a `DataObject` into a JSON-friendly dictionary structure. """ json_obj = OrderedDict() json_obj['kind'] = None json_obj['kinds'] = [] json_obj['mixins'] = [] json_obj['categories'] = [] json_obj['actions'] = [] json_obj['links'] = [] json_obj['attributes'] = OrderedDict() # Categories for category in obj.categories: d = OrderedDict() d['term'] = category.term d['scheme'] = category.scheme d['title'] = category.title if category.related: d['related'] = str(category.related) if category.attributes: attr_defs = OrderedDict() for attr in category.unique_attributes.itervalues(): attr_props = OrderedDict() attr_props['mutable'] = attr.mutable attr_props['required'] = attr.required attr_props['type'] = attr.type_name attr_defs[attr.name] = attr_props d['attributes'] = attr_defs if category.defaults: d['defaults'] = category.defaults if hasattr(category, 'actions') and category.actions: d['actions'] = [str(cat) for cat in category.actions] if hasattr(category, 'location') and category.location: d['location'] = obj.translator.url_build(category.location, path_only=True) cat_class = category.__class__.__name__.lower() if cat_class == 'kind': json_obj['kinds'].append(d) elif cat_class == 'mixin': json_obj['mixins'].append(d) else: json_obj['categories'].append(d) # Links for link in obj.links: d = OrderedDict() if link.target_title: d['title'] = link.target_title d['target_uri'] = link.target_location d['target_type'] = [str(cat) for cat in link.target_categories] if link.link_location: d['link_uri'] = link.link_location if link.link_categories: d['link_type'] = [str(cat) for cat in link.link_categories] if link.link_attributes: attrs = OrderedDict() for name, value in link.link_attributes: attrs[name] = value d['attributes'] = attrs json_obj['links'].append(d) # Actions for action in obj.actions: d = OrderedDict() if action.target_title: d['title'] = action.target_title d['uri'] = action.target_location assert (len(action.target_categories) == 1) d['type'] = str(action.target_categories[0]) json_obj['actions'].append(d) # Attributes for name, value in obj.attributes: json_obj['attributes'][name] = value # If this is a resource instance ... if 'resource_instance' in obj.render_flags: try: json_obj['kind'] = json_obj['kinds'][0] del json_obj['kinds'] except KeyError, IndexError: raise RendererError( 'Resource instance MUST be of one and only one Kind')
class CategoryRegistry(object): """Registry of all Category/Kind/Mixin instances currently known to the OCCI server or client. >>> reg = CategoryRegistry() >>> from occi.core import Category, ExtCategory, Kind, Mixin >>> from occi.ext.infrastructure import * >>> reg.register(ComputeKind) >>> reg.register(StorageKind) >>> reg.register(StorageLinkKind) >>> fooKind = Kind('foo', 'http://#', related=ResourceKind, location='compute/') >>> reg.register(fooKind) Traceback (most recent call last): Invalid: compute/: location path already defined >>> reg.lookup_id(ComputeKind) Kind('compute', 'http://schemas.ogf.org/occi/infrastructure#') >>> reg.lookup_location('storage/') Kind('storage', 'http://schemas.ogf.org/occi/infrastructure#') >>> reg.lookup_recursive('/link/') [Kind('storagelink', 'http://schemas.ogf.org/occi/infrastructure#')] >>> reg.lookup_recursive('/') == reg.all() True >>> reg.unregister(StorageKind) >>> reg.unregister(ComputeKind) >>> reg.unregister(EntityKind) ; reg.unregister(ResourceKind) ; reg.unregister(LinkKind) >>> reg.all() [Kind('storagelink', 'http://schemas.ogf.org/occi/infrastructure#')] """ def __init__(self): self._categories = OrderedDict() self._locations = {} # Always register OCCI Core types self.register(EntityKind) self.register(ResourceKind) self.register(LinkKind) def register(self, category): """Register a new Category/Kind/Mixin.""" s = str(category) if s in self._categories: raise Category.Invalid('%s: Category already registered' % s) # Location if hasattr(category, 'location') and category.location: if category.location in self._locations: raise Category.Invalid('%s: location path already defined' % category.location) self._locations[category.location] = category # Register category self._categories[s] = category # Register actions if hasattr(category, 'actions'): for action in category.actions: if hasattr(action, 'actions'): raise Category.Invalid( '%s: Only the base Category type allowed to identify Actions' % action) self.register(action) def unregister(self, category): """Unregister a previously registered Category/Kind/Mixin.""" try: category = self._categories[str(category)] except KeyError: raise Category.Invalid("%s: Category not registered" % category) # Unregister category del self._categories[str(category)] # Remove location entry if hasattr(category, 'location') and category.location: self._locations.pop(category.location, None) # Remove additional action categories if hasattr(category, 'actions'): for action in category.actions: self.unregister(action) def lookup_id(self, identifier): try: return self._categories[str(identifier)] except KeyError: raise Category.DoesNotExist('"%s": Category does not exist' % identifier) def lookup_location(self, path): loc = path.lstrip('/') return self._locations.get(loc) def lookup_recursive(self, path): """Find all categories registered at a location below the specified path. """ loc = path.lstrip('/') if not loc: return self.all() categories = [] for location, category in self._locations.iteritems(): if location.startswith(loc): categories.append(category) return categories def all(self): return self._categories.values()
def __init__(self): super(DummyBackend, self).__init__() self._db = OrderedDict() self._user_mixins = {}
class DummyBackend(ServerBackend): """Very simple (and inefficient) in-memory backend for test purposes. >>> backend = DummyBackend() >>> from occi.ext.infrastructure import * >>> t = backend.save_entities([ComputeKind.entity_type(ComputeKind)]) >>> compute = ComputeKind.entity_type(ComputeKind) >>> compute.occi_import_attributes([('occi.compute.memory', '2.0')]) >>> storage = StorageKind.entity_type(StorageKind) >>> s_compute, s_storage = backend.save_entities([compute, storage]) >>> link = StorageLinkKind.entity_type(StorageLinkKind) >>> link.occi_import_attributes([('occi.core.source', s_compute.id), ('occi.core.target', s_storage.id), ('occi.storagelink.deviceid', 'ide:0:0')]) >>> s_link = backend.save_entities([link]) >>> len(backend.filter_entities()) 4 >>> len(backend.filter_entities(categories=[ComputeKind])) 2 >>> len(backend.filter_entities(categories=[ComputeKind], attributes=[('occi.compute.memory', 2.0)])) 1 >>> backend.get_entity(s_compute.id) == compute True >>> backend.save_entities(delete_entity_ids=[entity.id for entity in t]) [] >>> [entity.id for entity in backend.filter_entities(categories=[ComputeKind])] == [s_compute.id] True """ def __init__(self): super(DummyBackend, self).__init__() self._db = OrderedDict() self._user_mixins = {} def auth_user(self, identity, secret=None, method=None, user=None): return None def get_entity(self, entity_id, user=None): entity_id = str(entity_id) try: return self._db[entity_id] except KeyError: raise Entity.DoesNotExist(entity_id) def filter_entities(self, categories=None, attributes=None, user=None): result = [] for entity_id, entity in self._db.iteritems(): skip = False # Filter on Categories cats = entity.occi_list_categories() for cat in categories or (): if str(cat) not in cats: skip = True break if skip: continue # Filter on Attributes if categories and attributes: for name, value in attributes: t = entity.occi_get_attribute(name) if str(t) != str( value): # FIXME - this implies "2.0" == 2.0 skip = True break if skip: continue result.append(entity) return result def save_entities(self, entities=None, delete_entity_ids=None, user=None): if delete_entity_ids: self._delete_entities(delete_entity_ids, user=user) saved_entities = [] for entity in entities or (): # Generate ID if new instance if not entity.id: entity.occi_set_attribute('occi.core.id', uuid.uuid4()) # Links if isinstance(entity, Link): source = self.get_entity( entity.occi_get_attribute('occi.core.source').id, user=user) target = self.get_entity( entity.occi_get_attribute('occi.core.target').id, user=user) entity.occi_set_attribute('occi.core.source', source) entity.occi_set_attribute('occi.core.target', target) links = [] for l in source.links: if l.id != source.id: links.append(l) links.append(entity) source.links = links self._db[str(entity.id)] = entity saved_entities.append(entity) return saved_entities def _delete_entities(self, entity_ids, user=None): for entity_id in entity_ids: entity_id = str(entity_id) try: entity = self._db[entity_id] if isinstance(entity, Resource): for l in entity.links: self._db.pop(l.id, None) elif isinstance(entity, Link): try: entity.source.links.remove(entity) except ValueError: pass del self._db[entity_id] except KeyError: raise Entity.DoesNotExist(entity_id) def exec_action(self, action, entity, payload=None, user=None): try: return getattr(entity, 'exec_action')(action, payload=payload) except AttributeError: return None def exec_action_on_collection(self, action, collection, payload=None, user=None): # FIXME: make atomic for entity in self.filter_entities(categories=[collection], user=user): self.exec_action(action, entity, payload=payload, user=user) return None def add_user_category(self, category, user=None): if not isinstance(category, Mixin): raise self.InvalidOperation('Permission denied') self._user_mixins[str(category)] = category return category def remove_user_category(self, category, user=None): try: del self._user_mixins[str(category)] except KeyError: raise self.InvalidOperation('Permission denied')
class DummyBackend(ServerBackend): """Very simple (and inefficient) in-memory backend for test purposes. >>> backend = DummyBackend() >>> from occi.ext.infrastructure import * >>> t = backend.save_entities([ComputeKind.entity_type(ComputeKind)]) >>> compute = ComputeKind.entity_type(ComputeKind) >>> compute.occi_import_attributes([('occi.compute.memory', '2.0')]) >>> storage = StorageKind.entity_type(StorageKind) >>> s_compute, s_storage = backend.save_entities([compute, storage]) >>> link = StorageLinkKind.entity_type(StorageLinkKind) >>> link.occi_import_attributes([('occi.core.source', s_compute.id), ('occi.core.target', s_storage.id), ('occi.storagelink.deviceid', 'ide:0:0')]) >>> s_link = backend.save_entities([link]) >>> len(backend.filter_entities()) 4 >>> len(backend.filter_entities(categories=[ComputeKind])) 2 >>> len(backend.filter_entities(categories=[ComputeKind], attributes=[('occi.compute.memory', 2.0)])) 1 >>> backend.get_entity(s_compute.id) == compute True >>> backend.save_entities(delete_entity_ids=[entity.id for entity in t]) [] >>> [entity.id for entity in backend.filter_entities(categories=[ComputeKind])] == [s_compute.id] True """ def __init__(self): super(DummyBackend, self).__init__() self._db = OrderedDict() self._user_mixins = {} def auth_user(self, identity, secret=None, method=None, user=None): return None def get_entity(self, entity_id, user=None): entity_id = str(entity_id) try: return self._db[entity_id] except KeyError: raise Entity.DoesNotExist(entity_id) def filter_entities(self, categories=None, attributes=None, user=None): result = [] for entity_id, entity in self._db.iteritems(): skip = False # Filter on Categories cats = entity.occi_list_categories() for cat in categories or (): if str(cat) not in cats: skip=True break if skip: continue # Filter on Attributes if categories and attributes: for name, value in attributes: t = entity.occi_get_attribute(name) if str(t) != str(value): # FIXME - this implies "2.0" == 2.0 skip = True break if skip: continue result.append(entity) return result def save_entities(self, entities=None, delete_entity_ids=None, user=None): if delete_entity_ids: self._delete_entities(delete_entity_ids, user=user) saved_entities = [] for entity in entities or (): # Generate ID if new instance if not entity.id: entity.occi_set_attribute('occi.core.id', uuid.uuid4()) # Links if isinstance(entity, Link): source = self.get_entity(entity.occi_get_attribute('occi.core.source').id, user=user) target = self.get_entity(entity.occi_get_attribute('occi.core.target').id, user=user) entity.occi_set_attribute('occi.core.source', source) entity.occi_set_attribute('occi.core.target', target) links = [] for l in source.links: if l.id != source.id: links.append(l) links.append(entity) source.links = links self._db[str(entity.id)] = entity saved_entities.append(entity) return saved_entities def _delete_entities(self, entity_ids, user=None): for entity_id in entity_ids: entity_id = str(entity_id) try: entity = self._db[entity_id] if isinstance(entity, Resource): for l in entity.links: self._db.pop(l.id, None) elif isinstance(entity, Link): try: entity.source.links.remove(entity) except ValueError: pass del self._db[entity_id] except KeyError: raise Entity.DoesNotExist(entity_id) def exec_action(self, action, entity, payload=None, user=None): try: return getattr(entity, 'exec_action')(action, payload=payload) except AttributeError: return None def exec_action_on_collection(self, action, collection, payload=None, user=None): # FIXME: make atomic for entity in self.filter_entities(categories=[collection], user=user): self.exec_action(action, entity, payload=payload, user=user) return None def add_user_category(self, category, user=None): if not isinstance(category, Mixin): raise self.InvalidOperation('Permission denied') self._user_mixins[str(category)] = category return category def remove_user_category(self, category, user=None): try: del self._user_mixins[str(category)] except KeyError: raise self.InvalidOperation('Permission denied')