This section will discuss interaction with container instances, which generally includes starting, stopping and running. From within python, you can instantiate an sphython client, and then use the following functions to control an Instance:

Along with the above, there are a few client commands that will give you a list of instances. While this listing doesn’t directly link to finding an Instance that you have created, you can find based on the name (shown later in the documentation).


Singularity Version

After Singularity 3.0, the instances command subgroup changed so that the original call to interact with instances might have looked like “instances.list”. After 3.0, the instances subgroup changed to be of the format “instances list.” Singularity Python determines this automatically by looking at your Singularity version, however if you want to control the final command that is used (for one reason or another) you can also export the environment variable:

export SPYTHON_SINGULARITY_VERSION=2.6

Would change behavior of the client for Singularity instances. This currently only has this changed behavior for the instances subgroup.

Shell

All of the commands below start with creating an spython client:

from spython.main import Client

but if you want, you can skip this step with the spython shell, which basically loads it for you!

$ spython shell

Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 18:10:19)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: client
Out[1]: [singularity-python]

You will be able to interact with instances via the Client, discussed in the following sections.


Create an Instance

Running this command is equivalent to creating an instance from the command line, meaning that we “start” it. This means that an image is required. Let’s say that we have a local image, ubuntu.simg

$ from spython.main import Client
$ myinstance = Client.instance('ubuntu.simg')

Optionally you can define other arguments! Just specify them as options. You can split options into a list, where each entry is either a single flag, or a flag that is also given a value (the following item in the list). Below, let’s create some trivial directory, and try creating arguments to bind it to /opt in the instance.

# This is on the host, not from within Python
mkdir -p /tmp/colors
echo "red orange yellow green blue violet pancake" >> /tmp/colors/rainbow.txt

Now we can bind this to /opt in our container.

from spython.main import Client
options = ["--bind", "/tmp/colors:/opt"]
myinstance = Client.instance('ubuntu.simg', options=options)

You can check the options that were given to the instance:

$ myinstance.options
['--bind', '/tmp:/opt']

You can also check the entire command, which is saved with the instance object.

$ myinstance.cmd

['singularity',
 'instance.start',
 '--bind',
 '/tmp/colors:/opt',
 'spython/ubuntu.simg',
 'lovable_poo_3785']

Cool!

To check the bind, let’s next learn how to interact with our instances.


Commands

Let’s use the instance we created above, and try an exec command to see if we successfully bound our /tmp to /opt. If you don’t have the instance, remember that you can ask for it by name:

$ from spython.main import Client
$ myinstance = Client.instances('lovable_poo_3785', quiet=True)

myinstance
instance://lovable_poo_3785

Now let’s list the contents of /tmp/colors

contents = Client.execute(myinstance,["ls","/tmp/colors"])

contents
$ 'rainbow.txt\n'

The same is true for run, and you can use the same arguments to bind, etc. as you would for the client’s main commands.

Stop

Instances have two states, alive (after started), and then dead of course. To stop your instance, just stop it.

$ from spython.main import Client
$ myinstance = Client.instances('lovable_poo_3785', quiet=True)
$ myinstance.stop()

# This is the return code
0

$ Client.instances('lovable_poo_3785')
No instances found.

He’s really gone!

Stop All

If you want to stop all instances, that command is on the level of the main client (it wouldn’t make sense to have it associated with a single instance!)

from spython.main import Client
$ Client.instance_stopall()

# Return code
0

# Confirm no instances
$ Client.instances()
No instances found.


### List

First, to list running instances, here is what you see when there aren't any:

```bash
from spython.main import Client
Client.instances()
No instances found.

List (Instance Object)

The default listing will return a list of instance objects:

$ instances = Client.instances()
DAEMON NAME      PID      CONTAINER IMAGE
blue_latke_2291  22472    /home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg
creamy_train_2570 23162    /home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg

If you don’t want to see the Table printed, set quiet=True to prevent this.

instances = Client.instances(return_json=False, quiet=True)

If you look at the output, you have a list of instances:

$ instances
$ [instance://blue_latke_2291, instance://creamy_train_2570]

If you inspect one, you can get it’s pid, it’s name, associated container, and some other useful things:

$ myinstance = instances.pop(0)

$ myinstance
instance://blue_latke_2291

$ myinstance.pid
'22472'

$ myinstance.name
'blue_latke_2291'

$ myinstance.get_uri()
'instance://blue_latke_2291'

$ myinstance._image
'/home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg'

We explicitly don’t have a “status” field because by way of existing, it’s status is started. If the status were stopped, you wouldn’t find it.

List (Json)

If instances are found, a list is returned! The list is of json objects, each with a daemon name, pid, and associted container image.

$ instances = Client.instances(return_json=True)
DAEMON NAME      PID      CONTAINER IMAGE
creamy           30859    /home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg
tart_hippo_4068  1743     /home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg

Here is the json result:

$ instances

[{'container_image': '/home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg',
  'daemon_name': 'creamy',
  'pid': '30859'},
 {'container_image': '/home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg',
  'daemon_name': 'tart_hippo_4068',
  'pid': '1743'}]

List (Single)

If you provide a specific instance name, this is akin to searching running instances for it. The match is done based on name. For example, here we retrieve the instance called creamy:

$ Client.instances(name='creamy', quiet=True)
[{'container_image': '/home/vanessa/spython/ubuntu.simg',
  'daemon_name': 'creamy',
  'pid': '15051'}]

If you ask to return an object (discussed further in the next section) you can inspect it! For example:

$ creamy = Client.instances(name='creamy', return_json=False,  quiet=True)
[instance://creamy]

You can then inspect things like the pid, and original container:

$ creamy.pid
'15051'

$ creamy.name
'creamy'

$ creamy._image
'/home/vanessa/Documents/Dropbox/Code/sregistry/singularity-cli/spython/ubuntu.simg'

$ creamy.get_uri()
`instance://creamy`

It follows that if you search for a name that doesn’t exist, you won’t find any instances.

$ Client.instances(name='creamier', quiet=True)
No instances found.

Logs

If you are running Singularity 3.5 or later, the instance logs (error and output) should be programatically available, and you can return them via these functions:

logs = creamy.error_logs()
logs = creamy.output_logs()

To print them to the screen, set print_logs to True:

logs = creamy.error_logs(print_logs=True)