# Monitor Scripts¶

## Overview¶

There are several different types of Monitor scripts available. While the large majority of the ones shipping with Deadline are Submission Scripts used to submit new Jobs to the farm, the Monitor has the capability of running utility scripts in the context of specific Jobs, Tasks, Slaves, Limits, or even Reports.

Below, we go into more detail for each of the different types of Scripts, and how to create your own.

## Scripting Reference¶

As with all other Deadline scripts, Monitor scripts use Python 2.7, which is supported using Python for .NET. This means that in addition to typical cPython modules, Python for .NET allows your scripts to make use of .NET Libraries, and Deadline’s own internal functions.

Particular functions of note relevant to Monitor Scripting can be found in the aforementioned Scripting Reference, under the following sections:

It can also be very helpful when developing your own Monitor Script to take a look at how our built-in Monitor Scripts of that type are structured.

## General Script Template¶

We follow a fairly specific template when making any new built-in Monitor scripts. The template is loosely as follows:

• Define your __main__ function: This is the function that Deadline will call when invoking your script. This is mandatory, and your script will generate an error if it isn’t done.

def __main__( *args ):
#Replace "pass"
pass

• Build the submission UI: Typically done in the __main__ function by creating a ScriptDialog object, and adding controls to it. Each control’s name must be unique, so that each control can be identified properly. You can also set the dialog’s size (if not using a grid layout), the row and column (if using a grid layout), title, and a few other settings. For more details, see the ScriptDialog and ScriptControl sections of the Reference Manual. For an example on how to use the grid layout see the Grid Layout Example Script documentation.

• Define and Load Sticky Settings: Sticky settings are settings that persist after the dialog has been closed. They are defined by creating a string array that contains the names of the controls for which you want the settings to persist. After defining them, you can load them by calling the ‘LoadSettings’ function of your ScriptDialog.
• Show the Dialog: The last thing you should do in your __main__ function is to show your ScriptDialog, by using its ‘ShowDialog’ function.
• Define Your Functions: Specify any functions that may be used by your script. These could just be helper functions, or event handlers that do stuff when UI values are modified.

Note that you don’t necessarily need to follow this template, but the closer you stick to it, the more examples you’ll have to draw on.

## Monitor Scripts¶

There are many different types of scripts you can write for the Monitor, which are listed below. It is recommended that these scripts be created in the ‘custom’ folder in the Repository to avoid issues when upgrading your Repository in the future. See the Scripting Overview documentation for more information on the ‘custom’ folder in the Repository and how it’s used.

When a monitor script is executed the log will show where the script is being loaded from.

### Submission Scripts¶

Submission Scripts are used to create custom Submission dialogs, and ultimately submit new Jobs to Deadline. They are located in the ‘Submit’ menu of the Monitor’s main menu bar, as well as the ‘Submit’ menu in the the Launcher. Creating your own custom Submission dialog is quite simple, and the process is described below.

To create new submission scripts, simply navigate to the ‘custom\scripts\Submission’ folder in your Repository. Then, create a new Python file named ‘MySubmissionScript.py’, where ‘MySubmissionScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### General Scripts¶

General scripts are used to perform any sort of custom action by selecting them from the Monitor’s (or Launcher’s) ‘Scripts’ menu. Under the hood, there technically isn’t anything different between General and Submission scripts. The only real difference is that they show up under different menus, which is just to help keep scripts semantically separated.

To create new General scripts, simply navigate to the ‘custom\scripts\General’ folder in your Repository. Then, create a new Python file named ‘MyGeneralScript.py’, where ‘MyGeneralScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Job Scripts¶

Job Scripts are typically used to modify or to perform actions on a selected Job in the Monitor. They can be accessed by right-clicking an existing Job in the Job Panel, under the ‘Scripts’ sub-menu.

To create new Job scripts, simply navigate to the ‘custom\scripts\Jobs’ folder in your Repository. Then, create a new Python file named ‘MyJobScript.py’, where ‘MyJobScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

Task Scripts are typically used to modify or to perform actions on a selected Task in the Monitor. They can be accessed by right-clicking an existing Task in the Task Panel, under the ‘Scripts’ sub-menu.

To create new Task scripts, simply navigate to the ‘custom\scripts\Tasks’ folder in your Repository. Then, create a new Python file named ‘MyTaskScript.py’, where ‘MyTaskScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Slave Scripts¶

Slave Scripts are typically used to modify or to perform actions on a selected Slave in the Monitor. They can be accessed by right-clicking an existing Slave in the Slave Panel, under the ‘Scripts’ sub-menu.

To create new Slave scripts, simply navigate to the ‘custom\scripts\Slaves’ folder in your Repository. Then, create a new Python file named ‘MySlaveScript.py’, where ‘MySlaveScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Pulse Scripts¶

