def query(self, device_id, class_id=None, instance_id=None, attributes=None): """ Get database information. This method can be used to request information from the database to the detailed level requested :param device_id: (str) ONU Device ID :param class_id: (int) Managed Entity class ID :param instance_id: (int) Managed Entity instance :param attributes: (list/set or str) Managed Entity instance's attributes :return: (dict) The value(s) requested. If class/inst/attribute is not found, an empty dictionary is returned :raises KeyError: If the requested device does not exist :raises DatabaseStateError: If the database is not enabled """ self.log.debug('query', device_id=device_id, class_id=class_id, entity_instance_id=instance_id, attributes=attributes) data = dict() try: if class_id is None: # Get full device info self.log.warn('get-all-instances-by-device-not-supported') try: dev_data = AlarmDeviceData() device_path = self._get_device_path(device_id) dev_data.ParseFromString(self._kv_store[device_path]) data = self._device_to_dict(dev_data) except KeyError: data = dict() elif instance_id is None: # Get all instances of the class self.log.warn('get-all-instances-by-class-not-supported') try: cls_data = AlarmClassData() class_path = self._get_class_path(device_id, class_id) cls_data.ParseFromString(self._kv_store[class_path]) data = self._class_to_dict(cls_data) except KeyError: data = dict() else: # Get all attributes of a specific ME try: inst_data = AlarmInstanceData() inst_path = self._get_instance_path( device_id, class_id, instance_id) inst_data.ParseFromString(self._kv_store[inst_path]) if attributes is None: # All Attributes data = self._instance_to_dict(inst_data) self.log.debug('query-result-all', data=data) else: # Specific attribute(s) if isinstance(attributes, basestring): attributes = {attributes} data = { attr.name: self._string_to_attribute(attr.value) for attr in inst_data.attributes if attr.name in attributes } except KeyError: self.log.debug('no-instance-data-keyError') data = dict() except Exception as e: self.log.exception('get-last-sync-exception', device_id=device_id, e=e) raise self.log.debug('query-result', data=data) return data except KeyError: self.log.warn('query-no-device', device_id=device_id) raise except Exception as e: self.log.exception('get-last-sync-exception', device_id=device_id, e=e) raise
def set(self, device_id, class_id, instance_id, attributes): """ Set a database value. This should only be called by the Alarm synchronizer and its related tasks :param device_id: (str) ONU Device ID :param class_id: (int) ME Class ID :param instance_id: (int) ME Entity ID :param attributes: (dict) Attribute dictionary :returns: (bool) True if the value was saved to the database. False if the value was identical to the current instance :raises KeyError: If device does not exist :raises DatabaseStateError: If the database is not enabled """ self.log.debug('set', device_id=device_id, class_id=class_id, instance_id=instance_id, attributes=attributes) try: if not isinstance(device_id, basestring): raise TypeError('Device ID should be a string') if not 0 <= class_id <= 0xFFFF: raise ValueError( "Invalid Class ID: {}, should be 0..65535".format( class_id)) if not 0 <= instance_id <= 0xFFFF: raise ValueError( "Invalid Instance ID: {}, should be 0..65535".format( instance_id)) if not isinstance(attributes, dict): raise TypeError("Attributes should be a dictionary") if not self._started: raise DatabaseStateError( 'The Database is not currently active') try: class_data = AlarmClassData() class_path = AlarmDbExternal.CLASS_PATH.format( device_id, class_id) class_data.ParseFromString(self._kv_store[class_path]) modified = False new_data = None try: inst_data = AlarmInstanceData() inst_path = AlarmDbExternal.INSTANCE_PATH.format( device_id, class_id, instance_id) inst_data.ParseFromString(self._kv_store[inst_path]) exist_attr_indexes = dict() attr_len = len(inst_data.attributes) for index in xrange(0, attr_len): exist_attr_indexes[ inst_data.attributes[index].name] = index str_value = '' new_attributes = [] for k, v in attributes.items(): try: str_value = self._attribute_to_string(v) new_attributes.append( AlarmAttributeData(name=k, value=str_value)) except Exception as e: self.log.exception('save-error', e=e, class_id=class_id, attr=k, value_type=type(v)) if k not in exist_attr_indexes or \ inst_data.attributes[exist_attr_indexes[k]].value != str_value: modified = True self.log.debug('different-attributes', device_id=device_id, class_id=class_id, instance_id=instance_id, attributes=inst_data.attributes, new_attributes=new_attributes) if modified: now = datetime.utcnow() new_data = AlarmInstanceData( instance_id=instance_id, created=inst_data.created, modified=self._time_to_string(now), attributes=new_attributes) except KeyError: # Here if the instance_id does not yet exist in the database new_data = self._create_new_instance( device_id, class_id, instance_id, attributes) modified = True if modified: del self._kv_store[inst_path] self._kv_store[inst_path] = new_data.SerializeToString() return modified except KeyError: # Here if the class-id does not yet exist in the database return self._add_new_class_and_instance( device_id, class_id, instance_id, attributes) except Exception as e: self.log.exception('set-exception', device_id=device_id, class_id=class_id, instance_id=instance_id, attributes=attributes, e=e) raise