def _values_retrieved(self, vals_dict): """ A values response has been received. Create and notify corresponding event to platform agent. """ # maximum of the latest timestamps in the returned values; # used to prepare for the next request: max_ntp_ts = None for attr_id, attr_vals in vals_dict.iteritems(): assert attr_vals, "Must be a non-empty array of values per _retrieve_attribute_values" _, ntp_ts = attr_vals[-1] if max_ntp_ts is None: max_ntp_ts = ntp_ts else: max_ntp_ts = max(max_ntp_ts, ntp_ts) # update _last_ts based on max_ntp_ts: note that timestamps are reported # in NTP so we need to convert it to ION system time for a subsequent request: self._last_ts = ntp_2_ion_ts(max_ntp_ts) # finally, notify the values event: driver_event = AttributeValueDriverEvent(self._platform_id, _STREAM_NAME, vals_dict) self._notify_driver_event(driver_event)
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 show_listeners(): from datetime import datetime from ion.agents.platform.util import ntp_2_ion_ts event_listeners = proxy.event.get_registered_event_listeners() print("Event listeners (%d):" % len(event_listeners)) for a, b in sorted(event_listeners.iteritems(), lambda a, b: int(a[1] - b[1])): time = datetime.fromtimestamp(float(ntp_2_ion_ts(b)) / 1000) print(" %s %s" % (time, a)) print
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 _values_retrieved(self, vals_dict): """ A values response has been received. Create and notify corresponding event to platform agent. """ # update _last_ts_millis for each retrieved attribute: for attr_id, attr_vals in vals_dict.iteritems(): _, ntp_ts = attr_vals[-1] # update _last_ts_millis based on ntp_ts: note that timestamps are reported # in NTP so we need to convert it to ION system time for a subsequent request: self._last_ts_millis[attr_id] = ntp_2_ion_ts(ntp_ts) # finally, notify the values event: driver_event = AttributeValueDriverEvent(self._platform_id, _STREAM_NAME, vals_dict) self._notify_driver_event(driver_event)
def test_resource_monitoring_recent(self): # # https://jira.oceanobservatories.org/tasks/browse/OOIION-1372 # # Verifies that the requests for attribute values are always for # the most recent ones, meaning that the retrieved values should *not* # be older than a small multiple of the nominal monitoring rate, even # after a long period in non-monitoring state. # See ResourceMonitor._retrieve_attribute_values # # start this test as in test_resource_monitoring() self.test_resource_monitoring() # which completes right after stopping monitoring. We want that initial # start/stop-monitoring phase to make this test more comprehensive. self._assert_state(PlatformAgentState.COMMAND) # now, the rest of this test does the following: # - pick an attribute to use as a basis for the time parameters to # be used in the test # - wait for a while in the current non-monitoring mode # - re-enable monitoring # - wait for a sample to be published # - verify that new received data sample is "recent" # - stop monitoring # first, use an attribute (from the root platform being tested) with # a minimal monitoring rate, since that attribute should be reported # in a first sample received after re-enabling the monitoring. attr = None for attr_id, plat_attr in self._platform_attributes[self.PLATFORM_ID].iteritems(): if attr is None or \ float(plat_attr['monitor_cycle_seconds']) < float(attr['monitor_cycle_seconds']): attr = plat_attr self.assertIsNotNone(attr, "some attribute expected to be defined for %r to " "actually proceed with this test" % self.PLATFORM_ID) attr_id = attr['attr_id'] monitor_cycle_seconds = attr['monitor_cycle_seconds'] log.info("test_resource_monitoring_recent: using attr_id=%r: monitor_cycle_seconds=%s", attr_id, monitor_cycle_seconds) # sleep for twice the interval defining "recent": from ion.agents.platform.resource_monitor import _MULT_INTERVAL time_to_sleep = 2 * (_MULT_INTERVAL * monitor_cycle_seconds) log.info("test_resource_monitoring_recent: sleeping for %s secs " "before resuming monitoring", time_to_sleep) sleep(time_to_sleep) # reset the variables associated with the _wait_for_a_data_sample call below: self._samples_received = [] self._async_data_result = AsyncResult() ################################################# # re-start monitoring and wait for new sample: log.info("test_resource_monitoring_recent: re-starting monitoring") self._start_resource_monitoring(recursion=False) # should also work with recursion to children but set recursion=False # to avoid wasting the extra time in this test. try: self._wait_for_a_data_sample() # get current time here (right after receiving sample) for comparison below: curr_time_millis = current_time_millis() # verify that the timestamp of the received sample is not too old. # For this, use the minimum of the reported timestamps: rdt = RecordDictionaryTool.load_from_granule(self._samples_received[0]) log.trace("test_resource_monitoring_recent: rdt:\n%s", rdt.pretty_print()) temporal_parameter_name = rdt.temporal_parameter times = rdt[temporal_parameter_name] log.trace("test_resource_monitoring_recent: times:\n%s", self._pp.pformat(times)) # minimum reported timestamp (note the NTP -> ION_time conversion): min_reported_time_ntp = min(times) min_reported_time_millis = float(ntp_2_ion_ts(min_reported_time_ntp)) log.info("test_resource_monitoring_recent: sample received, min_reported_time_millis=%s", int(min_reported_time_millis)) # finally verify that it is actually not older than the small multiple # of monitor_cycle_seconds plus some additional tolerance (which is # arbitrarily set here to 10 secs): lower_limit_millis = \ curr_time_millis - 1000 * (_MULT_INTERVAL * monitor_cycle_seconds + 10) self.assertGreaterEqual( min_reported_time_millis, lower_limit_millis, "min_reported_time_millis=%s must be >= %s. Diff=%s millis" % ( min_reported_time_millis, lower_limit_millis, min_reported_time_millis - lower_limit_millis)) finally: self._stop_resource_monitoring(recursion=False)
def test_ion_ts_and_ntp_conversion(self): sys_time = get_ion_ts() ntp_time = ion_ts_2_ntp(sys_time) sys2_time = ntp_2_ion_ts(ntp_time) self.assertEquals(sys_time, sys2_time)
def test_resource_monitoring_recent(self): # # https://jira.oceanobservatories.org/tasks/browse/OOIION-1372 # # Verifies that the requests for attribute values are always for # the most recent ones, meaning that the retrieved values should *not* # be older than a small multiple of the nominal monitoring rate, even # after a long period in non-monitoring state. # See ResourceMonitor._retrieve_attribute_values # # start this test as in test_resource_monitoring() self.test_resource_monitoring() # which completes right after stopping monitoring. We want that initial # start/stop-monitoring phase to make this test more comprehensive. self._assert_state(PlatformAgentState.COMMAND) # now, the rest of this test does the following: # - pick an attribute to use as a basis for the time parameters to # be used in the test # - wait for a while in the current non-monitoring mode # - re-enable monitoring # - wait for a sample to be published # - verify that new received data sample is "recent" # - stop monitoring # first, use an attribute (from the root platform being tested) with # a minimal monitoring rate, since that attribute should be reported # in a first sample received after re-enabling the monitoring. attr = None for attr_id, plat_attr in self._platform_attributes[ self.PLATFORM_ID].iteritems(): if attr is None or \ float(plat_attr['monitor_cycle_seconds']) < float(attr['monitor_cycle_seconds']): attr = plat_attr self.assertIsNotNone( attr, "some attribute expected to be defined for %r to " "actually proceed with this test" % self.PLATFORM_ID) attr_id = attr['attr_id'] monitor_cycle_seconds = attr['monitor_cycle_seconds'] log.info( "test_resource_monitoring_recent: using attr_id=%r: monitor_cycle_seconds=%s", attr_id, monitor_cycle_seconds) # sleep for twice the interval defining "recent": from ion.agents.platform.resource_monitor import _MULT_INTERVAL time_to_sleep = 2 * (_MULT_INTERVAL * monitor_cycle_seconds) log.info( "test_resource_monitoring_recent: sleeping for %s secs " "before resuming monitoring", time_to_sleep) sleep(time_to_sleep) # reset the variables associated with the _wait_for_a_data_sample call below: self._samples_received = [] self._async_data_result = AsyncResult() ################################################# # re-start monitoring and wait for new sample: log.info("test_resource_monitoring_recent: re-starting monitoring") self._start_resource_monitoring(recursion=False) # should also work with recursion to children but set recursion=False # to avoid wasting the extra time in this test. try: self._wait_for_a_data_sample() # get current time here (right after receiving sample) for comparison below: curr_time_millis = current_time_millis() # verify that the timestamp of the received sample is not too old. # For this, use the minimum of the reported timestamps: rdt = RecordDictionaryTool.load_from_granule( self._samples_received[0]) log.trace("test_resource_monitoring_recent: rdt:\n%s", rdt.pretty_print()) temporal_parameter_name = rdt.temporal_parameter times = rdt[temporal_parameter_name] log.trace("test_resource_monitoring_recent: times:\n%s", self._pp.pformat(times)) # minimum reported timestamp (note the NTP -> ION_time conversion): min_reported_time_ntp = min(times) min_reported_time_millis = float( ntp_2_ion_ts(min_reported_time_ntp)) log.info( "test_resource_monitoring_recent: sample received, min_reported_time_millis=%s", int(min_reported_time_millis)) # finally verify that it is actually not older than the small multiple # of monitor_cycle_seconds plus some additional tolerance (which is # arbitrarily set here to 10 secs): lower_limit_millis = \ curr_time_millis - 1000 * (_MULT_INTERVAL * monitor_cycle_seconds + 10) self.assertGreaterEqual( min_reported_time_millis, lower_limit_millis, "min_reported_time_millis=%s must be >= %s. Diff=%s millis" % (min_reported_time_millis, lower_limit_millis, min_reported_time_millis - lower_limit_millis)) finally: self._stop_resource_monitoring(recursion=False)