Sites can extend the functionality of a blade through a class defined in TractorSiteStatusFilter.py. Customizations include:


TractorSiteStatusFilter.py must be installed in a directory visible to a blade, ideally the directory defined by SiteModulesPathin blade.config.

To start, copy lib/python2.7/site-packages/tractor/apps/blade/TractorSiteStatusFilter.py from the Tractor install directory to the SiteModulesPath directory.

Note that it will be necessary to reload blade.config for blades to reflect changes to SiteModulesPath or to TractorSiteStatusFilter.py.

Scenario: New Metrics

New metrics can be employed to determine the ability of a blade to perform work by overriding the FilterBasicState() andTestBasicState() methods. In the following example, www.example.com might represent a resource such as a license server that needs to be reachable before a blade would consider requesting work.

def FilterBasicState(self, stateDict, now):
    if stateDict is not None:
        rcode = os.system("ping -q -t 1 -c 1 www.example.com >& /dev/null")
        stateDict["server_reachable"] = (rcode == 0)
    self.super.FilterBasicState(stateDict, now)

def TestBasicState(self, stateDict, now):
    if stateDict is not None and not stateDict.get("server_reachable"):
        return False
    return self.super.TestBasicState(stateDict, now)

Scenario: Logging Errors

One could maintain a distinct log of errored processes by overriding SubprocessEnded().

def SubprocessEnded(self, cmd):
    if cmd.exitcode:
        with open("/tmp/errors.log", "a") as f:
            f.write("process %d errored with exit code %d\n" % (cmd.pid, cmd.exitcode))

Scenario: Early Process Termination

FilterSubprocessOutputLine() is called by the blade for each line of output from a process.

In this example, any prman process that emits a line starting with R10007 will be immediately terminated. The logic could be modified to examine the output of other applications, look for other patterns, and peform other actions. Note that non-matches should defer to FilterSubprocessOutputLine() of the superclass.

def FilterSubprocessOutputLine (self, cmd, textline):
    Return a 2-tuple giving a disposition code and a value.
    The pass-through result would be:  (self.TR_LOG_TEXT_EMIT, textline)
    if "prman" == cmd.app and textline.startswith("R10007"):
        # example:  immediately fail on prman warning number "R10007"
        return (self.TR_LOG_FATAL_CODE, 10007, textline)
        # otherwise defer to the usual built-in filters
        return self.super.FilterSubprocessOutputLine( cmd, textline )