Pulse Scripts are typically used to modify or to perform actions on a selected Pulse in the Monitor. They can be accessed by right-clicking an existing Pulse in the Pulse Panel, under the ‘Scripts’ sub-menu.

To create new Pulse scripts, simply navigate to the ‘custom\scripts\Pulse’ folder in your Repository. Then, create a new Python file named ‘MyPulseScript.py’, where ‘MyPulseScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Balancer Scripts¶

Balancer Scripts are typically used to modify or to perform actions on a selected Balancer in the Monitor. They can be accessed by right-clicking an existing Balancer in the Balancer Panel, under the ‘Scripts’ sub-menu.

To create new Balancer scripts, simply navigate to the ‘custom\scripts\Balancer’ folder in your Repository. Then, create a new Python file named ‘MyBalancerScript.py’, where ‘MyBalancerScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Limit Scripts¶

Limit Scripts are typically used to modify or to perform actions on selected Limits in the Monitor. They can be accessed by right-clicking an existing Limit in the Pulse Panel, under the ‘Scripts’ sub-menu.

To create new Limit scripts, simply navigate to the ‘custom\scripts\Limits’ folder in your Repository. Then, create a new Python file named ‘MyLimitScript.py’, where ‘MyLimitScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Job Report Scripts¶

Job Report Scripts are typically used to modify or to perform actions on selected Job Reports in the Monitor. They can be accessed by right-clicking an existing Job Report in the Job Report Panel, under the ‘Scripts’ sub-menu.

To create new Job Report scripts, simply navigate to the ‘custom\scripts\JobReports’ folder in your Repository. Then, create a new Python file named ‘MyJobReportScript.py’, where ‘MyJobReportScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

### Slave Report Scripts¶

Slave Report Scripts are typically used to modify or to perform actions on selected Slave Reports in the Monitor. They can be accessed by right-clicking an existing Slave Report in the Slave Report Panel, under the ‘Scripts’ sub-menu.

To create new Slave Report scripts, simply navigate to the ‘custom\scripts\SlaveReports’ folder in your Repository. Then, create a new Python file named ‘MySlaveReportScript.py’, where ‘MySlaveReportScript’ is the name of your new script.

Once created, you can follow the template outlined above in the General Script Template section to build up your script.

## Customizing Script Display¶

As with any built-in script, once you’ve created your new Monitor Script you can change its Display Name, Keyboard Shortcut, Icon, and its position within the menu in the Repository Configuration.

You can also control who can see (and use) your Submission Script through by tweaking its access level in User Management. It is probably a good idea to disable access to it for most users until you have your new script in working order.

## Grid Layout Example Script¶

Grid layouts allow your script dialog to dynamically resize its contents to fit the the size of the dialog. Below are some examples of how to use the new grid layout to build a script dialog.

First you must create a ScriptDialog object and start a grid. Once all controls have been added you must end the grid

dg = DeadlineScriptDialog()

#...
#Added controls go here
#...
dg.EndGrid()


Once you start a grid you can add controls to it by row and column. There is no need to specify how many rows or columns you want the grid to have, just specify the row and column where you want the control to be and the grid will grow to accommodate. Here is an example of adding a label and a text field to the dialog in the same row.

dg.AddGrid()
dg.AddControlToGrid("Label1", "LabelControl", "I'm a label.", 0,0, "A tooltip", False)
dg.AddControlToGrid( "TextBox1", "TextControl", "", 0, 1 )

dg.EndGrid()


Here is an example of what this dialog would look like:

It is not possible to specify the size of the controls you want to add to the grid, however it is also not necessary to do so. The contents of the grid(s) will automatically adjust themselves to share the size of the dialog. If you want certain elements to not grow within a row you can set the “expand” property to be disabled. If you want a control to take more space you can set the control span multiple rows or columns using “rowSpan” and “colSpan”, respectively. By default controls have “expand” set and have their “colSpan” and “rowSpan” properties set to 1.

This is an example of a dialog with two rows and four columns. The first row contains a label in the first column and is set to not grow any bigger than it needs to and a text control that spans the next 3 columns and is allowed to grow. The second row contains three labels that are not allowed to grow in the first three columns and a text control in the fourth column that can grow as needed.

dg.AddGrid()
"L1", "LabelControl", "I'm a label.", 0,0, "A tooltip", expand=False)
"TextBox1", "TextControl", "", 0, 1, colSpan=3)

"L2", "LabelControl", "I'm another label.", 1,0, "A tooltip", expand=False)
"L3", "LabelControl", "I'm another label.", 1,1, "A tooltip", expand=False)
"L4", "LabelControl", "I'm another label.", 1,2, "A tooltip", expand=False)
"TextBox2", "TextControl", "", 1, 3)

