From bd5f6b7ede7d2baaf3e17ee31466ea841f00ed6b Mon Sep 17 00:00:00 2001 From: Vanessa Sochat Date: Sun, 18 Nov 2018 01:42:50 -0500 Subject: [PATCH 1/3] updating instances to support singularity instances subgroup >= 3.0 --- CHANGELOG.md | 1 + docs/pages/commands-instances.md | 17 +++++++++++++++++ spython/image/cmd/__init__.py | 2 -- spython/instance/__init__.py | 1 - spython/instance/cmd/__init__.py | 2 -- spython/instance/cmd/iutils.py | 10 ++++++++-- spython/instance/cmd/start.py | 11 +++++++++-- spython/instance/cmd/stop.py | 10 ++++++++-- spython/main/__init__.py | 8 ++++---- spython/main/base/command.py | 19 +++++++++---------- spython/main/instances.py | 8 ++++++-- spython/tests/test_utils.py | 11 +++++++++++ spython/utils/__init__.py | 1 + spython/utils/terminal.py | 18 ++++++++++++++++++ spython/version.py | 2 +- 15 files changed, 93 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 198265e4..e749b9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The client here will eventually be released as "spython" (and eventually to singularity on pypi), and the versions here will coincide with these releases. ## [master](https://github.com/singularityhub/singularity-cli/tree/master) + - adding support for instance list (0.0.47) - ENV variables in Dockerfile can be empty (like unsetting) (0.0.46) - COPY can handle multiple sources to one destination for Dockerfile parser (0.0.45) - Adding DockerRecipe, SingularityRecipe "load" action to load file diff --git a/docs/pages/commands-instances.md b/docs/pages/commands-instances.md index 651b8b5a..d35ee921 100644 --- a/docs/pages/commands-instances.md +++ b/docs/pages/commands-instances.md @@ -10,6 +10,7 @@ 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: + - [version](#singularity-version): control the instance command subgroup - [Shell](#shell) gives you an interactive python shell with a client - [Start](#create-an-instance) create a Singularity instance! - [Commands](#commands) how to interact with your instance (run, exec) @@ -23,6 +24,22 @@ 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](https://github.com/sylabs/singularity/blob/master/CHANGELOG.md#v300---20181008) +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: + +```bash +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: diff --git a/spython/image/cmd/__init__.py b/spython/image/cmd/__init__.py index c6824471..0df06f28 100644 --- a/spython/image/cmd/__init__.py +++ b/spython/image/cmd/__init__.py @@ -54,5 +54,3 @@ class ImageClient(object): cli = ImageClient() return cli - -image_group = generate_image_commands() diff --git a/spython/instance/__init__.py b/spython/instance/__init__.py index db16da2e..8d903839 100644 --- a/spython/instance/__init__.py +++ b/spython/instance/__init__.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - from spython.image import ImageBase import os diff --git a/spython/instance/cmd/__init__.py b/spython/instance/cmd/__init__.py index ae389193..b48d083e 100644 --- a/spython/instance/cmd/__init__.py +++ b/spython/instance/cmd/__init__.py @@ -46,5 +46,3 @@ def generate_instance_commands(): Instance.instance = Instance return Instance - -instance_group = generate_instance_commands() diff --git a/spython/instance/cmd/iutils.py b/spython/instance/cmd/iutils.py index 3a307a20..a5c58c92 100644 --- a/spython/instance/cmd/iutils.py +++ b/spython/instance/cmd/iutils.py @@ -46,10 +46,16 @@ def get(self, name, return_json=False, quiet=False): '''get is a list for a single instance. It is assumed to be running, and we need to look up the PID, etc. ''' - from spython.utils import check_install + from spython.utils import ( check_install, get_singularity_version ) check_install() - cmd = self._init_command('instance.list') + # Ensure compatible for singularity prior to 3.0, and after 3.0 + subgroup = "instance.list" + if get_singularity_version().startswith("3"): + subgroup = ["instance", "list"] + + cmd = self._init_command(subgroup) + cmd.append(name) output = run_command(cmd, quiet=True) diff --git a/spython/instance/cmd/start.py b/spython/instance/cmd/start.py index 09f654c9..5a4d12ab 100644 --- a/spython/instance/cmd/start.py +++ b/spython/instance/cmd/start.py @@ -34,7 +34,9 @@ def start(self, image=None, name=None, sudo=False, options=[], capture=False): singularity [...] instance.start [...] ''' - from spython.utils import ( run_command, check_install ) + from spython.utils import ( run_command, + check_install, + get_singularity_version ) check_install() # If no name provided, give it an excellent one! @@ -52,7 +54,12 @@ def start(self, image=None, name=None, sudo=False, options=[], capture=False): image = self._image - cmd = self._init_command('instance.start') + # Derive subgroup command based on singularity version + subgroup = 'instance.start' + if get_singularity_version().startswith("3"): + subgroup = ["instance", "start"] + + cmd = self._init_command(subgroup) # Add options, if they are provided if not isinstance(options, list): diff --git a/spython/instance/cmd/stop.py b/spython/instance/cmd/stop.py index a1f08a7a..acfd441f 100644 --- a/spython/instance/cmd/stop.py +++ b/spython/instance/cmd/stop.py @@ -32,10 +32,16 @@ def stop(self, name=None, sudo=False): singularity [...] instance.start [...] ''' - from spython.utils import ( check_install, run_command ) + from spython.utils import ( check_install, + run_command, + get_singularity_version ) check_install() - cmd = self._init_command('instance.stop') + subgroup = 'instance.stop' + if get_singularity_version().startswith("3"): + subgroup = ["instance", "stop"] + + cmd = self._init_command(subgroup) # If name is provided assume referencing an instance instance_name = self.name diff --git a/spython/main/__init__.py b/spython/main/__init__.py index 61aa1879..f11c90af 100644 --- a/spython/main/__init__.py +++ b/spython/main/__init__.py @@ -52,12 +52,12 @@ def get_client(quiet=False, debug=False): Client.pull = pull # Command Groups, Images - from spython.image.cmd import image_group # deprecated image commands - Client.image = image_group + from spython.image.cmd import generate_image_commands # deprecated + Client.image = generate_image_commands() # Commands Groups, Instances - from spython.instance.cmd import instance_group # instance level commands - Client.instance = instance_group + from spython.instance.cmd import generate_instance_commands # instance level commands + Client.instance = generate_instance_commands() Client.instance_stopall = stopall # Initialize diff --git a/spython/main/base/command.py b/spython/main/base/command.py index 7a9d4b52..14d6461d 100644 --- a/spython/main/base/command.py +++ b/spython/main/base/command.py @@ -32,18 +32,18 @@ def init_command(self, action, flags=None): - ''' - return the initial Singularity command with any added flags. + '''return the initial Singularity command with any added flags. - Parameters - ========== - action: the main action to perform (e.g., build) - flags: one or more additional flags (e.g, volumes) - not implemented yet. - + Parameters + ========== + action: the main action to perform (e.g., build) + flags: one or more additional flags (e.g, volumes) + not implemented yet. ''' - cmd = ['singularity', action ] + if not isinstance(action, list): + action = [action] + cmd = ['singularity'] + [action] if self.quiet is True: cmd.insert(1, '--quiet') @@ -123,4 +123,3 @@ def run_command(self, cmd, sudo=False, capture=True): if self.quiet is False: bot.error("Return Code %s: %s" %(return_code, message)) - diff --git a/spython/main/instances.py b/spython/main/instances.py index 03202afa..611b9484 100644 --- a/spython/main/instances.py +++ b/spython/main/instances.py @@ -16,7 +16,7 @@ from spython.logger import bot -from spython.utils import run_command, check_install +from spython.utils import ( run_command, check_install, get_singularity_version ) def instances(self, name=None, return_json=False, quiet=False): '''list instances. For Singularity, this is provided as a command sub @@ -42,7 +42,11 @@ def instances(self, name=None, return_json=False, quiet=False): from spython.utils import check_install check_install() - cmd = self._init_command('instance.list') + subgroup = 'instance.list' + if get_singularity_version().startswith("3"): + subgroup = ["instance", "list"] + + cmd = self._init_command(subgroup) # If the user has provided a name, we want to see a particular instance if name is not None: diff --git a/spython/tests/test_utils.py b/spython/tests/test_utils.py index fd8d9020..2dbc353f 100644 --- a/spython/tests/test_utils.py +++ b/spython/tests/test_utils.py @@ -81,6 +81,17 @@ def test_check_install(self): self.assertTrue(not is_not_installed) + def test_check_get_singularity_version(self): + '''check that the singularity version is found to be that installed''' + print("Testing utils.get_singularity_version") + from spython.utils import get_singularity_version + version = get_singularity_version() + self.assertTrue(version != "") + os.environ['SPYTHON_SINGULARITY_VERSION'] = "3.0" + version = get_singularity_version() + self.assertTrue(version == "3.0") + + def test_get_installdir(self): '''get install directory should return the base of where singularity is installed diff --git a/spython/utils/__init__.py b/spython/utils/__init__.py index c71b5b53..702fdb3a 100644 --- a/spython/utils/__init__.py +++ b/spython/utils/__init__.py @@ -9,6 +9,7 @@ from .terminal import ( check_install, get_installdir, + get_singularity_version, stream_command, run_command, format_container_name, diff --git a/spython/utils/terminal.py b/spython/utils/terminal.py index 2480c5b6..17a14ba9 100644 --- a/spython/utils/terminal.py +++ b/spython/utils/terminal.py @@ -56,6 +56,24 @@ def check_install(software='singularity', quiet=True): return found +def get_singularity_version(): + '''get the singularity client version. Useful in the case that functionality + has changed, etc. Can be "hacked" if needed by exporting + SPYTHON_SINGULARITY_VERSION, which is checked before checking on the + command line. + ''' + version = os.environ.get('SPYTHON_SINGULARITY_VERSION', "") + if version == "": + try: + version = run_command(["singularity", '--version'], quiet=True) + except: # FileNotFoundError + return version + + if version['return_code'] == 0: + version = version['message'][0].strip('\n') + + return version + def get_installdir(): '''get_installdir returns the installation directory of the application ''' diff --git a/spython/version.py b/spython/version.py index 3a205b5b..b7cd9325 100644 --- a/spython/version.py +++ b/spython/version.py @@ -16,7 +16,7 @@ -__version__ = "0.0.46" +__version__ = "0.0.47" AUTHOR = 'Vanessa Sochat' AUTHOR_EMAIL = 'vsochat@stanford.edu' NAME = 'spython' From 55b341d139a847b865410efd76fbadaf858a4321 Mon Sep 17 00:00:00 2001 From: Vanessa Sochat Date: Sun, 18 Nov 2018 08:17:44 -0500 Subject: [PATCH 2/3] bug that shouldnt be in second list --- spython/main/base/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spython/main/base/command.py b/spython/main/base/command.py index 14d6461d..cd197c32 100644 --- a/spython/main/base/command.py +++ b/spython/main/base/command.py @@ -43,7 +43,7 @@ def init_command(self, action, flags=None): if not isinstance(action, list): action = [action] - cmd = ['singularity'] + [action] + cmd = ['singularity'] + action if self.quiet is True: cmd.insert(1, '--quiet') From be22517d9756749eb9f485a95668590bd6ac86f7 Mon Sep 17 00:00:00 2001 From: Vanessa Sochat Date: Sun, 18 Nov 2018 09:45:21 -0500 Subject: [PATCH 3/3] testing with version 3 find --- spython/instance/cmd/iutils.py | 2 +- spython/instance/cmd/start.py | 2 +- spython/instance/cmd/stop.py | 2 +- spython/main/instances.py | 2 +- spython/utils/terminal.py | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spython/instance/cmd/iutils.py b/spython/instance/cmd/iutils.py index a5c58c92..c90d3366 100644 --- a/spython/instance/cmd/iutils.py +++ b/spython/instance/cmd/iutils.py @@ -51,7 +51,7 @@ def get(self, name, return_json=False, quiet=False): # Ensure compatible for singularity prior to 3.0, and after 3.0 subgroup = "instance.list" - if get_singularity_version().startswith("3"): + if get_singularity_version().find("version 3"): subgroup = ["instance", "list"] cmd = self._init_command(subgroup) diff --git a/spython/instance/cmd/start.py b/spython/instance/cmd/start.py index 5a4d12ab..6bb5f481 100644 --- a/spython/instance/cmd/start.py +++ b/spython/instance/cmd/start.py @@ -56,7 +56,7 @@ def start(self, image=None, name=None, sudo=False, options=[], capture=False): # Derive subgroup command based on singularity version subgroup = 'instance.start' - if get_singularity_version().startswith("3"): + if get_singularity_version().find("version 3"): subgroup = ["instance", "start"] cmd = self._init_command(subgroup) diff --git a/spython/instance/cmd/stop.py b/spython/instance/cmd/stop.py index acfd441f..b9a1d160 100644 --- a/spython/instance/cmd/stop.py +++ b/spython/instance/cmd/stop.py @@ -38,7 +38,7 @@ def stop(self, name=None, sudo=False): check_install() subgroup = 'instance.stop' - if get_singularity_version().startswith("3"): + if get_singularity_version().find("version 3"): subgroup = ["instance", "stop"] cmd = self._init_command(subgroup) diff --git a/spython/main/instances.py b/spython/main/instances.py index 611b9484..9eb1a0e2 100644 --- a/spython/main/instances.py +++ b/spython/main/instances.py @@ -43,7 +43,7 @@ def instances(self, name=None, return_json=False, quiet=False): check_install() subgroup = 'instance.list' - if get_singularity_version().startswith("3"): + if get_singularity_version().find("version 3"): subgroup = ["instance", "list"] cmd = self._init_command(subgroup) diff --git a/spython/utils/terminal.py b/spython/utils/terminal.py index 17a14ba9..3b5b79f9 100644 --- a/spython/utils/terminal.py +++ b/spython/utils/terminal.py @@ -70,7 +70,8 @@ def get_singularity_version(): return version if version['return_code'] == 0: - version = version['message'][0].strip('\n') + if len(version['message']) > 0: + version = version['message'][0].strip('\n') return version