Scenario API

Quickstart

A scenario is a Python sub-class of the NEOS Scenario class. There are only two requirements to be a valid and usable scenario for the application:

  • Have a NAME class attribute,
  • Implement a run() method that returns an exit code.

A minimal Scenario would look like:

#!/usr/bin/env python

from neos import Scenario

class ScenarioMinimal(Scenario):

    NAME = 'minimal'

    def run(self):

        return 0

The name of the class has no real importance. The name of the scenario across NEOS will be the value of the NAME class attribute.

NEOS considers the scenario run failed when the run() method returns non-0 exit code. This exit code is also the exit code returned by neos command.

If you save this scenario code into ~/scenarios/minimal.py, you can run it with the following command:

srun neos --scenarios-dir=~/scenarios --scenario=minimal

Optional parameters

The scenarios can be configured at runtime with optional parameters. The declaration of optional parameters is done through the OPTS class attribute. As an example, optional paramters can be added to the previous minimal scenario this way:

#!/usr/bin/env python

from neos import Scenario

class ScenarioMinimal(Scenario):

    NAME = 'minimal'
    OPTS = ['wait:bool:false',
            'time:int:10',
            'msg:str:foo']

    def run(self):

        output = self.cmd_output(['echo', self.opts.msg])

        if self.opts.wait is True:
            self.sleep(self.opts.time)

        return 0

The OPTS class attribute is a list of strings. Each string is a triplet of parameter name, type and default value separated by the ‘:’ character.

In the previous example, the scenario has 3 optional parameters:

  • the boolean wait which is false by default,
  • the integer time whose default value is 10,
  • the string msg with default value to foo.

The parameters are then accessible in the run() method as attributes of the opts object attribute. Ex: self.opts.wait for the wait attribute.

Without options specified on neos command line, the default values are used. Other values can be set with -o, --opts parameter:

srun neos --scenarios-dir=~/scenarios --scenario=minimal --opts=wait:false

NEOS framework make sure parameters types are respected.

Command level logfiles

Additionally to -l,--log argument which redirect the outputs of all sub-commands of a scenario, NEOS also supports fine-grain redirections of the stdout and stderr outputs to arbitrary files at command level. This is controlled with optional stdout and stderr arguments of cmd_run_bg() and cmd_wait() scenarios methods. Here is a commented example:

#!/usr/bin/env python

from neos import Scenario

class ScenarioOutputs(Scenario):

    NAME = 'outputs'

    def run(self):

        # bar1 printed to neos stdout or --log file if set
        self.cmd_wait(['echo', 'bar1'])

        # bar2 printed in foo2 file
        self.cmd_wait(['echo', 'bar2'], stdout='foo2')

        # bar3 redirected to /dev/null, foo3 created but empty
        self.cmd_wait(['echo', 'bar3'], stdout='/dev/null', stderr='foo3')

        # error printed on stderr by cat redirected to /dev/null
        self.cmd_wait(['cat', '/root/fail'], stderr='/dev/null')

        # neos cannot open /root/fail (permission denied), bar4 is printed to
        # neos stdout or --log file is set.
        self.cmd_wait(['echo', 'bar4'], stdout='/root/fail')

        return 0

NEOS automatically takes care of opening and closing all files descriptors as needed.

Abstract scenarios

A scenario does not need to have the Scenario base class as its direct parent class. As soon as one its parents inherits from the Scenario class, directly or not, it is valid scenario. Here comes the concept of abstract scenario.

An abstract scenario is a class that inherits from the Scenario base class but has no NAME attribute. Those classes can define code and optional parameters but cannot be run directly with NEOS. They are useful to define generic code shared by multiple scenarios.

Here is a complete example:

#!/usr/bin/env python

from neos import Scenario

class ScenarioEchoWait(Scenario):

    OPTS = ['wait:bool:false',
            'time:int:10']

    def _echo_wait(self, msg):

        output = self.cmd_output(['echo', msg])

        if self.opts.wait is True:
            self.sleep(self.opts.time)

        return 0


class ScenarioFoo(ScenarioEchoWait):

    NAME = 'true'
    OPTS = ['msg:str:foo']

    def run(self):
        self._echo_wait(self.opts.msg)


