From e9a7cca081bc68502cffd47c3d103d83a57534c9 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 15 Feb 2017 14:53:13 +0100 Subject: [PATCH 1/3] Event Script plugin This is an event plugin that executes a script specified in the job parameters. --- Custom/events/EventScript/EventScript.param | 9 + Custom/events/EventScript/EventScript.py | 187 ++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 Custom/events/EventScript/EventScript.param create mode 100644 Custom/events/EventScript/EventScript.py diff --git a/Custom/events/EventScript/EventScript.param b/Custom/events/EventScript/EventScript.param new file mode 100644 index 0000000..b7c666c --- /dev/null +++ b/Custom/events/EventScript/EventScript.param @@ -0,0 +1,9 @@ +[State] +Type=Enum +Items=Global Enabled;Opt-In;Disabled +Category=Options +CategoryOrder=0 +CategoryIndex=0 +Label=State +Default=Disabled +Description=How this event plug-in should respond to events. If Global, all jobs and slaves will trigger the events for this plugin. If Opt-In, jobs and slaves can choose to trigger the events for this plugin. If Disabled, no events are triggered for this plugin. diff --git a/Custom/events/EventScript/EventScript.py b/Custom/events/EventScript/EventScript.py new file mode 100644 index 0000000..cd3f3fa --- /dev/null +++ b/Custom/events/EventScript/EventScript.py @@ -0,0 +1,187 @@ +import sys +import os +import traceback + +import Deadline.Events + + +def GetDeadlineEventListener(): + return EventScriptListener() + + +def CleanupDeadlineEventListener(eventListener): + eventListener.Cleanup() + + +class EventScriptListener(Deadline.Events.DeadlineEventListener): + + def __init__(self): + self.OnJobSubmittedCallback += self.OnJobSubmitted + self.OnJobStartedCallback += self.OnJobStarted + self.OnJobFinishedCallback += self.OnJobFinished + self.OnJobRequeuedCallback += self.OnJobRequeued + self.OnJobFailedCallback += self.OnJobFailed + self.OnJobSuspendedCallback += self.OnJobSuspended + self.OnJobResumedCallback += self.OnJobResumed + self.OnJobPendedCallback += self.OnJobPended + self.OnJobReleasedCallback += self.OnJobReleased + self.OnJobDeletedCallback += self.OnJobDeleted + self.OnJobErrorCallback += self.OnJobError + self.OnJobPurgedCallback += self.OnJobPurged + + self.OnHouseCleaningCallback += self.OnHouseCleaning + self.OnRepositoryRepairCallback += self.OnRepositoryRepair + + self.OnSlaveStartedCallback += self.OnSlaveStarted + self.OnSlaveStoppedCallback += self.OnSlaveStopped + self.OnSlaveIdleCallback += self.OnSlaveIdle + self.OnSlaveRenderingCallback += self.OnSlaveRendering + self.OnSlaveStartingJobCallback += self.OnSlaveStartingJob + self.OnSlaveStalledCallback += self.OnSlaveStalled + + self.OnIdleShutdownCallback += self.OnIdleShutdown + self.OnMachineStartupCallback += self.OnMachineStartup + self.OnThermalShutdownCallback += self.OnThermalShutdown + self.OnMachineRestartCallback += self.OnMachineRestart + + def Cleanup(self): + del self.OnJobSubmittedCallback + del self.OnJobStartedCallback + del self.OnJobFinishedCallback + del self.OnJobRequeuedCallback + del self.OnJobFailedCallback + del self.OnJobSuspendedCallback + del self.OnJobResumedCallback + del self.OnJobPendedCallback + del self.OnJobReleasedCallback + del self.OnJobDeletedCallback + del self.OnJobErrorCallback + del self.OnJobPurgedCallback + + del self.OnHouseCleaningCallback + del self.OnRepositoryRepairCallback + + del self.OnSlaveStartedCallback + del self.OnSlaveStoppedCallback + del self.OnSlaveIdleCallback + del self.OnSlaveRenderingCallback + del self.OnSlaveStartingJobCallback + del self.OnSlaveStalledCallback + + del self.OnIdleShutdownCallback + del self.OnMachineStartupCallback + del self.OnThermalShutdownCallback + del self.OnMachineRestartCallback + + def run_script(self, *args): + + try: + job = args[1] + script = job.GetJobExtraInfoKeyValueWithDefault("EventScript", "") + + # Make arguments available to script with sys.argv + sys.argv = args + + # Add script directory to sys.path + sys.path.append(os.path.dirname(script)) + + # Execute script + execfile(script) + except: + print traceback.format_exc() + + def OnJobSubmitted(self, job): + + self.run_script("OnJobSubmitted", job) + + def OnJobStarted(self, job): + + self.run_script("OnJobStarted", job) + + def OnJobFinished(self, job): + + self.run_script("OnJobFinished", job) + + def OnJobRequeued(self, job): + + self.run_script("OnJobRequeued", job) + + def OnJobFailed(self, job): + + self.run_script("OnJobFailed", job) + + def OnJobSuspended(self, job): + + self.run_script("OnJobSuspended", job) + + def OnJobResumed(self, job): + + self.run_script("OnJobResumed", job) + + def OnJobPended(self, job): + + self.run_script("OnJobPended", job) + + def OnJobReleased(self, job): + + self.run_script("OnJobReleased", job) + + def OnJobDeleted(self, job): + + self.run_script("OnJobDeleted", job) + + def OnJobError(self, job, task, report): + + self.run_script("OnJobError", job, task, report) + + def OnJobPurged(self, job): + + self.run_script("OnJobPurged", job) + + def OnHouseCleaning(self): + + self.run_script("OnHouseCleaning") + + def OnRepositoryRepair(self, job): + + self.run_script("OnRepositoryRepair", job) + + def OnSlaveStarted(self, job): + + self.run_script("OnSlaveStarted", job) + + def OnSlaveStopped(self, job): + + self.run_script("OnSlaveStopped", job) + + def OnSlaveIdle(self, job): + + self.run_script("OnSlaveIdle", job) + + def OnSlaveRendering(self, slaveName, job): + + self.run_script("OnSlaveRendering", job, slaveName) + + def OnSlaveStartingJob(self, slaveName, job): + + self.run_script("OnSlaveStartingJob", job, slaveName) + + def OnSlaveStalled(self, slaveName, job): + + self.run_script("OnSlaveStalled", job, slaveName) + + def OnIdleShutdown(self, job): + + self.run_script("OnIdleShutdown", job) + + def OnMachineStartup(self, job): + + self.run_script("OnMachineStartup", job) + + def OnThermalShutdown(self, job): + + self.run_script("OnThermalShutdown", job) + + def OnMachineRestart(self, job): + + self.run_script("OnMachineRestart", job) From 4029e7890078661081b51368d266a645199d4a5f Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 15 Feb 2017 18:35:10 +0100 Subject: [PATCH 2/3] Fix EventScript print statement. --- Custom/events/EventScript/EventScript.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Custom/events/EventScript/EventScript.py b/Custom/events/EventScript/EventScript.py index cd3f3fa..3d002aa 100644 --- a/Custom/events/EventScript/EventScript.py +++ b/Custom/events/EventScript/EventScript.py @@ -88,7 +88,7 @@ def run_script(self, *args): # Execute script execfile(script) except: - print traceback.format_exc() + print(traceback.format_exc()) def OnJobSubmitted(self, job): From cc19f0bb9a46f26c3104996d0e1768afdd181ba4 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 15 Feb 2017 18:35:21 +0100 Subject: [PATCH 3/3] Add EventScript README. --- Custom/events/EventScript/README.md | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Custom/events/EventScript/README.md diff --git a/Custom/events/EventScript/README.md b/Custom/events/EventScript/README.md new file mode 100644 index 0000000..ba2ea4c --- /dev/null +++ b/Custom/events/EventScript/README.md @@ -0,0 +1,35 @@ +# EventScript.py + +An event plugin that executes an external script. + +The plugin gets the path to the external script from the jobs extra info, specifically if "EventScript" is specified as a key/value member. + +``` +ExtraInfoKeyValue1=EventScript=path/to/script.py +``` + +The event plugin also adds the direcotory of the script to ```sys.path```, so relative imports can be used. + +The arguments passed that is normally passed to an event plugin are stored in ```sys.argv```. These arguments vary in length depending the event, but as a minimum will always have the name of the event and the job object. + +Example of an external script printing all the arguments available. +```python +import sys + + +def main(): + + event_name = sys.argv[0] + print("Event Name: {0}".format(event_name)) + + job = sys.argv[1] + print("Job Object: {0}".format(job)) + + print("Other arguments: {0}".format(sys.argv[1:])) + +main() +``` + +Since event plugin execute the script in the same process, you import any Deadline related modules. + +Lastly if anything fails a stracktrace will be printed and available in the job reports.