def aparam_set_mission(self, yaml_filename): """ Specifies mission to be executed. @param yaml_filename Mission definition """ log.debug('[mm] aparam_set_mission: yaml_filename=%s', yaml_filename) mission_loader = MissionLoader() mission_loader.load_mission_file(yaml_filename) self._agent.aparam_mission = mission_loader.mission_entries log.debug('[mm] aparam_set_mission: _ia_clients=\n%s', self._agent._pp.pformat(self._agent._ia_clients)) # get instrument IDs and clients for the valid running instruments: instruments = {} for (instrument_id, obj) in self._agent._ia_clients.iteritems(): if isinstance(obj, dict): # it's valid instrument. if instrument_id != obj.resource_id: log.error('[mm] aparam_set_mission: instrument_id=%s, ' 'resource_id=%s', instrument_id, obj.resource_id) instruments[obj.resource_id] = obj.ia_client self.mission_scheduler = MissionScheduler(self._agent, instruments, self._agent.aparam_mission) log.debug('[mm] aparam_set_mission: MissionScheduler created. entries=%s', self._agent.aparam_mission)
def test_simple_simulator_mission(self): """ Test the RSN OMS platform simulator with the SBE37_SIM instruments """ filename = "ion/agents/platform/test/mission_RSN_simulator1.yml" self.load_mission(yaml_filename=filename) log.debug('mission_entries=%s', self.mission.mission_entries) self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) self.missionSchedule.run_mission()
def test_shallow_profiler_mission(self): """ Test the Shallow Water Profiler mission """ filename = 'ion/agents/platform/test/mission_ShallowProfiler_simulated.yml' self.load_mission(yaml_filename=filename) # Setup the platform and instruments self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) # Start profiler event simulator and mission scheduler self.threads = [] self.threads.append(gevent.spawn(self.missionSchedule.run_mission)) # self.threads.append(gevent.spawn_later(30, SimulateShallowWaterProfilerEvents())) self.threads.append( gevent.spawn_later(120, self.simulate_profiler_events, 'stair_step')) gevent.joinall(self.threads)
def test_shallow_profiler_mission(self): """ Test the Shallow Water Profiler mission """ filename = 'ion/agents/platform/test/mission_ShallowProfiler_simulated.yml' self.load_mission(yaml_filename=filename) # Setup the platform and instruments self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) # Start profiler event simulator and mission scheduler self.threads = [] self.threads.append(gevent.spawn(self.missionSchedule.run_mission)) # self.threads.append(gevent.spawn_later(30, SimulateShallowWaterProfilerEvents())) self.threads.append(gevent.spawn_later(120, self.simulate_profiler_events, 'stair_step')) gevent.joinall(self.threads)
class MissionManager(object): """ Coordinating class for integration of mission execution with platform agent. """ def __init__(self, pa): """ @param pa The associated platform agent object to access the elements handled by this helper. """ self._agent = pa self._platform_id = pa._platform_id self._agent.aparam_mission = [] self._agent.aparam_set_mission = self.aparam_set_mission # TODO confirm appropriate mechanism to indicate mission to the agent def aparam_set_mission(self, yaml_filename): """ Specifies mission to be executed. @param yaml_filename Mission definition """ log.debug('[mm] aparam_set_mission: yaml_filename=%s', yaml_filename) mission_loader = MissionLoader() mission_loader.load_mission_file(yaml_filename) self._agent.aparam_mission = mission_loader.mission_entries log.debug('[mm] aparam_set_mission: _ia_clients=\n%s', self._agent._pp.pformat(self._agent._ia_clients)) # get instrument IDs and clients for the valid running instruments: instruments = {} for (instrument_id, obj) in self._agent._ia_clients.iteritems(): if isinstance(obj, dict): # it's valid instrument. if instrument_id != obj.resource_id: log.error('[mm] aparam_set_mission: instrument_id=%s, ' 'resource_id=%s', instrument_id, obj.resource_id) instruments[obj.resource_id] = obj.ia_client self.mission_scheduler = MissionScheduler(self._agent, instruments, self._agent.aparam_mission) log.debug('[mm] aparam_set_mission: MissionScheduler created. entries=%s', self._agent.aparam_mission) # TODO appropriate way to handle potential errors/exceptions in # methods below. Very ad hoc for the moment. def run_mission(self): try: self.mission_scheduler.run_mission() return None except Exception as ex: log.exception('[mm] run_mission') return ex def abort_mission(self): try: self.mission_scheduler.abort_mission() return None except Exception as ex: log.exception('[mm] abort_mission') return ex def kill_mission(self): try: self.mission_scheduler.kill_mission() return None except Exception as ex: log.exception('[mm] kill_mission') return ex
class TestSimpleMission(BaseIntTestPlatform, PyonTestCase): """ Test cases for the RSN OMS simulator, which is instantiated directly (ie., no connection to external simulator is involved). """ def _run_shutdown_commands(self, recursion=True): try: self._go_inactive(recursion) self._reset(recursion) finally: # attempt shutdown anyway self._shutdown(True) # NOTE: shutdown always with recursion=True def setup_platform_simulator_and_instruments(self): self._set_receive_timeout() # Create a platform in the test environment p_root = self._create_single_platform() # Create instruments and assign to platform for mission in self.mission.mission_entries: for instrument_id in mission['instrument_id']: # create only if not already created: if instrument_id not in self._setup_instruments: i_obj = self._create_instrument(instrument_id, start_port_agent=True) self._assign_instrument_to_platform(i_obj, p_root) # Start the platform self._start_platform(p_root) self.addCleanup(self._stop_platform, p_root) # self.addCleanup(self._run_shutdown_commands) self._instruments = {} self._instruments.update({self.PLATFORM_ID: self._pa_client}) # Now get instrument clients for each instrument for mission in self.mission.mission_entries: for instrument_id in mission['instrument_id']: instrument_device_id = self._setup_instruments[instrument_id]['instrument_device_id'] # Start a resource agent client to talk with each instrument agent. ia_client = ResourceAgentClient(instrument_device_id, process=FakeProcess()) # make a dictionary storing the instrument ids and client objects self._instruments.update({instrument_id: ia_client}) def get_mission_attachment(self, filename): """ Treat the mission file as if it were a platform attachment """ # read the file with open(filename, 'r') as rfile: content = rfile.read() # make an attachment attachment = IonObject(RT.Attachment, name="Example mission", description="Mission File", content=content, content_type="text/yml", keywords=["mission"], attachment_type=AttachmentType.ASCII) # Create a platform in the test environment p_root = self._create_single_platform() self.RR2.create_attachment(p_root['platform_device_id'], attachment) attachments, _ = self.RR.find_objects(p_root['platform_device_id'], PRED.hasAttachment, RT.Attachment, True) self.assertEqual(len(attachments), 1) a = self.RR.read_attachment(attachments[0], include_content=True) # Write contents of attached mission file to temp yaml file temp_file = 'temp_mission.yml' with open(temp_file, 'w') as wfile: wfile.write(a.content) self.load_mission(yaml_filename=temp_file) if os.path.isfile(temp_file): os.remove(temp_file) return p_root def simulate_profiler_events(self, profile_type): """ Simulate the Shallow Water profiler stair step mission """ event_publisher = EventPublisher(event_type="ResourceAgentResourceStateEvent") profiler_resource_id = 'FakeID' num_profiles = 2 def profiler_event_state_change(state, sleep_duration): """ Publish the state change event @param state the state entered by the driver. @param sleep_duration seconds to sleep for after event """ # Create event publisher. event_data = {'state': state} event_publisher.publish_event(event_type='ResourceAgentResourceStateEvent', origin=profiler_resource_id, **event_data) gevent.sleep(sleep_duration) def stair_step_simulator(): # Let's simulate a profiler stair step scenario seconds_between_steps = 60 num_steps = 2 # Start Mission profiler_event_state_change('StartMission', 1) # Going up profiler_event_state_change('StartingAscent', seconds_between_steps) for x in range(num_profiles): # Step up for down in range(num_steps): profiler_event_state_change('atStep', seconds_between_steps) profiler_event_state_change('StartingUp', 1) # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) # Start to descend profiler_event_state_change('StartingDescent', seconds_between_steps) # Arrive at floor profiler_event_state_change('atFloor', seconds_between_steps) profiler_event_state_change('MissionComplete', 1) def up_down_simulator(): # Let's simulate a profiler up-down scenario seconds_between_steps = 5 * 60 # Start Mission profiler_event_state_change('StartMission', 1) # Start ascent profiler_event_state_change('StartingAscent', seconds_between_steps) for x in range(num_profiles): # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) # Start to descend profiler_event_state_change('StartingDescent', seconds_between_steps) # Arrive at floor profiler_event_state_change('atFloor', seconds_between_steps) profiler_event_state_change('MissionComplete', 1) def simulator_error(): # Let's simulate a profiler up-down scenario seconds_between_steps = 60 # Start Mission profiler_event_state_change('StartMission', 1) # Start ascent profiler_event_state_change('StartingAscent', seconds_between_steps) # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) profiler_event_state_change('systemError', 1) if profile_type == 'stair_step': stair_step_simulator() else: up_down_simulator() def load_mission(self, yaml_filename='ion/agents/platform/test/mission_RSN_simulator1.yml'): """ Load and parse the mission file """ self.mission = MissionLoader(self._pa_client) self.mission.load_mission_file(yaml_filename) @skip("Deprecated... Use test_mission_manager instead") def test_simple_simulator_mission(self): """ Test the RSN OMS platform simulator with the SBE37_SIM instruments """ filename = "ion/agents/platform/test/mission_RSN_simulator1.yml" self.load_mission(yaml_filename=filename) log.debug('mission_entries=%s', self.mission.mission_entries) self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) self.missionSchedule.run_mission() @skip("Work in progress...") def test_shallow_profiler_mission(self): """ Test the Shallow Water Profiler mission """ filename = 'ion/agents/platform/test/mission_ShallowProfiler.yml' self.load_mission(yaml_filename=filename) # Setup the platform and instruments self.setup_platform_simulator_and_instruments() # Start profiler event simulator and mission scheduler self.threads = [] self.threads.append(gevent.spawn( MissionScheduler, self._pa_client, self._instruments, self.mission.mission_entries)) # self.threads.append(gevent.spawn_later(30, SimulateShallowWaterProfilerEvents())) self.threads.append(gevent.spawn_later(120, self.simulate_profiler_events, 'stair_step')) gevent.joinall(self.threads)
def test_simple_simulator_mission(self): # Dump mission file contents to IonObject filename = "ion/agents/platform/test/mission_RSN_simulator1.yml" with open(filename, 'r') as rfile: content = rfile.read() # make an attachment attachment = IonObject(RT.Attachment, name="Example mission", description="Mission File", content=content, content_type="text/yml", keywords=["mission"], attachment_type=AttachmentType.ASCII) # Create a platform in the test environment p_root = self._create_single_platform() self.RR2.create_attachment(p_root['platform_device_id'], attachment) attachments, _ = self.RR.find_objects(p_root['platform_device_id'], PRED.hasAttachment, RT.Attachment, True) self.assertEqual(len(attachments), 1) a = self.RR.read_attachment(attachments[0], include_content=True) # Write contents of attached mission file to temp yaml file temp_file = 'temp_mission.yml' with open(temp_file, 'w') as wfile: wfile.write(a.content) self.load_mission(yaml_filename=temp_file) self._set_receive_timeout() instruments = [] for missionIndex in range(len(self.mission.mission_entries)): instruments.append( self.mission.mission_entries[missionIndex]['instrument_id']) # p_root = self._set_up_single_platform_with_some_instruments(instruments) # for instr_key in instruments: # self.assertIn(instr_key, instruments_dict) # create and assign instruments: for instr_key in instruments: # create only if not already created: if instr_key in self._setup_instruments: i_obj = self._setup_instruments[instr_key] else: i_obj = self._create_instrument(instr_key, start_port_agent=True) self._assign_instrument_to_platform(i_obj, p_root) self._start_platform(p_root) self.addCleanup(self._stop_platform, p_root) self.addCleanup(self._run_shutdown_commands) self.missionSchedule = MissionScheduler(self._pa_client, self._setup_instruments, self.mission.mission_entries) if os.path.isfile(temp_file): os.remove(temp_file)
def _create_mission_scheduler(self, mission_id, mission_yml): """ - loads the mission - verifies instruments associated - gets exclusive access to those instruments - creates MissionScheduler @param mission_id @param mission_yml @return (mission_loader, mission_scheduler, instrument_objs) @raise Exception if no stable ID is found for an instrument; or the first exception while requesting exclusive access to a child instrument (in this case, all other successful such requests, if any, are reverted). """ log.debug('%r: [mm] _create_mission_scheduler: mission_id=%r', self._platform_id, mission_id) mission_loader = MissionLoader(self._agent) mission_loader.load_mission(mission_id, mission_yml) self._mission_entries = mission_loader.mission_entries if log.isEnabledFor(logging.DEBUG): log.debug('%r: [mm] _create_mission_scheduler: _ia_clients=\n%s', self._platform_id, self._agent._pp.pformat(self._agent._ia_clients)) # {stable_id: obj, ...} objects of valid running instruments: instrument_objs = {} for (instrument_id, obj) in self._agent._ia_clients.iteritems(): if isinstance(obj, dict): # dict means it's valid instrument. # get first "PRE:*" ID from obj.alt_ids: pres = [alt_id for alt_id in obj.alt_ids if alt_id.startswith('PRE:')] if not pres: raise Exception('%r: No stable ID found for instrument_id=%r. alt_ids=%s' % ( self._platform_id, instrument_id, obj.alt_ids)) stable_id = pres[0] log.debug('%r: [mm] _create_mission_scheduler: instrument_id=%r, stable_id=%r,' ' resource_id=%r', self._platform_id, instrument_id, stable_id, obj.resource_id) instrument_objs[stable_id] = obj # {stable_id: client, ...} dict for scheduler instruments_for_scheduler = dict((stable_id, obj.ia_client) for stable_id, obj in instrument_objs.iteritems()) mission_entries = mission_loader.mission_entries # get all involved instruments referenced in the mission: instrument_ids = set() for mission_entry in mission_entries: for instrument_id in mission_entry.get('instrument_id', []): if instrument_id in instrument_objs: instrument_ids.add(instrument_id) else: raise Exception('%r: No stable ID found for instrument_id=%r referenced' ' in mission, mission_id=%r' % (self._platform_id, instrument_id, mission_id)) # get exclusive access to those instruments. If any one fails, # rollback and raise that first exception: instrument_ids_ok = set() exception = None for instrument_id in instrument_ids: resource_id = instrument_objs[instrument_id].resource_id try: self._get_exclusive_access(instrument_id, resource_id, mission_id) instrument_ids_ok.add(instrument_id) except Exception as ex: exception = ex log.warn('%r: [xa] _create_mission_scheduler: exclusive access request to' ' resource_id=%r, instrument_id=%r failed: %s', self._platform_id, resource_id, instrument_id, exception) break if exception: if len(instrument_ids_ok): log.warn('%r: [xa] _create_mission_scheduler: reverting exclusive access to the resources: %s', self._platform_id, instrument_ids_ok) for instrument_id in instrument_ids_ok: resource_id = instrument_objs[instrument_id].resource_id try: self._remove_exclusive_access(instrument_id, resource_id, mission_id) except Exception as ex: # just log warning an continue log.warn('%r: [xa] exception while reverting exclusive access to resource_id=%r, ' 'instrument_id=%r: %s', self._platform_id, resource_id, instrument_id, ex) raise exception mission_scheduler = MissionScheduler(self._agent, instruments_for_scheduler, mission_entries) log.debug('%r: [mm] _create_mission_scheduler: MissionScheduler created. entries=%s', self._platform_id, mission_entries) return mission_loader, mission_scheduler, instrument_objs
class TestSimpleMission(BaseIntTestPlatform, PyonTestCase): """ Test cases for the RSN OMS simulator, which is instantiated directly (ie., no connection to external simulator is involved). """ def _run_shutdown_commands(self, recursion=True): try: self._go_inactive(recursion) self._reset(recursion) finally: # attempt shutdown anyway self._shutdown(True) # NOTE: shutdown always with recursion=True def setup_platform_simulator_and_instruments(self): self._set_receive_timeout() # Create a platform in the test environment p_root = self._create_single_platform() # Create instruments and assign to platform for mission in self.mission.mission_entries: for instrument_id in mission['instrument_id']: # create only if not already created: if instrument_id not in self._setup_instruments: i_obj = self._create_instrument(instrument_id, start_port_agent=True) self._assign_instrument_to_platform(i_obj, p_root) # Start the platform self._start_platform(p_root) self.addCleanup(self._stop_platform, p_root) # self.addCleanup(self._run_shutdown_commands) self._instruments = {} self._instruments.update({self.PLATFORM_ID: self._pa_client}) # Now get instrument clients for each instrument for mission in self.mission.mission_entries: for instrument_id in mission['instrument_id']: instrument_device_id = self._setup_instruments[instrument_id][ 'instrument_device_id'] # Start a resource agent client to talk with each instrument agent. ia_client = ResourceAgentClient(instrument_device_id, process=FakeProcess()) # make a dictionary storing the instrument ids and client objects self._instruments.update({instrument_id: ia_client}) def get_mission_attachment(self, filename): """ Treat the mission file as if it were a platform attachment """ # read the file with open(filename, 'r') as rfile: content = rfile.read() # make an attachment attachment = IonObject(RT.Attachment, name="Example mission", description="Mission File", content=content, content_type="text/yml", keywords=["mission"], attachment_type=AttachmentType.ASCII) # Create a platform in the test environment p_root = self._create_single_platform() self.RR2.create_attachment(p_root['platform_device_id'], attachment) attachments, _ = self.RR.find_objects(p_root['platform_device_id'], PRED.hasAttachment, RT.Attachment, True) self.assertEqual(len(attachments), 1) a = self.RR.read_attachment(attachments[0], include_content=True) # Write contents of attached mission file to temp yaml file temp_file = 'temp_mission.yml' with open(temp_file, 'w') as wfile: wfile.write(a.content) self.load_mission(yaml_filename=temp_file) if os.path.isfile(temp_file): os.remove(temp_file) return p_root def simulate_profiler_events(self, profile_type): """ Simulate the Shallow Water profiler stair step mission """ event_publisher = EventPublisher(event_type="OMSDeviceStatusEvent") num_profiles = 2 def profiler_event_state_change(state, sleep_duration): """ Publish the state change event @param state the state entered by the driver. @param sleep_duration seconds to sleep for after event """ # Create event publisher. event_data = {'sub_type': state} event_publisher.publish_event(event_type='OMSDeviceStatusEvent', origin='LJ01D', **event_data) gevent.sleep(sleep_duration) def stair_step_simulator(): # Let's simulate a profiler stair step scenario seconds_between_steps = 60 num_steps = 2 # Start Mission profiler_event_state_change('StartMission', 1) # Going up profiler_event_state_change('StartingAscent', seconds_between_steps) for x in range(num_profiles): # Step up for down in range(num_steps): profiler_event_state_change('atStep', seconds_between_steps) profiler_event_state_change('StartingUp', 1) # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) # Start to descend profiler_event_state_change('StartingDescent', seconds_between_steps) # Arrive at floor profiler_event_state_change('atFloor', seconds_between_steps) profiler_event_state_change('MissionComplete', 1) def up_down_simulator(): # Let's simulate a profiler up-down scenario seconds_between_steps = 5 * 60 # Start Mission profiler_event_state_change('StartMission', 1) # Start ascent profiler_event_state_change('StartingAscent', seconds_between_steps) for x in range(num_profiles): # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) # Start to descend profiler_event_state_change('StartingDescent', seconds_between_steps) # Arrive at floor profiler_event_state_change('atFloor', seconds_between_steps) profiler_event_state_change('MissionComplete', 1) def simulator_error(): # Let's simulate a profiler up-down scenario seconds_between_steps = 60 # Start Mission profiler_event_state_change('StartMission', 1) # Start ascent profiler_event_state_change('StartingAscent', seconds_between_steps) # Ascend to ceiling profiler_event_state_change('atCeiling', seconds_between_steps) profiler_event_state_change('systemError', 1) if profile_type == 'stair_step': stair_step_simulator() else: up_down_simulator() def load_mission( self, yaml_filename='ion/agents/platform/test/mission_RSN_simulator1.yml' ): """ Load and parse the mission file """ self.mission = MissionLoader('') self.mission.load_mission_file(yaml_filename) @skip("Deprecated... Use test_mission_manager instead") def test_simple_simulator_mission(self): """ Test the RSN OMS platform simulator with the SBE37_SIM instruments """ filename = "ion/agents/platform/test/mission_RSN_simulator1.yml" self.load_mission(yaml_filename=filename) log.debug('mission_entries=%s', self.mission.mission_entries) self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) self.missionSchedule.run_mission() @skip("Work in progress...") def test_shallow_profiler_mission(self): """ Test the Shallow Water Profiler mission """ filename = 'ion/agents/platform/test/mission_ShallowProfiler_simulated.yml' self.load_mission(yaml_filename=filename) # Setup the platform and instruments self.setup_platform_simulator_and_instruments() # Start Mission Scheduer self.missionSchedule = MissionScheduler(self._pa_client, self._instruments, self.mission.mission_entries) # Start profiler event simulator and mission scheduler self.threads = [] self.threads.append(gevent.spawn(self.missionSchedule.run_mission)) # self.threads.append(gevent.spawn_later(30, SimulateShallowWaterProfilerEvents())) self.threads.append( gevent.spawn_later(120, self.simulate_profiler_events, 'stair_step')) gevent.joinall(self.threads)