class ScenarioBar(ScenarioEchoWait):

    NAME = 'false'
    OPTS = ['msg:str:bar']

    def run(self):
        self._echo_wait(self.opts.msg)

In this example, the ScenarioEchoWait class does not have a NAME class attribute. Then, NEOS consider it as an abtract scenario.

The other classes ScenarioFoo and ScenarioBar inherits from the Scenario base class (through the ScenarioEchoWait class), have a NAME class attribute and define a run() method. Then, NEOS consider those classes as valid scenarios that can be run.

Using this mechanism, ScenarioFoo and ScenarioBar can share code: they both use the same method _echo_wait() and the optional parameters defined in the ScenarioEchoWait class.

Then, the scenarios can be run with:

srun neos --scenarios-dir=~/scenarios --scenario=foo

Or:

srun neos --scenarios-dir=~/scenarios --scenario=bar

Reference API

The run() method of the scenarios can run any arbitrary Python code. However, the parent Scenario class provides a set of methods to ease most common tasks and code patterns. This is highly recommended to widely use those methods in the source code of your scenarios in order to get the following benefits:

  • significantly reduce the number of lines of code,
  • integrates fully with NEOS framework and thus Slurm workload manager.

Here are the available public methods of the base Scenario class:

ensure_dir(filename)

Creates recursively all the parent directories of a file if they do not exist.

Parameters:filename (str) – the relative or absolute path of the file.
Returns:None
create_file(filename)

First ensures the parent the directory of the file exists, then create an empty file if it does not exist.

Parameters:filename (str) – the relative or absolute path of the file.
Returns:None
register_tmpfile(filename)

Register a temporary file to remove on NEOS exit. All temporary files created by the scenarios must be registered using this method.

Parameters:filename (str) – the absolute path to the file.
Returns:None
sleep(time)

Sleep the specified amount of time unless in dry-run mode.

Parameters:time (int or float) – the time in seconds to sleep for.
Returns:None
cmd_run_bg(cmd, shell=False, stdout=None, stderr=None)

Run the given command in background, unless in dry-run mode. In dry-run mode, the command is just printed as an information message. If the shell parameter is True, the command is run in a new spawned shell. If stdout and stderr are valid file paths and can be opened, respectively stdout and stderr outputs of the command are redirected to these files. If not set or an error is encountered while opening the files, the outputs of the command will be either connected to neos stdout/stderr or redirected to the logfile if -l,--log parameter is set.

Parameters:
  • cmd (a list of strings with the command and its parameters.) – the command to run in background.
  • shell (bool) – whether the command is run in a new shell or not.
  • stdout (str) – file path where to redirect stdout of the command.
  • stderr (str) – file path where to redirect stderr of the command.
Returns:

the handler on the process launched in background.

Return type:

Popen object

cmd_wait(cmd, shell=False, stdout=None, stderr=None)

Run the given command and wait for it to complete, unless in dry-run mode. In dry-run mode, the command is just printed as an information message. If the shell parameter is True, the command is run in a new spawned shell. If stdout and stderr are valid file paths and can be opened, respectively stdout and stderr outputs of the command are redirected to these files. If not set or an error is encountered while opening the files, the outputs of the command will be either connected to neos stdout/stderr or redirected to the logfile if -l,--log parameter is set.

Parameters:
  • cmd (a list of strings with the command and its parameters.) – the command to run in background.
  • shell (bool) – whether the command is run in a new shell or not.
  • stdout (str) – file path where to redirect stdout of the command.
  • stderr (str) – file path where to redirect stderr of the command.
Returns:

the command exit code

Return type:

int

cmd_output(cmd, shell=False)

Run the given command, wait for it to complete and returns its output, unless in dry-run mode. If the shell parameter is True, the command is run in a new spawned shell. In dry-run mode, the command is just printed as an information message and the fake output dryrunoutput is returned.

Parameters:
  • cmd (a list of strings with the command and its parameters.) – the command to run in background.
  • shell (bool) – whether the command is run in a new shell or not.
Returns:

the output the command

Return type:

string