class __impl: def __init__(self): persistent = False force_clean = False # couchdb cannot handle capital letters, apparently datastore_name = bootstrap.sys_name.lower() + "_directory" if 'directory' in CFG: directory_cfg = CFG['directory'] if 'persistent' in directory_cfg: persistent = directory_cfg['persistent'] if 'force_clean' in directory_cfg: force_clean = directory_cfg['force_clean'] if persistent: self.datastore = CouchDB_DataStore(datastore_name=datastore_name) else: self.datastore = MockDB_DataStore(datastore_name=datastore_name) if force_clean: self._delete() if not self.datastore.datastore_exists(datastore_name): self._create() self._init() def _delete(self): """ Method to delete directory. Delete occurs as side effect of deleting the underlying data store. TODO: Change this functionality in the future? """ log.debug("Deleting data store and Directory") try: self.datastore.delete_datastore() except NotFound: pass def _get_dn(self, parent, key): if parent == '/': return "/%s" % (key) else: return "%s/%s" % (parent,key) def _init(self): self._assert_existence("/", "Agents") self._assert_existence("/", "Config") self._assert_existence("/", "Containers") self._assert_existence("/", "ObjectTypes") self._assert_existence("/", "ResourceTypes") self._assert_existence("/", "ServiceInterfaces") self._assert_existence("/", "Services") def _assert_existence(self, parent, key): dn = self._get_dn(parent, key) direntry = self._safe_read(dn) if not direntry: direntry = IonObject("DirEntry", parent=parent, key=key, attributes={}) # TODO: This may fail because of concurrent create self.datastore.create(direntry, dn) def _safe_read(self, oid): try: res = self.datastore.read(oid) return res except NotFound: return None def _create(self): """ Method which will create the underlying data store and persist an empty Directory object. """ log.debug("Creating data store and Directory") self.datastore.create_datastore() # Persist empty Directory object under known name self.dir_name = bootstrap.sys_name directory_obj = IonObject('Directory', name=self.dir_name) dir_id,rev = self.datastore.create(directory_obj, 'DIR') # Persist ROOT Directory object root_obj = IonObject('DirEntry', parent='/', key="ROOT", attributes=dict(sys_name=bootstrap.sys_name)) root_id,rev = self.datastore.create(root_obj, self._get_dn(root_obj.parent, root_obj.key)) def register(self, parent, key, **kwargs): """ Add/replace an entry to directory below a parent node. Note: Does not merge the attribute values of the entry if existing """ assert parent and key, "Malformed Directory register" dn = self._get_dn(parent, key) log.debug("Directory.add(%s): %s" % (dn, kwargs)) entry_old = None direntry = self._safe_read(dn) if direntry: entry_old = direntry.attributes direntry.attributes = kwargs # TODO: This may fail because of concurrent update self.datastore.update(direntry) else: direntry = IonObject("DirEntry", parent=parent, key=key, attributes=kwargs) # TODO: This may fail because of concurrent create self.datastore.create(direntry, dn) return entry_old def lookup(self, qualified_key='/'): """ Read entry residing in directory at parent node level. """ log.debug("Reading content at path %s" % qualified_key) direntry = self._safe_read(qualified_key) return direntry.attributes if direntry else None def unregister(self, parent, key): """ Remove entry residing in directory at parent node level. """ dn = self._get_dn(parent, key) log.debug("Removing content at path %s" % dn) entry_old = None direntry = self._safe_read(dn) if direntry: entry_old = direntry.attributes self.datastore.delete(direntry) return entry_old def find_entries(self, qname='/'): if not str(qname).startswith('/'): raise BadRequest("Illegal directory node: qname=%s" % qname) delist = self.datastore.find_dir_entries(qname) return delist
class ResourceRegistryService(BaseResourceRegistryService): """ Service that manages the definition of types of resources and all cross-cutting concerns of all system resources. The resource registry uses the underlying push and pull ops of the datastore to fetch, retrieve and create resource objects. """ def on_init(self): resource_registry_name = sys_name + "_resources" resource_registry_name = resource_registry_name.lower() persistent = False force_clean = False if 'resource_registry' in self.CFG: resource_registry_cfg = self.CFG['resource_registry'] if 'persistent' in resource_registry_cfg: if resource_registry_cfg['persistent'] == True: persistent = True if 'force_clean' in resource_registry_cfg: if resource_registry_cfg['force_clean'] == True: force_clean = True if persistent: self.resource_registry = CouchDB_DataStore(datastore_name=resource_registry_name) else: self.resource_registry = MockDB_DataStore(datastore_name=resource_registry_name) if force_clean: try: self.resource_registry.delete_datastore(resource_registry_name) except NotFound: pass if not self.resource_registry.datastore_exists(resource_registry_name): self.resource_registry.create_datastore(resource_registry_name) # For easier interactive debugging self.dss = self.resource_registry.server[resource_registry_name] if persistent else None self.ds = self.resource_registry def create(self, object={}): cur_time = get_ion_ts() object.ts_created = cur_time object.ts_updated = cur_time return self.resource_registry.create(object) def read(self, object_id='', rev_id=''): return self.resource_registry.read(object_id, rev_id) def update(self, object={}): # Do an check whether LCS has been modified res_obj = self.read(object._id, object._rev) self.assert_condition(res_obj.lcstate == object.lcstate, "Cannot modify life cycle state in update!") object.ts_updated = get_ion_ts() return self.resource_registry.update(object) def delete(self, object_id=''): res_obj = self.read(object_id) if not res_obj: raise NotFound("Resource %s does not exist" % object_id) return self.resource_registry.delete(res_obj) def execute_lifecycle_transition(self, resource_id='', transition_event='', current_lcstate=''): self.assert_condition(not current_lcstate or current_lcstate in LCS, "Unknown life-cycle state %s" % current_lcstate) res_obj = self.read(resource_id) if current_lcstate and res_obj.lcstate != current_lcstate: raise Inconsistent("Resource id=%s lcstate is %s, expected was %s" % ( resource_id, res_obj.lcstate, current_lcstate)) restype = type(res_obj).__name__ restype_workflow = lcs_workflows.get(restype, None) if not restype_workflow: restype_workflow = lcs_workflows['Resource'] new_state = restype_workflow.get_successor(res_obj.lcstate, transition_event) if not new_state: raise Inconsistent("Resource id=%s, type=%s, lcstate=%s has no transition for event %s" % ( resource_id, restype, res_obj.lcstate, transition_event)) res_obj.lcstate = new_state res_obj.ts_updated = get_ion_ts() updres = self.resource_registry.update(res_obj) return new_state def create_association(self, subject=None, predicate=None, object=None, assoc_type=None): return self.resource_registry.create_association(subject, predicate, object, assoc_type) def delete_association(self, association=''): return self.resource_registry.delete_association(association) def find(self, **kwargs): raise NotImplementedError("Do not use find. Use a specific find operation instead.") def find_objects(self, subject="", predicate="", object_type="", id_only=False): return self.resource_registry.find_objects(subject, predicate, object_type, id_only=id_only) def find_subjects(self, subject_type="", predicate="", object="", id_only=False): return self.resource_registry.find_subjects(subject_type, predicate, object, id_only=id_only) def find_associations(self, subject="", predicate="", object="", id_only=False): return self.resource_registry.find_associations(subject, predicate, object, id_only=id_only) def get_association(self, subject="", predicate="", object=""): assoc = self.resource_registry.find_associations(subject, predicate, object, id_only=True) if not assoc: raise NotFound("Association for subject/predicate/object %s/%s/%s not found" % (str(subject),str(predicate),str(object))) elif len(assoc) > 1: raise Inconsistent("Duplicate associations found for subject/predicate/object %s/%s/%s" % (str(subject),str(predicate),str(object))) return assoc[0] def find_resources(self, restype="", lcstate="", name="", id_only=False): return self.resource_registry.find_resources(restype, lcstate, name, id_only=id_only)