def start_resource_monitoring(self): """ Starts greenlets to periodically retrieve values of the attributes associated with my platform, and do corresponding event notifications. """ if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: starting resource monitoring: attr_info=%s", self._platform_id, str(self._attr_info)) # # TODO attribute grouping so one single greenlet is launched for a # group of attributes having same or similar monitoring rate. For # simplicity at the moment, start a greenlet per attribute. # for attr_id, attr_defn in self._attr_info.iteritems(): if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: dispatching resource monitoring for attr_id=%r attr_defn=%s", self._platform_id, attr_id, attr_defn) if 'monitorCycleSeconds' in attr_defn: self._start_monitor_greenlet(attr_id, attr_defn) else: log.warn( "CIDEVSA-450 %r: unexpected: attribute info does not contain %r " "for attribute %r. attr_defn = %s", self._platform_id, 'monitorCycleSeconds', attr_id, str(attr_defn))
def _retrieve_attribute_value(self): """ Retrieves the attribute value using the given function and calls _values_retrieved with retrieved values. """ attrNames = [self._attr_id] from_time = (self._last_ts + _DELTA_TIME) if self._last_ts else 0.0 if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: retrieving attribute %r from_time %f", self._platform_id, self._attr_id, from_time) retrieved_vals = self._get_attribute_values(attrNames, from_time) if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: _get_attribute_values returned %s", self._platform_id, retrieved_vals) if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: retrieved attribute %r values from_time %f = %s", self._platform_id, self._attr_id, from_time, str(retrieved_vals)) if self._attr_id in retrieved_vals: values = retrieved_vals[self._attr_id] if values: self._values_retrieved(values) elif log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: No values reported for attribute=%r from_time=%f", self._platform_id, self._attr_id, from_time) else: log.warn("CIDEVSA-450 %r: unexpected: response does not include requested attribute %r", self._platform_id, self._attr_id)
def __init__(self, oms, platform_id, attr_id, attr_defn, notify_driver_event): """ Creates a monitor for a specific attribute in a given platform. Call start to start the monitoring greenlet. @param oms The CI-OMS object @param platform_id Platform ID @param attr_id Attribute name @param attr_defn Corresp. attribute definition @param notify_driver_event Callback to notify whenever a value is retrieved. """ if log.isEnabledFor(logging.DEBUG): log.debug("%r: OmsResourceMonitor entered. attr_defn=%s", platform_id, attr_defn) assert platform_id, "must give a valid platform ID" assert 'monitorCycleSeconds' in attr_defn, "must include monitorCycleSeconds" self._oms = oms self._platform_id = platform_id self._attr_defn = attr_defn self._notify_driver_event = notify_driver_event self._attr_id = attr_id self._monitorCycleSeconds = attr_defn['monitorCycleSeconds'] # timestamp of last retrieved attribute value self._last_ts = None self._active = False if log.isEnabledFor(logging.DEBUG): log.debug("%r: OmsResourceMonitor created. attr_defn=%s", self._platform_id, attr_defn)
def _sendto(self, data): if log.isEnabledFor(logging.DEBUG): log.debug("calling sendto(%r)" % data) nobytes = self._sock.sendto(data, self._address) if log.isEnabledFor(logging.TRACE): log.trace("sendto returned: %i" % nobytes) return nobytes
def set_attribute_values(self, attrs): """ """ if log.isEnabledFor(logging.DEBUG): log.debug("set_attribute_values: attrs = %s" % str(attrs)) error_vals = self._validate_set_attribute_values(attrs) if len(error_vals) > 0: # remove offending attributes for the request below attrs_dict = dict(attrs) for bad_attr_name in error_vals: del attrs_dict[bad_attr_name] # no good attributes at all? if len(attrs_dict) == 0: # just immediately return with the errors: return error_vals # else: update attrs with the good attributes: attrs = attrs_dict.items() # ok, now make the request to RSN OMS: retval = self._oms.setPlatformAttributeValues(self._platform_id, attrs) log.debug("setPlatformAttributeValues = %s", retval) if not self._platform_id in retval: raise PlatformException("Unexpected: response does not include " "requested platform '%s'" % self._platform_id) attr_values = retval[self._platform_id] # OOIION-631 the reported timestamps are in NTP; see below for # conversion to system time. if log.isEnabledFor(logging.DEBUG): log.debug("set_attribute_values: response before conversion = %s" % str(attr_values)) # conv_attr_values: the time converted dictionary to return, initialized # with the error ones determined above if any: conv_attr_values = error_vals for attr_name, attr_val_ts in attr_values.iteritems(): (val, ntp_time) = attr_val_ts if isinstance(ntp_time, (float, int)): # do conversion: sys_ts = ntp_2_ion_ts(ntp_time) else: # NO conversion; just keep whatever the returned value is -- # normally an error code in str format: sys_ts = ntp_time conv_attr_values[attr_name] = (val, sys_ts) if log.isEnabledFor(logging.DEBUG): log.debug("set_attribute_values: response after conversion = %s" % str(conv_attr_values)) return conv_attr_values
def handle_attribute_value_event(self, driver_event): if log.isEnabledFor(logging.TRACE): # pragma: no cover # show driver_event as retrieved (driver_event.vals_dict might be large) log.trace("%r: driver_event = %s", self._platform_id, driver_event) log.trace("%r: vals_dict:\n%s", self._platform_id, self._pp.pformat(driver_event.vals_dict)) elif log.isEnabledFor(logging.DEBUG): # pragma: no cover log.debug("%r: driver_event = %s", self._platform_id, driver_event.brief()) stream_name = driver_event.stream_name publisher = self._data_publishers.get(stream_name, None) if not publisher: log.warn('%r: no publisher configured for stream_name=%r. ' 'Configured streams are: %s', self._platform_id, stream_name, self._data_publishers.keys()) return param_dict = self._param_dicts[stream_name] stream_def = self._stream_defs[stream_name] if isinstance(stream_def, str): rdt = RecordDictionaryTool(param_dictionary=param_dict.dump(), stream_definition_id=stream_def) else: rdt = RecordDictionaryTool(stream_definition=stream_def) self._publish_granule_with_multiple_params(publisher, driver_event, param_dict, rdt)
def listener(self, line): """ The line listener """ if log.isEnabledFor(logging.DEBUG): log.debug("CgsnState.listener called. line=%r" % line) toks = line.split(',') (dst, src, nnn, lng) = tuple(int(toks[i]) for i in range(4)) msg = toks[4] assert CIPOP == dst assert CICGINT == nnn assert lng == len(msg) m = re.match(r"(ACK|NACK) (.*)", msg) if m: an = m.group(1) cmd = m.group(2) key = (src, cmd) self._an[key] = an if log.isEnabledFor(logging.DEBUG): log.debug("Set %s to %s" % (str(key), an)) else: # TODO handle remaining cases pass
def set_ports(pnode): platform_id = pnode.platform_id port_infos = rsn_oms.get_platform_ports(platform_id) if not isinstance(port_infos, dict): log.warn("%r: get_platform_ports returned: %s", platform_id, port_infos) return if log.isEnabledFor(logging.TRACE): log.trace("%r: port_infos: %s", platform_id, port_infos) assert platform_id in port_infos ports = port_infos[platform_id] for port_id, dic in ports.iteritems(): port = PortNode(port_id, dic['network']) port.set_on(dic['is_on']) pnode.add_port(port) # add connected instruments: instrs_res = rsn_oms.get_connected_instruments(platform_id, port_id) if not isinstance(instrs_res, dict): log.warn("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) continue if log.isEnabledFor(logging.TRACE): log.trace("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) assert platform_id in instrs_res assert port_id in instrs_res[platform_id] instr = instrs_res[platform_id][port_id] for instrument_id, attrs in instr.iteritems(): port.add_instrument(InstrumentNode(instrument_id, attrs))
def create_instance(cls, uri=None): """ Creates an CIOMSClient instance. @param uri URI to connect to the RSN OMS server or simulator. If None (the default) the value of the OMS environment variable is used as argument. If not defined or if the resulting argument is "embsimulator" then an CIOMSSimulator instance is created and returned. Otherwise, the argument is looked up in the OMS URI aliases file and if found the corresponding URI is used for the connection. Otherwise, the given argument (or value of the OMS environment variable) is used as given to try the connection with corresponding XML/RPC server. """ if cls._uri_aliases is None: cls._load_uri_aliases() if uri is None: uri = os.getenv('OMS', 'embsimulator') if "embsimulator" == uri: # "embedded" simulator, so instantiate CIOMSSimulator here: log.debug("Using embedded CIOMSSimulator instance") instance = CIOMSSimulator() else: # try alias resolution and then create ServerProxy instance: uri = cls._uri_aliases.get(uri, uri) if log.isEnabledFor(logging.DEBUG): log.debug("Creating xmlrpclib.ServerProxy: uri=%s", uri) instance = xmlrpclib.ServerProxy(uri, allow_none=True) if log.isEnabledFor(logging.DEBUG): log.debug("Created xmlrpclib.ServerProxy: uri=%s", uri) return instance
def set_ports(pnode): platform_id = pnode.platform_id port_infos = rsn_oms.get_platform_ports(platform_id) if not isinstance(port_infos, dict): log.warn("%r: get_platform_ports returned: %s", platform_id, port_infos) return if log.isEnabledFor(logging.TRACE): log.trace("%r: port_infos: %s", platform_id, port_infos) assert platform_id in port_infos ports = port_infos[platform_id] for port_id, dic in ports.iteritems(): port = PortNode(port_id, dic['network']) pnode.add_port(port) # add connected instruments: instrs_res = rsn_oms.get_connected_instruments( platform_id, port_id) if not isinstance(instrs_res, dict): log.warn("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) continue if log.isEnabledFor(logging.TRACE): log.trace("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) assert platform_id in instrs_res assert port_id in instrs_res[platform_id] instr = instrs_res[platform_id][port_id] for instrument_id, attrs in instr.iteritems(): port.add_instrument(InstrumentNode(instrument_id, attrs))
def set_ports(pnode): platform_id = pnode.platform_id port_infos = rsn_oms.port.get_platform_ports(platform_id) if not isinstance(port_infos, dict): raise PlatformDriverException( "%r: get_platform_ports response is not a dict: %s" % (platform_id, port_infos)) if log.isEnabledFor(logging.TRACE): log.trace("%r: port_infos: %s", platform_id, port_infos) if not platform_id in port_infos: raise PlatformDriverException( "%r: get_platform_ports response does not include " "platform_id: %s" % (platform_id, port_infos)) ports = port_infos[platform_id] if not isinstance(ports, dict): raise PlatformDriverException( "%r: get_platform_ports: entry for platform_id is " "not a dict: %s" % (platform_id, ports)) for port_id, dic in ports.iteritems(): port = PortNode(port_id, dic['network']) port.set_state(dic['state']) pnode.add_port(port) # add connected instruments: instrs_res = rsn_oms.instr.get_connected_instruments( platform_id, port_id) if not isinstance(instrs_res, dict): log.warn("%r: port_id=%r: get_connected_instruments " "response is not a dict: %s" % (platform_id, port_id, instrs_res)) continue if log.isEnabledFor(logging.TRACE): log.trace("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) if not platform_id in instrs_res: raise PlatformDriverException( "%r: port_id=%r: get_connected_instruments response" "does not have entry for platform_id: %s" % (platform_id, ports)) if not port_id in instrs_res[platform_id]: raise PlatformDriverException( "%r: port_id=%r: get_connected_instruments response " "for platform_id does not have entry for port_id: %s" % (platform_id, port_id, instrs_res[platform_id])) instr = instrs_res[platform_id][port_id] for instrument_id, attrs in instr.iteritems(): port.add_instrument(InstrumentNode(instrument_id, attrs))
def _publish_granule(self, stream_name, publisher, param_dict, rdt, pub_params, timestamps): log.trace("%r: ======== publish_granule", self._platform_id) # Set timestamp info in rdt: if param_dict.temporal_parameter_name is not None: temp_param_name = param_dict.temporal_parameter_name rdt[temp_param_name] = numpy.array(timestamps) #@TODO: Ensure that the preferred_timestamp field is correct rdt['preferred_timestamp'] = numpy.array(['internal_timestamp'] * len(timestamps)) if log.isEnabledFor(logging.DEBUG): # pragma: no cover log.debug( 'Preferred timestamp is unresolved, using "internal_timestamp"' ) else: log.warn( "%r: Not including timestamp info in granule: " "temporal_parameter_name not defined in parameter dictionary", self._platform_id) g = rdt.to_granule(data_producer_id=self.resource_id, connection_id=self._connection_ID.hex, connection_index=str( self._connection_index[stream_name])) try: publisher.publish(g) if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace( "%r: Platform agent published data granule on stream %r: " "%s timestamps: %s", self._platform_id, stream_name, self._pp.pformat(pub_params), self._pp.pformat(timestamps)) elif log.isEnabledFor(logging.DEBUG): # pragma: no cover summary_params = { attr_id: "(%d vals)" % len(vals) for attr_id, vals in pub_params.iteritems() } summary_timestamps = "(%d vals)" % len(timestamps) log.debug( "%r: Platform agent published data granule on stream %r: " "%s timestamps: %s", self._platform_id, stream_name, summary_params, summary_timestamps) log.debug( "%r: granule published with connection_id=%s, connection_index=%i", self._platform_id, self._connection_ID.hex, self._connection_index[stream_name]) self._connection_index[stream_name] += 1 except Exception: log.exception( "%r: Platform agent could not publish data on stream %s.", self._platform_id, stream_name)
def set_ports(pnode): platform_id = pnode.platform_id port_infos = rsn_oms.port.get_platform_ports(platform_id) if not isinstance(port_infos, dict): raise PlatformDriverException( "%r: get_platform_ports response is not a dict: %s" % ( platform_id, port_infos)) if log.isEnabledFor(logging.TRACE): log.trace("%r: port_infos: %s", platform_id, port_infos) if not platform_id in port_infos: raise PlatformDriverException( "%r: get_platform_ports response does not include " "platform_id: %s" % (platform_id, port_infos)) ports = port_infos[platform_id] if not isinstance(ports, dict): raise PlatformDriverException( "%r: get_platform_ports: entry for platform_id is " "not a dict: %s" % (platform_id, ports)) for port_id, dic in ports.iteritems(): port = PortNode(port_id, dic['network']) port.set_state(dic['state']) pnode.add_port(port) # add connected instruments: instrs_res = rsn_oms.instr.get_connected_instruments(platform_id, port_id) if not isinstance(instrs_res, dict): log.warn("%r: port_id=%r: get_connected_instruments " "response is not a dict: %s" % (platform_id, port_id, instrs_res)) continue if log.isEnabledFor(logging.TRACE): log.trace("%r: port_id=%r: get_connected_instruments " "returned: %s" % (platform_id, port_id, instrs_res)) if not platform_id in instrs_res: raise PlatformDriverException( "%r: port_id=%r: get_connected_instruments response" "does not have entry for platform_id: %s" % ( platform_id, ports)) if not port_id in instrs_res[platform_id]: raise PlatformDriverException( "%r: port_id=%r: get_connected_instruments response " "for platform_id does not have entry for port_id: %s" % ( platform_id, port_id, instrs_res[platform_id])) instr = instrs_res[platform_id][port_id] for instrument_id, attrs in instr.iteritems(): port.add_instrument(InstrumentNode(instrument_id, attrs))
def get_attribute_values(self, attr_names, from_time): """ """ if log.isEnabledFor(logging.DEBUG): log.debug("get_attribute_values: attr_names=%s from_time=%s" % ( str(attr_names), from_time)) self._assert_rsn_oms() # OOIION-631 convert the system time from_time to NTP, which is used by # the RSN OMS interface: ntp_from_time = ion_ts_2_ntp(from_time) retval = self._rsn_oms.get_platform_attribute_values(self._platform_id, attr_names, ntp_from_time) if not self._platform_id in retval: raise PlatformException("Unexpected: response does not include " "requested platform '%s'" % self._platform_id) attr_values = retval[self._platform_id] # OOIION-631 the reported timestamps are in NTP; do conversion to system time if log.isEnabledFor(logging.TRACE): log.trace("get_attribute_values: response before conversion = %s" % str(attr_values)) conv_attr_values = {} # the converted dictionary to return for attr_name, array in attr_values.iteritems(): conv_array = [] for (val, ntp_time) in array: if isinstance(ntp_time, (float, int)): # do conversion: sys_ts = ntp_2_ion_ts(ntp_time) else: # NO conversion; just keep whatever the returned value is -- # normally an error code in str format: sys_ts = ntp_time conv_array.append((val, sys_ts)) conv_attr_values[attr_name] = conv_array if log.isEnabledFor(logging.TRACE): log.trace("get_attribute_values: response after conversion = %s" % str(conv_attr_values)) return conv_attr_values
def setUp(self): self.DVR_CONFIG = { 'oms_uri': self._dispatch_simulator('launchsimulator'), 'attributes': {}, 'ports': {} } log.debug("DVR_CONFIG['oms_uri'] = %s", self.DVR_CONFIG['oms_uri']) yaml_filename = 'ion/agents/platform/rsn/simulator/network.yml' log.debug("retrieving network definition from %s", yaml_filename) network_definition = NetworkUtil.deserialize_network_definition( file(yaml_filename)) if log.isEnabledFor(logging.DEBUG): network_definition_ser = NetworkUtil.serialize_network_definition( network_definition) log.debug("NetworkDefinition serialization:\n%s", network_definition_ser) platform_id = self.PLATFORM_ID pnode = network_definition.pnodes[platform_id] def evt_recv(driver_event): log.debug('GOT driver_event=%s', str(driver_event)) self._plat_driver = RSNPlatformDriver(pnode, evt_recv, Mock(), Mock()) res_state = self._plat_driver.get_resource_state() self.assertEqual(res_state, RSNPlatformDriverState.UNCONFIGURED)
def _handler_connected_disconnect_instrument(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) port_id = kwargs.get('port_id', None) if port_id is None: raise FSMError('disconnect_instrument: missing port_id argument') instrument_id = kwargs.get('instrument_id', None) if instrument_id is None: raise FSMError('disconnect_instrument: missing instrument_id argument') try: result = self.disconnect_instrument(port_id, instrument_id) next_state = None except PlatformConnectionException as e: return self._connection_lost(RSNPlatformDriverEvent.DISCONNECT_INSTRUMENT, args, kwargs, e) return next_state, result
def __init__(self, pnode, evt_recv): """ Creates a PlatformDriver instance. @param pnode Root PlatformNode defining the platform network rooted at this platform. @param evt_recv Listener of events generated by this driver """ assert pnode, "pnode must be given" assert evt_recv, "evt_recv parameter must be given" self._pnode = pnode self._send_event = evt_recv self._platform_id = self._pnode.platform_id if self._pnode.parent: self._parent_platform_id = self._pnode.parent.platform_id else: self._parent_platform_id = None self._platform_attributes = \ dict((a.attr_id, a.defn) for a in self._pnode.attrs.itervalues()) if log.isEnabledFor(logging.DEBUG): log.debug("%r: PlatformDriver constructor called: pnode:\n%s\n" "_platform_attributes=%s", self._platform_id, NetworkUtil._dump_pnode(self._pnode, include_subplatforms=False), self._platform_attributes) self._driver_config = None # construct FSM and start it with initial state UNCONFIGURED: self._construct_fsm() self._fsm.start(PlatformDriverState.UNCONFIGURED)
def _handler_connected_turn_off_port(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) port_id = kwargs.get('port_id', None) if port_id is None: raise FSMError('turn_off_port: missing port_id argument') port_id = kwargs.get('port_id', None) instrument_id = kwargs.get('instrument_id', None) if port_id is None and instrument_id is None: raise FSMError('turn_off_port: at least one of port_id and ' 'instrument_id argument must be given') try: result = self.turn_off_port(port_id=port_id, instrument_id=instrument_id) return None, result except PlatformConnectionException as e: return self._connection_lost(RSNPlatformDriverEvent.TURN_OFF_PORT, args, kwargs, e)
def test_compute_checksum(self): # create NetworkDefinition object by de-serializing the simulated network: ndef = NetworkUtil.deserialize_network_definition(file("ion/agents/platform/rsn/simulator/network.yml")) checksum = ndef.compute_checksum() if log.isEnabledFor(logging.DEBUG): log.debug("NetworkDefinition checksum = %s", checksum)
def _handler_connected_set_over_current(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % (self._platform_id, self.get_driver_state(), str(args), str(kwargs))) port_id = kwargs.get('port_id', None) if port_id is None: raise FSMError('set_over_current: missing port_id argument') ma = kwargs.get('ma', None) if ma is None: raise FSMError('set_over_current: missing ma argument') us = kwargs.get('us', None) if us is None: raise FSMError('set_over_current: missing us argument') # TODO: provide source info if not explicitly given: src = kwargs.get('src', 'source TBD') try: result = self.set_over_current(port_id, ma, us, src) return None, result except PlatformConnectionException as e: return self._connection_lost(RSNPlatformDriverEvent.TURN_OFF_PORT, args, kwargs, e)
def test_build_network_definition(self): ndef = RsnOmsUtil.build_network_definition(self._rsn_oms) if log.isEnabledFor(logging.TRACE): # serialize object to string serialization = NetworkUtil.serialize_network_definition(ndef) log.trace("NetworkDefinition serialization:\n%s", serialization) if not isinstance(self._rsn_oms, CIOMSSimulator): # OK, no more tests if we are not using the embedded simulator return # Else: do some verifications against network.yml (the spec used by # the simulator): self.assertTrue("UPS" in ndef.platform_types) pnode = ndef.root self.assertEqual(pnode.platform_id, "ShoreStation") self.assertIn("ShoreStation_attr_1|0", pnode.attrs) self.assertIn("ShoreStation_port_1", pnode.ports) sub_pnodes = pnode.subplatforms self.assertIn("L3-UPS1", sub_pnodes) self.assertIn("Node1A", sub_pnodes) self.assertIn("input_voltage|0", sub_pnodes["Node1A"].attrs) self.assertIn("Node1A_port_1", sub_pnodes["Node1A"].ports)
def _values_retrieved(self, values): """ A values response has been received. Create and notify corresponding event to platform agent. """ if log.isEnabledFor(logging.DEBUG): ln = len(values) # just show a couple of elements arrstr = "[" if ln <= 3: vals = [str(e) for e in values[:ln]] arrstr += ", ".join(vals) else: vals = [str(e) for e in values[:2]] last_e = values[-1] arrstr += ", ".join(vals) arrstr += ", ..., " +str(last_e) arrstr += "]" log.debug("CIDEVSA-450 %r: attr=%r: values retrieved(%s) = %s", self._platform_id, self._attr_id, ln, arrstr) # update _last_ts based on last element in values: _, ts = values[-1] self._last_ts = float(ts) driver_event = AttributeValueDriverEvent(self._platform_id, self._attr_id, values) self._notify_driver_event(driver_event)
def _construct_stream_and_publisher(self, stream_name, stream_config): if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r: _construct_stream_and_publisher: " "stream_name:%r, stream_config:\n%s", self._platform_id, stream_name, self._pp.pformat(stream_config)) decoder = IonObjectDeserializer(obj_registry=get_obj_registry()) if 'stream_def_dict' not in stream_config: # should not happen: PlatformAgent._validate_configuration validates this. log.error("'stream_def_dict' key not in configuration for stream %r" % stream_name) return stream_def_dict = stream_config['stream_def_dict'] stream_def_dict['type_'] = 'StreamDefinition' stream_def_obj = decoder.deserialize(stream_def_dict) self._stream_defs[stream_name] = stream_def_obj routing_key = stream_config['routing_key'] stream_id = stream_config['stream_id'] exchange_point = stream_config['exchange_point'] parameter_dictionary = stream_def_dict['parameter_dictionary'] log.debug("%r: got parameter_dictionary from stream_def_dict", self._platform_id) self._data_streams[stream_name] = stream_id self._param_dicts[stream_name] = ParameterDictionary.load(parameter_dictionary) stream_route = StreamRoute(exchange_point=exchange_point, routing_key=routing_key) publisher = self._create_publisher(stream_id, stream_route) self._data_publishers[stream_name] = publisher log.debug("%r: created publisher for stream_name=%r", self._platform_id, stream_name)
def test_build_network_definition(self): ndef = RsnOmsUtil.build_network_definition(self._rsn_oms) if log.isEnabledFor(logging.TRACE): # serialize object to string serialization = NetworkUtil.serialize_network_definition(ndef) log.trace("NetworkDefinition serialization:\n%s", serialization) if not isinstance(self._rsn_oms, CIOMSSimulator): # OK, no more tests if we are not using the embedded simulator return # Else: do some verifications against network.yml (the spec used by # the simulator): self.assertTrue("UPS" in ndef.platform_types) pnode = ndef.root self.assertEqual(pnode.platform_id, "ShoreStation") self.assertTrue("ShoreStation_attr_1" in pnode.attrs) self.assertTrue("ShoreStation_port_1" in pnode.ports) sub_pnodes = pnode.subplatforms self.assertTrue("L3-UPS1" in sub_pnodes) self.assertTrue("Node1A" in sub_pnodes) self.assertTrue("input_voltage" in sub_pnodes["Node1A"].attrs) self.assertTrue("Node1A_port_1" in sub_pnodes["Node1A"].ports)
def _handler_connected_set_over_current(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) port_id = kwargs.get('port_id', None) if port_id is None: raise FSMError('set_over_current: missing port_id argument') ma = kwargs.get('ma', None) if ma is None: raise FSMError('set_over_current: missing ma argument') us = kwargs.get('us', None) if us is None: raise FSMError('set_over_current: missing us argument') # TODO: provide source info if not explicitly given: src = kwargs.get('src', 'source TBD') try: result = self.set_over_current(port_id, ma, us, src) return None, result except PlatformConnectionException as e: return self._connection_lost(RSNPlatformDriverEvent.TURN_OFF_PORT, args, kwargs, e)
def setUp(self): self._start_container() self.container.start_rel_from_url('res/deploy/r2deploy.yml') self.RR = ResourceRegistryServiceClient(node=self.container.node) self.IMS = InstrumentManagementServiceClient(node=self.container.node) self.DAMS = DataAcquisitionManagementServiceClient(node=self.container.node) self.DP = DataProductManagementServiceClient(node=self.container.node) self.PSC = PubsubManagementServiceClient(node=self.container.node) self.PDC = ProcessDispatcherServiceClient(node=self.container.node) self.DSC = DatasetManagementServiceClient() self.IDS = IdentityManagementServiceClient(node=self.container.node) self.RR2 = EnhancedResourceRegistryClient(self.RR) # Use the network definition provided by RSN OMS directly. rsn_oms = CIOMSClientFactory.create_instance(DVR_CONFIG['oms_uri']) self._network_definition = RsnOmsUtil.build_network_definition(rsn_oms) # get serialized version for the configuration: self._network_definition_ser = NetworkUtil.serialize_network_definition(self._network_definition) if log.isEnabledFor(logging.TRACE): log.trace("NetworkDefinition serialization:\n%s", self._network_definition_ser) self._async_data_result = AsyncResult() self._data_subscribers = [] self._samples_received = [] self.addCleanup(self._stop_data_subscribers) self._async_event_result = AsyncResult() self._event_subscribers = [] self._events_received = [] self.addCleanup(self._stop_event_subscribers) self._start_event_subscriber()
def _get_checksum(self, platform_id): # get checksum from RSN OMS: res = self._rsn_oms.get_checksum(platform_id) checksum = res[platform_id] if log.isEnabledFor(logging.DEBUG): log.debug("_rsn_oms: checksum: %s", checksum) return checksum
def _handler_connected_connect_instrument(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) port_id = kwargs.get('port_id', None) if port_id is None: raise FSMError('connect_instrument: missing port_id argument') instrument_id = kwargs.get('instrument_id', None) if instrument_id is None: raise FSMError('connect_instrument: missing instrument_id argument') attributes = kwargs.get('attributes', None) if attributes is None: raise FSMError('connect_instrument: missing attributes argument') try: result = self.connect_instrument(port_id, instrument_id, attributes) return None, result except PlatformConnectionException as e: return self._connection_lost(RSNPlatformDriverEvent.CONNECT_INSTRUMENT, args, kwargs, e)
def _get_checksum(self, platform_id): # get checksum from RSN OMS: res = self._rsn_oms.config.get_checksum(platform_id) checksum = res[platform_id] if log.isEnabledFor(logging.DEBUG): log.debug("_rsn_oms: checksum: %s", checksum) return checksum
def setUp(self): self.DVR_CONFIG = { 'oms_uri': self._dispatch_simulator('launchsimulator'), 'attributes': {}, 'ports': {} } log.debug("DVR_CONFIG['oms_uri'] = %s", self.DVR_CONFIG['oms_uri']) yaml_filename = 'ion/agents/platform/rsn/simulator/network.yml' log.debug("retrieving network definition from %s", yaml_filename) network_definition = NetworkUtil.deserialize_network_definition(file(yaml_filename)) if log.isEnabledFor(logging.DEBUG): network_definition_ser = NetworkUtil.serialize_network_definition(network_definition) log.debug("NetworkDefinition serialization:\n%s", network_definition_ser) platform_id = self.PLATFORM_ID pnode = network_definition.pnodes[platform_id] def evt_recv(driver_event): log.debug('GOT driver_event=%s', str(driver_event)) self._plat_driver = RSNPlatformDriver(pnode, evt_recv, Mock(), Mock()) res_state = self._plat_driver.get_resource_state() self.assertEqual(res_state, RSNPlatformDriverState.UNCONFIGURED)
def _publish_granule(self, stream_name, publisher, param_dict, rdt, pub_params, timestamps): log.trace("%r: ======== publish_granule", self._platform_id) # Set timestamp info in rdt: if param_dict.temporal_parameter_name is not None: temp_param_name = param_dict.temporal_parameter_name rdt[temp_param_name] = numpy.array(timestamps) #@TODO: Ensure that the preferred_timestamp field is correct rdt['preferred_timestamp'] = numpy.array(['internal_timestamp'] * len(timestamps)) if log.isEnabledFor(logging.DEBUG): # pragma: no cover log.debug('Preferred timestamp is unresolved, using "internal_timestamp"') else: log.warn("%r: Not including timestamp info in granule: " "temporal_parameter_name not defined in parameter dictionary", self._platform_id) g = rdt.to_granule(data_producer_id=self.resource_id, connection_id=self._connection_ID.hex, connection_index=str(self._connection_index[stream_name])) try: publisher.publish(g) if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r: Platform agent published data granule on stream %r: " "%s timestamps: %s", self._platform_id, stream_name, self._pp.pformat(pub_params), self._pp.pformat(timestamps)) elif log.isEnabledFor(logging.DEBUG): # pragma: no cover summary_params = {attr_id: "(%d vals)" % len(vals) for attr_id, vals in pub_params.iteritems()} summary_timestamps = "(%d vals)" % len(timestamps) log.debug("%r: Platform agent published data granule on stream %r: " "%s timestamps: %s", self._platform_id, stream_name, summary_params, summary_timestamps) log.debug("%r: granule published with connection_id=%s, connection_index=%i", self._platform_id, self._connection_ID.hex, self._connection_index[stream_name]) self._connection_index[stream_name] += 1 except Exception: log.exception("%r: Platform agent could not publish data on stream %s.", self._platform_id, stream_name)
def _load_uri_aliases(cls): try: cls._uri_aliases = yaml.load(file(_OMS_URI_ALIASES_FILENAME)) if log.isEnabledFor(logging.DEBUG): log.debug("Loaded OMS URI aliases = %s" % cls._uri_aliases) except Exception as e: log.warn("Cannot loaded %s: %s" % (_OMS_URI_ALIASES_FILENAME, e)) cls._uri_aliases = {}
def test_compute_checksum(self): # create NetworkDefinition object by de-serializing the simulated network: ndef = NetworkUtil.deserialize_network_definition( file('ion/agents/platform/rsn/simulator/network.yml')) checksum = ndef.compute_checksum() if log.isEnabledFor(logging.DEBUG): log.debug("NetworkDefinition checksum = %s", checksum)
def run(self): if self._listener == self._dummy_listener: log.warn("No listener provided. Using a dummy one") if log.isEnabledFor(logging.DEBUG): log.debug("_Recv running") self._running = True while self._running: # some timeout to regularly check for end call rlist, wlist, elist = select.select([self._sock], [], [], 0.5) if rlist: recv_data = self._sock.recv(1024) self._handle_recv_data(recv_data) if log.isEnabledFor(logging.DEBUG): log.debug("_Recv.run done.")
def disconnect(self): """ Destroys the CIOMSClient instance. """ self._assert_rsn_oms() self._rsn_oms = None if log.isEnabledFor(logging.DEBUG): log.debug("%r: CIOMSClient instance destroyed" % self._platform_id)
def _load_uri_aliases(cls): try: cls._uri_aliases = yaml.load(file(_URI_ALIASES_FILENAME)) if log.isEnabledFor(logging.TRACE): log.trace("Loaded CGSN URI aliases = %s" % cls._uri_aliases) except Exception as e: log.warn("Cannot loaded %s: %s" % (_URI_ALIASES_FILENAME, e)) cls._uri_aliases = {}
def _start_diagnostics_subscriber(self): # pragma: no cover """ For debugging/diagnostics purposes. Registers a subscriber to DeviceStatusEvent events with origin="command_line" and sub_type="diagnoser" to log the current statuses via log.info. This method does nothing if the logging level is not enabled for INFO for this module. From the pycc command line, the event can be sent as indicated in publish_event_for_diagnostics(). """ # TODO perhaps a more visible/official command for diagnostic purposes, # and for resource agents in general should be considered, something # like RESOURCE_AGENT_EVENT_REPORT_DIAGNOSTICS. if not log.isEnabledFor(logging.INFO): return event_type = "DeviceStatusEvent" origin = "command_line" sub_type = "diagnoser" def got_event(evt, *args, **kwargs): if not self._active: log.warn("%r: got_event called but manager has been destroyed", self._platform_id) return if evt.type_ != event_type: log.trace("%r: ignoring event type %r. Only handle %r directly", self._platform_id, evt.type_, event_type) return if evt.sub_type != sub_type: log.trace("%r: ignoring event sub_type %r. Only handle %r", self._platform_id, evt.sub_type, sub_type) return state = self._agent.get_agent_state() statuses = formatted_statuses(self.aparam_aggstatus, self.aparam_child_agg_status, self.aparam_rollup_status) invalidated_children = self._agent._get_invalidated_children() log.info("%r/%s: (%s) status report triggered by diagnostic event:\n" "%s\n" "%40s : %s\n", self._platform_id, state, self.resource_id, statuses, "invalidated_children", invalidated_children) self._diag_sub = self._agent._create_event_subscriber(event_type=event_type, origin=origin, sub_type=sub_type, callback=got_event) log.info("%r: registered diagnostics event subscriber", self._platform_id)
def _retrieve_attribute_values(self): """ Retrieves the attribute values using the given function and calls _values_retrieved. """ # determine from_time for the request: if self._last_ts is None: # This is the very first retrieval request, so pick a from_time # that makes sense. At the moment, setting from_time to be current # system minus the monitoring rate. # TODO: determine actual criteria here. from_time = current_time_millis() - self._rate_millis # TODO: Also note that the "from_time" parameter for the request was # influenced by the RSN case (see CI-OMS interface). Need to see # whether it also applies to CGSN so eventually adjustments may be needed. # else: # note that int(x) returns a long object if needed. from_time = int(self._last_ts) + _DELTA_TIME log.debug("%r: _retrieve_attribute_values: attr_ids=%r from_time=%s", self._platform_id, self._attr_ids, from_time) retrieved_vals = self._get_attribute_values(self._attr_ids, from_time) log.debug( "%r: _retrieve_attribute_values: _get_attribute_values " "for attr_ids=%r and from_time=%s returned %s", self._platform_id, self._attr_ids, from_time, retrieved_vals) # vals_dict: attributes with non-empty reported values: vals_dict = {} for attr_id in self._attr_ids: if not attr_id in retrieved_vals: log.warn( "%r: _retrieve_attribute_values: unexpected: " "response does not include requested attribute %r. " "Response is: %s", self._platform_id, attr_id, retrieved_vals) continue attr_vals = retrieved_vals[attr_id] if not attr_vals: log.debug( "%r: No values reported for attribute=%r from_time=%f", self._platform_id, attr_id, from_time) continue if log.isEnabledFor(logging.DEBUG): self._debug_values_retrieved(attr_id, attr_vals) # ok, include this attribute for the notification: vals_dict[attr_id] = attr_vals if vals_dict: self._values_retrieved(vals_dict)
def _debug_config(self, config, outname): if log.isEnabledFor(logging.DEBUG): import pprint outname = "logs/%s" % outname try: pprint.PrettyPrinter(stream=file(outname, "w")).pprint(config) log.debug("config pretty-printed to %s", outname) except Exception as e: log.warn("error printing config to %s: %s", outname, e)
def start(self): """ Starts greenlet for resource monitoring. """ if log.isEnabledFor(logging.DEBUG): log.debug("CIDEVSA-450 %r: starting resource monitoring %s", self._platform_id, str(self)) self._active = True runnable = Greenlet(self._run) runnable.start()
def _common_state_enter(self, *args, **kwargs): """ Common work upon every state entry. Nothing done in this base class. @todo determine what should be done, in particular regarding eventual notification of the platform driver state transition. """ state = self.get_driver_state() if log.isEnabledFor(logging.DEBUG): log.debug('%r: driver entering state: %s' % (self._platform_id, state))
def _publish_granule_with_multiple_params(self, publisher, driver_event, param_dict, rdt): stream_name = driver_event.stream_name pub_params = {} selected_timestamps = None for param_name, param_value in driver_event.vals_dict.iteritems(): param_name = param_name.lower() if not param_name in rdt: if param_name not in self._unconfigured_params: # an unrecognized attribute for this platform: self._unconfigured_params.add(param_name) log.warn('%r: got attribute value event for unconfigured parameter %r in stream %r' ' rdt.keys=%s', self._platform_id, param_name, stream_name, list(rdt.iterkeys())) continue # separate values and timestamps: vals, timestamps = zip(*param_value) self._agent._dispatch_value_alerts(stream_name, param_name, vals) # Use fill_value in context to replace any None values: param_ctx = param_dict.get_context(param_name) if param_ctx: fill_value = param_ctx.fill_value log.debug("%r: param_name=%r fill_value=%s", self._platform_id, param_name, fill_value) # do the replacement: vals = [fill_value if val is None else val for val in vals] if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r: vals array after replacing None with fill_value:\n%s", self._platform_id, self._pp.pformat(vals)) else: log.warn("%r: unexpected: parameter context not found for %r", self._platform_id, param_name) # Set values in rdt: rdt[param_name] = numpy.array(vals) pub_params[param_name] = vals selected_timestamps = timestamps if selected_timestamps is None: # that is, all param_name's were unrecognized; just return: return self._publish_granule(stream_name, publisher, param_dict, rdt, pub_params, selected_timestamps)
def __init__(self, pnode, event_callback, create_event_subscriber, destroy_event_subscriber): """ Creates a PlatformDriver instance. @param pnode Root PlatformNode defining the platform network rooted at this platform. @param event_callback Callback to notify platform agent about events generated by this driver. This is captured in self._send_event for this class and subclasses to call as needed. @param create_event_subscriber @param destroy_event_subscriber functions to create/destroy any needed EventSubscriber's, in particular regarding the Managed Endpoint API. """ # # NOTE the "pnode" parameter may be not very "standard" but it is the # current convenient mechanism that captures the overall definition # of the corresponding platform (most of which coming from configuration) # self._pnode = pnode self._send_event = event_callback self._create_event_subscriber = create_event_subscriber self._destroy_event_subscriber = destroy_event_subscriber self._platform_id = self._pnode.platform_id if self._pnode.parent: self._parent_platform_id = self._pnode.parent.platform_id else: self._parent_platform_id = None self._platform_attributes = \ dict((a.attr_id, a.defn) for a in self._pnode.attrs.itervalues()) if log.isEnabledFor(logging.DEBUG): log.debug("%r: PlatformDriver constructor called: pnode:\n%s\n" "_platform_attributes=%s", self._platform_id, NetworkUtil._dump_pnode(self._pnode, include_subplatforms=False), self._platform_attributes) self._driver_config = None self._resource_schema = {} # The parameter dictionary. self._param_dict = {} # construct FSM and start it with initial state UNCONFIGURED: self._construct_fsm() self._fsm.start(PlatformDriverState.UNCONFIGURED)
def configure(self, driver_config): """ Configures this driver. It first calls _validate_driver_configuration. @param driver_config Driver configuration. """ if log.isEnabledFor(logging.DEBUG): log.debug("%r: configure: %s" % (self._platform_id, str(driver_config))) self._validate_driver_configuration(driver_config) self._driver_config = driver_config
def _handler_connected_disconnect(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) result = self.disconnect(*args, **kwargs) next_state = PlatformDriverState.DISCONNECTED return next_state, result
def _handler_connected_get_checksum(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) result = self.get_checksum() next_state = None return next_state, result
def _add_timing_stats(self, timer): """ add stats from latest coverage operation to Accumulator and periodically log results """ self.time_stats.add(timer) if self.time_stats.get_count() % REPORT_FREQUENCY > 0: return if log.isEnabledFor(TRACE): # report per step for step in 'checks', 'insert', 'keys', 'save', 'notify': log.debug('%s step %s times: %s', self._id, step, self.time_stats.to_string(step)) # report totals log.debug('%s total times: %s', self._id, self.time_stats)
def _handler_disconnected_disconnect(self, *args, **kwargs): """ We allow the DISCONNECT event in DISCONNECTED state for convenience, in particular it facilitates the overall handling of the connection_lost event, which is processed by a subsequent call to disconnect from the platform agent. The handler here does nothing. """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) return None, None
def configure(self, driver_config): """ Configures this driver. In this base class it basically calls validate_driver_configuration and then assigns the given config to self._driver_config. @param driver_config Driver configuration. """ if log.isEnabledFor(logging.DEBUG): log.debug("%r: configure: %s" % (self._platform_id, str(driver_config))) self.validate_driver_configuration(driver_config) self._driver_config = driver_config
def setUp(self): # Use the network definition provided by RSN OMS directly. rsn_oms = CIOMSClientFactory.create_instance(DVR_CONFIG['oms_uri']) network_definition = RsnOmsUtil.build_network_definition(rsn_oms) if log.isEnabledFor(logging.DEBUG): network_definition_ser = NetworkUtil.serialize_network_definition(network_definition) log.debug("NetworkDefinition serialization:\n%s", network_definition_ser) platform_id = self.PLATFORM_ID pnode = network_definition.pnodes[platform_id] self._plat_driver = RSNPlatformDriver(pnode, self.evt_recv)
def _test_multiple_missions(self, instr_keys, mission_filenames, max_wait=None): """ Verifies platform agent can dispatch execution of multiple missions. Should receive 2 ResourceAgentStateEvents from the platform: - when transitioning to MISSION_COMMAND (upon first mission execution started) - when transitioning back to COMMAND No other explicit verifications, but the logs should show lines like the following where the number of running missions is included: DEBUG Dummy-204 ion.agents.platform.mission_manager:58 [mm] starting mission_id='ion/agents/platform/test/multi_mission_1.yml' (#running missions=1) ... DEBUG Dummy-205 ion.agents.platform.mission_manager:58 [mm] starting mission_id='ion/agents/platform/test/multi_mission_2.yml' (#running missions=2) @param instr_keys Instruments to associate with parent platform; these should be ones references in the mission plans. @param mission_filenames List of filenames @param max_wait maximum wait for mission completion; no effect if None. """ self._set_receive_timeout() # start everything up to platform agent in COMMAND state. p_root = self._start_everything_up(instr_keys, True) origin = p_root.platform_device_id async_event_result, events_received = self._start_event_subscriber2( count=2, event_type="ResourceAgentStateEvent", origin_type="PlatformDevice", origin=origin) for mission_filename in mission_filenames: mission_yml = self._get_processed_yml(instr_keys, mission_filename) self._run_mission(mission_filename, mission_yml) log.debug( '[mm] waiting for %s expected MissionLifecycleEvents from origin=%r', 2, origin) started = time.time() async_event_result.get(timeout=max_wait) if log.isEnabledFor(logging.DEBUG): log.debug('[mm] got %d events (%s secs):\n%s', len(events_received), time.time() - started, self._pp.pformat(events_received)) self.assertEqual(len(events_received), 2)
def _handler_connected_get(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) try: result = self.get(*args, **kwargs) return None, result except PlatformConnectionException as e: return self._connection_lost(PlatformDriverEvent.GET, args, kwargs, e)
def _handler_disconnected_connect(self, *args, **kwargs): """ """ if log.isEnabledFor(logging.TRACE): # pragma: no cover log.trace("%r/%s args=%s kwargs=%s" % ( self._platform_id, self.get_driver_state(), str(args), str(kwargs))) recursion = kwargs.get('recursion', None) self.connect(recursion=recursion) result = next_state = PlatformDriverState.CONNECTED return next_state, result
def setUp(self): self._start_container() self.container.start_rel_from_url('res/deploy/r2deploy.yml') self.rrclient = ResourceRegistryServiceClient(node=self.container.node) self.omsclient = ObservatoryManagementServiceClient( node=self.container.node) self.imsclient = InstrumentManagementServiceClient( node=self.container.node) self.damsclient = DataAcquisitionManagementServiceClient( node=self.container.node) self.dpclient = DataProductManagementServiceClient( node=self.container.node) self.pubsubcli = PubsubManagementServiceClient( node=self.container.node) self.processdispatchclient = ProcessDispatcherServiceClient( node=self.container.node) self.dataprocessclient = DataProcessManagementServiceClient( node=self.container.node) self.dataset_management = DatasetManagementServiceClient() # Use the network definition provided by RSN OMS directly. rsn_oms = CIOMSClientFactory.create_instance(DVR_CONFIG['oms_uri']) self._network_definition = RsnOmsUtil.build_network_definition(rsn_oms) # get serialized version for the configuration: self._network_definition_ser = NetworkUtil.serialize_network_definition( self._network_definition) if log.isEnabledFor(logging.DEBUG): log.debug("NetworkDefinition serialization:\n%s", self._network_definition_ser) self.platformModel_id = None self.all_platforms = {} self.agent_streamconfig_map = {} self._async_data_result = AsyncResult() self._data_subscribers = [] self._samples_received = [] self.addCleanup(self._stop_data_subscribers) self._async_event_result = AsyncResult() self._event_subscribers = [] self._events_received = [] self.addCleanup(self._stop_event_subscribers) self._start_event_subscriber() self._set_up_DataProduct_obj() self._set_up_PlatformModel_obj()