def check(self, task, # Task to check classifiers, # List of the classifiers check_schedule=True # Keep/disregard time-related limits ): """Determine if a task can be run, return true/false, a list of lists (see below) and a string of diagnostics. The list of lists contains one list per application passed, with that list containing descriptions of the limits passed for that application. (See the code in the top-level limit processor to see how this is used.) """ diags = [] pass_count = 0 limits_passed = [] # Run through each application, stopping when one passes or a # failed one has stop-on-failure for application in self.applications: # See if the classifier applies try: classifier = application['classifier'] if classifier not in classifiers: continue except KeyError: # No classifier always applies pass # Description diags.append("Application: %s" % application.get('description', "(No description)")) passed, forced_stop, check_limits_passed, app_diags \ = self.__check_application(application, task, classifiers, check_schedule) diags.extend([ indent(diag) for diag in app_diags]) if not passed and forced_stop: diags.append(" Failed - Stop Forced") return False, [], '\n'.join(diags) if passed: limits_passed.append(check_limits_passed) pass_count += 1 if pass_count > 0: return True, limits_passed, '\n'.join(diags) else: return False, [], '\n'.join(diags)
def process(self, task, hints, rewrite=True, prioritize=False): """Evaluate a proposed task against the full limit set. If the task has no 'run_schedule' section it will be assumed that is being evaluated on all other parameters except when it runs. (This will be used for restricting submission of new tasks.) Arguments: task - The proposed task, with run_schedule if there's a run time hints - A hash of the hints to be used in identification rewrite - True if the rewriter should be applied prioritize - True to prioritize the task Returns a tuple containing: passed - True if the proposed task passed the limits applied limits - A list of the limits that passed diags - A textual summary of how the conclusion was reached task - The task, after rewriting or None if unchanged priority - Integer priority or None of not calculated """ if self.inert: return True, [], "No limits were applied", None, None # TODO: Should this be JSON, or is text sufficient? diags = [] if hints is not None and len(hints) > 0: diags.append("Hints:") diags.extend([ pscheduler.indent("%s: %s" % (item, str(hints[item]))) for item in sorted(hints) ]) # Everything we know about what's being proposed proposal = { "hints": hints, "task": task, } # # Identification # identifications = self.identifiers.identities(hints) if not identifications: diags.append("Made no identifications.") return False, [], '\n'.join(diags), None, None diags.append("Identified as %s" % (', '.join(identifications))) # # Classification # classifications = self.classifiers.classifications(identifications) if not classifications: diags.append("Made no classifications.") return False, [], '\n'.join(diags), None, None diags.append("Classified as %s" % (', '.join(classifications))) check_schedule='run_schedule' in task re_new_task = None # # Rewriting # if self.rewriter is not None and rewrite: try: re_changed, re_new_task, re_diags \ = self.rewriter(proposal, classifications) except Exception as ex: return False, [], "Error while rewriting: %s" % (str(ex)), None, None if re_changed: diags.append("Rewriter made changes:") if len(re_diags): diags += map(lambda s: " " + s, re_diags) else: diags.append(" (Not enumerated)") task = re_new_task # # Applications # passed, app_limits_passed, app_diags \ = self.applications.check(proposal, classifications, check_schedule) diags.append(app_diags) diags.append("Proposal %s limits" % ("meets" if passed else "does not meet")) # If any of the passed applications had no task limits, there # should be no limits placed on the run. unlimited = len(app_limits_passed) == 0 \ or min([ len(item) for item in app_limits_passed ]) == 0 # # Priorities # if prioritize and passed and self.prioritizer is not None: try: priority, pri_diags = self.prioritizer(task, classifications) except Exception as ex: return False, [], "Error determining priority: %s" % (str(ex)), None, None if priority is None: return False, [], "Prioritizer produced no result", None, None requested_priority = task.get("priority", None) if requested_priority is not None: requested_message = " %d requested," % (requested_priority) else: requested_message ="" diags.append("Priority%s set at %d%s" % ( requested_message, priority, ":" if len(pri_diags) else ".")) if len(pri_diags): diags += map(lambda s: " " + s, pri_diags) else: priority = 0 diags.append("Priority set to default of %d" % (priority)) return passed, \ [] if (unlimited or not passed) else app_limits_passed, \ '\n'.join(diags), \ re_new_task, \ priority
def process(self, task, hints, rewrite=True): """Evaluate a proposed task against the full limit set. If the task has no 'schedule' section it will be assumed that is being evaluated on all other parameters except when it runs. (This will be used for restricting submission of new tasks.) Arguments: task - The proposed task hints - A hash of the hints to be used in identification rewrite - True if the rewriter should be applied Returns a tuple containing: passed - True if the proposed task passed the limits applied limits - A list of the limits that passed diags - A textual summary of how the conclusion was reached task - The task, after rewriting or None if unchanged """ if self.inert: return True, [], "No limits were applied", None # TODO: Should this be JSON, or is text sufficient? diags = [] if hints is not None and len(hints) > 0: diags.append("Hints:") diags.extend([ pscheduler.indent("%s: %s" % (item, str(hints[item]))) for item in sorted(hints) ]) identifications = self.identifiers.identities(hints) if not identifications: diags.append("Made no identifications.") return False, [], '\n'.join(diags), None diags.append("Identified as %s" % (', '.join(identifications))) classifications = self.classifiers.classifications(identifications) if not classifications: diags.append("Made no classifications.") return False, [], '\n'.join(diags), None diags.append("Classified as %s" % (', '.join(classifications))) check_schedule = 'schedule' in task re_new_task = None if self.rewriter is not None and rewrite: try: re_changed, re_new_task, re_diags \ = self.rewriter(task, classifications) except pscheduler.JQRuntimeError as ex: return False, [], "Error while rewriting: %s" % (str(ex)), None if re_changed: diags.append("Rewriter made changes:") if len(re_diags): diags += map(lambda s: " " + s, re_diags) else: diags.append(" (Not enumerated)") task = re_new_task passed, app_limits_passed, app_diags \ = self.applications.check(task["test"], classifications, check_schedule) diags.append(app_diags) diags.append("Proposal %s limits" % ("meets" if passed else "does not meet")) # If any of the passed applications had no task limits, there # should be no limits placed on the run. unlimited = len(app_limits_passed) == 0 \ or min([ len(item) for item in app_limits_passed ]) == 0 return passed, \ [] if (unlimited or not passed) else app_limits_passed, \ '\n'.join(diags), \ re_new_task