Muster Builtin scripting
Starting with version 8.5.0, Muster supports integrated scripting through the Console interface or extending the python functions inside any template. The Python scripting API let you customize behaviors of the Console, the Dispatcher and any Renderclient instance.
The Python modules available are:
- Dispatcher : MDispatcherAPI , gives access to the entire Dispatcher data structures
- Renderclient : MInstanceAPI , gives access to the Renderclient status as well as the running jobs
- Console : MConsoleAPI , gives access to the Console data structures. It also gives access to the running QT Gui libraries to create custom UI inside Console
Usage scenario
Here are some idea in what contexts you can use the builtin Muster scripting facilities:
Dispatcher scripting
One of the most useful script you can write on the Dispatcher is to perform background tasks.
You can script the Dispatcher from within the global template to perform idling tasks using the template member function onDispatcherIdling() available only in the global template (0). This function is invoked automatically by the Dispatcher every 60 seconds.
If you need to call it more or less frequently, you can change the idling time by setting the preferences like in the example below:
def onDispatcherIdling(self): import MClientAPI import MDispatcherAPI config = MClientAPI.MDispatcherConfiguration() err = MDispatcherAPI.systemGetConfiguration(config) config.tuning.setIdlingScriptingTime(10) # Execute this function each 10 seconds MDispatcherAPI.systemSetConfiguration(config,0) # We do not store the settings in the dispatcher.conf file, just flush back the changes in memory # Now executes your idling function, in this example , we automatically lock completed jobs err, jobs = MDispatcherAPI.jobGetList() for job in jobs: if (job.getStatus() == MClientAPI.MJob.kJobsStatusJobCompleted): job.setLocked(1) # Locks the job MDispatcherAPI.jobUpdate(job.getJobId()) # Refresh the job status to connected Consoles
Other useful tasks may be performed on the Dispatcher using the onJobCompleted() and onJobStart() templates functions. Also you can register a script to be run on the Dispatcher by registering a new script into the Console and select the Dispatcher as the execution context. This will make the script on-demand from the Console GUI.
Client scripting
One of the most useful script you can write on the client is to perform background tasks as well as checking your client availability.
You can script the client from within the global template to perform idling tasks using the template member function onClientIdling() available only in the global template (0). This function is invoked automatically by the client every 60 seconds.
If you need to call it more or less frequently, you can change the idling time by setting the preferences like in the example below:
def onClientIdling(self): import MClientAPI import MInstanceAPI config = MClientAPI.MNodeConfiguration() err = MInstanceAPI.getConfiguration(config) config.tuning.setIdlingScriptingTime(10) # Execute this function each 10 seconds MInstanceAPI.setConfiguration(config,0) # We do not store the settings in the dispatcher.conf file, just flush back the changes in memory # Now executes your idling function
def onCheckClientAvailability: import MClientAPI import MInstanceAPI err, status = MInstanceAPI.getInstanceStatus(0) # Grabs the status of instance 0, you should tweak this if running multiple instances by collecting the overall status if (status == MClientAPI.MNode.kInstanceStatusInprogress): # There's a rendering in progress, check what job is rendering err, job = MInstanceAPI.getRunningJob() if (job.getName() == "My very special job"): # Do not stop the client availability but confirm it return MTemplateAPI.kTemplateFunctionSuccess # Client will be available for rendering # Otherwise calculates the default availability return MTemplateAPI.kTemplateFunctionDoDefault
Console scripting
Here there are unlimited capabilities. With the inclusion of PySide inside the Muster python distribution, you can write your own GUI to react to context menus inside the Muster views as well as create your own submission or job checking dialogs.
One of the most useful implementation may be to create a custom dialog to validate any job you submit into Console. This can be easily done writing the onJobValidate() on the global template (0) or any specific engine template. This is a full example that asks for an extra job attribute at the time of the submission, you can then recall your custom attribute on any template or script:
# The following script goes at the top of the global template, it declares a Job Validator Class only if running inside the Console context if (muster.runningContext() == "console"): from PySide import QtCore, QtGui import MConsoleAPI class JobValidatorDialog(QtGui.QDialog): def __init__(self): super(JobValidatorDialog,self).__init__() self.initUI() def initUI(self): self.layout = QtGui.QVBoxLayout() self.label = QtGui.QLabel("Job shot:") self.shot = QtGui.QLineEdit() self.buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok| QtGui.QDialogButtonBox.Cancel) self.layout.addWidget(self.label) self.layout.addWidget(self.shot) self.layout.addStretch() self.layout.addWidget(self.buttonBox) self.setLayout(self.layout) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject)
Then, at the template definition level, you can change the onValidateJob function in this way:
def onValidateJobSubmission(self, job, err): if (muster.runningContext() != "console"): return 1 # Skip validation on no console contexts dlg = JobValidatorDialog() result = dlg.exec() if (result == QtGui.QDialog.Accepted): job.attributeSetString("JOBSHOT", dlg.shot.text(), 1 ,0) # If user clicks OK, a new attribute is appended to the job, it can be later checked from the templates, or shown in console by customizing the job view headers return 1 else: err.setString("Cancelled by user!") return 0