dg.EndGrid()


Here is an example of what this dialog would look like:

When you expand the dialog horizontally, only the text controls will grow in the above example. Nothing will grow, other than the dialog itself, when expanding vertically. Note that if you set all controls in a row to not expand that this will cause the cells in the grid that the controls are in to expand without allowing any of the controls to expand with it. This will result in the dialog losing its layout when it is expanded.

Here is an example of what this dialog would look like expanded horizontally:

Here is an example of what this dialog would look like expanded vertically:

Here is an example of what the dialog would look like expanded horizontally if all controls had “expand=False” set.

If you want to space controls out in the grid you can use labels filled with white space, or you can use horizontal spacers. Here is an example of adding two buttons to a dialog and keeping them to the far right of the dialog.

dg.AddGrid()
dg.AddHorizontalSpacerToGrid( "DummyLabel", 0, 0 )

"Ok", "ButtonControl", "OK", 0, 1, expand=False )
ok.ValueModified.connect(OkButtonPressed)

"Cancel", "ButtonControl", "Cancel", 0, 2, expand=False )
cancel.ValueModified.connect(CancelButtonPressed)
dg.EndGrid()


Here is an example of what this dialog will look like when expanded horizontally:

All together, here is an example of a basic script dialog using grid layouts.

from DeadlineUI.Controls.Scripting.DeadlineScriptDialog import DeadlineScriptDialog

########################################################################
## Globals
########################################################################
dg = None

########################################################################
## Main Function Called By Deadline
########################################################################
def __main__( *args ):
global dg

dg.SetTitle( "Example Deadline Script" )

"L1", "LabelControl", "I'm a label.", 0,0, "A tooltip", expand=False)
"TextBox1", "TextControl", "", 0, 1, colSpan=3)

"L2", "LabelControl", "I'm another label.", 1,0, "A tooltip", expand=False)
"L3", "LabelControl", "I'm another label.", 1,1, "A tooltip", expand=False)
"L4", "LabelControl", "I'm another label.", 1,2, "A tooltip", expand=False)
"TextBox2", "TextControl", "", 1, 3)

dg.EndGrid()

#Adds an OK and Cancel button to the dialog
dg.AddHorizontalSpacerToGrid( "DummyLabel", 0, 0 )

"Ok", "ButtonControl", "OK", 0, 1, expand=False )
ok.ValueModified.connect(OkButtonPressed)

"Cancel", "ButtonControl", "Cancel", 0, 2, expand=False )
cancel.ValueModified.connect(CancelButtonPressed)
dg.EndGrid()

dg.ShowDialog( True )

def CloseDialog():
global dg

dg.CloseDialog()

def CancelButtonPressed():
CloseDialog()

def OkButtonPressed( *args ):
global dg

dg.ShowMessageBox( "You pressed the OK button.", "Button Pressed" )


Here is what this dialog looks like:

## Migrating Scripts from Deadline 5¶

Some changes were made to the Scripting API in Deadline 6, which means that Deadline 6 and later are NOT backward compatible with scripts written for Deadline 5. However, migrating your scripts over is relatively straightforward, and this guide will walk you through the API changes so that you can update your scripts as necessary.

### Global Functions¶

The globally defined functions are no longer available. See the Migrating Scripts From Deadline 5 section in the Scripting Overview documentation for more information, including replacement functions.

### User Interface¶

If you are creating a user interface using the ScriptDialog object, you can no longer get an instance of it from DeadlineScriptEngine using the following:

scriptDialog = DeadlineScriptEngine.GetScriptDialog()


Instead, you need to import the DeadlineScriptDialog class, and use its constructor to create an instance:

from DeadlineUI.Controls.Scripting.DeadlineScriptDialog import DeadlineScriptDialog
...


Another change is how the ValueModifed event handlers are hooked up for the ScriptDialog controls. For example, this is how the event was hooked up in Deadline 5:

compBox = scriptDialog.AddControl(
"CompBox", "TextControl", "", dialogWidth-labelWidth-24,-1)
compBox.ValueModified += CompChanged


Now, because the ScriptDialog object is a Qt object, you need to use the connect function to hook up events:

compBox = scriptDialog.AddControl(
"CompBox", "TesxtControl", "", dialogWidth-labelWidth-24,-1)
compBox.ValueModified.connect( CompChanged )


The File Browser based controls have also changed their file filter syntax. In Deadline 5, the file filter syntax looked like this:

scriptDialog.AddRow()
"FileLabel", "LabelControl", "Select File", labelWidth, -1)

scriptDialog.AddRow()