def test_node_exclusive(self): # the node_exclusive constraint is used to ensure multiple processes # of the same "kind" each get a VM exclusive of each other. Other # processes may run on these VMs, just not processes with the same # node_exclusive tag. Since we cannot directly query the contents # of each node in this test, we prove the capability by scheduling # processes one by one and checking their state. # verifies L4-CI-CEI-RQ121 # verifies L4-CI-CEI-RQ57 # first off, setUp() created a single node and eeagent. # We schedule two processes with the same "abc" node_exclusive # tag. Since there is only one node, the first process should run # and the second should be queued. process_target = ProcessTarget(execution_engine_id="engine1") process_target.node_exclusive = "abc" process_schedule = ProcessSchedule() process_schedule.queueing_mode = ProcessQueueingMode.ALWAYS process_schedule.target = process_target pid1 = self.pd_cli.create_process(self.process_definition_id) self.waiter.start() self.pd_cli.schedule_process(self.process_definition_id, process_schedule, process_id=pid1) self.waiter.await_state_event(pid1, ProcessStateEnum.RUNNING) pid2 = self.pd_cli.create_process(self.process_definition_id) self.pd_cli.schedule_process(self.process_definition_id, process_schedule, process_id=pid2) self.waiter.await_state_event(pid2, ProcessStateEnum.WAITING) # now demonstrate that the node itself is not full by launching # a third process without a node_exclusive tag -- it should start # immediately process_target.node_exclusive = None pid3 = self.pd_cli.create_process(self.process_definition_id) self.pd_cli.schedule_process(self.process_definition_id, process_schedule, process_id=pid3) self.waiter.await_state_event(pid3, ProcessStateEnum.RUNNING) # finally, add a second node to the engine. pid2 should be started # since there is an exclusive "abc" node free. node2_id = uuid.uuid4().hex self._send_node_state("engine1", node2_id) self._start_eeagent(node2_id) self.waiter.await_state_event(pid2, ProcessStateEnum.RUNNING) # kill the processes for good self.pd_cli.cancel_process(pid1) self.waiter.await_state_event(pid1, ProcessStateEnum.TERMINATED) self.pd_cli.cancel_process(pid2) self.waiter.await_state_event(pid2, ProcessStateEnum.TERMINATED) self.pd_cli.cancel_process(pid3) self.waiter.await_state_event(pid3, ProcessStateEnum.TERMINATED)
def _get_process_schedule(**kwargs): queueing_mode = kwargs.get('queueing_mode') restart_mode = kwargs.get('restart_mode') execution_engine_id = kwargs.get('execution_engine_id') node_exclusive = kwargs.get('node_exclusive') constraints = kwargs.get('constraints') process_schedule = ProcessSchedule() if queueing_mode is not None: try: process_schedule.queueing_mode = ProcessQueueingMode._value_map[queueing_mode] except KeyError: msg = "%s is not a known ProcessQueueingMode" % (queueing_mode) raise BadRequest(msg) if restart_mode is not None: try: process_schedule.restart_mode = ProcessRestartMode._value_map[restart_mode] except KeyError: msg = "%s is not a known ProcessRestartMode" % (restart_mode) raise BadRequest(msg) else: # if restart mode isn't specified, use NEVER. HA Agent itself will reschedule failures. process_schedule.restart_mode = ProcessRestartMode.NEVER target = ProcessTarget() if execution_engine_id is not None: target.execution_engine_id = execution_engine_id if node_exclusive is not None: target.node_exclusive = node_exclusive if constraints is not None: target.constraints = constraints process_schedule.target = target return process_schedule
def schedule_process(self, upid, definition_id, configuration=None, subscribers=None, constraints=None, queueing_mode=None, restart_mode=None, execution_engine_id=None, node_exclusive=None): definition = self.real_client.read_process_definition(definition_id) self.event_pub.publish_event(event_type="ProcessLifecycleEvent", origin=definition.name, origin_type="DispatchedHAProcess", state=ProcessStateEnum.RUNNING) create_upid = self.real_client.create_process(definition_id) process_schedule = ProcessSchedule() if queueing_mode is not None: try: process_schedule.queueing_mode = ProcessQueueingMode._value_map[queueing_mode] except KeyError: msg = "%s is not a known ProcessQueueingMode" % (queueing_mode) raise BadRequest(msg) if restart_mode is not None: try: process_schedule.restart_mode = ProcessRestartMode._value_map[restart_mode] except KeyError: msg = "%s is not a known ProcessRestartMode" % (restart_mode) raise BadRequest(msg) target = ProcessTarget() if execution_engine_id is not None: target.execution_engine_id = execution_engine_id if node_exclusive is not None: target.node_exclusive = node_exclusive if constraints is not None: target.constraints = constraints process_schedule.target = target sched_pid = self.real_client.schedule_process(definition_id, process_schedule, configuration=configuration, process_id=create_upid) proc = self.real_client.read_process(sched_pid) self._associate_process(proc) dict_proc = {'upid': proc.process_id, 'state': self.state_map.get(proc.process_state, self.unknown_state), } return dict_proc