Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ workflows:
waitforapt: &waitforapt
name: Remove cloud init lock
command: |
sudo rm -rf /var/lib/apt/lists/lock
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 10; done
while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1; do echo 'Waiting for autoupdates to complete...'; sleep 10; done
echo 'Waiting for instance to really be ready...'
sleep 30
sudo rm -rf /var/lib/apt/lists/lock
sudo rm /var/lib/dpkg/lock && sudo dpkg --configure -a


Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ 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)
- Added ability for exec and run to return the full output and message (0.0.55)
- By default, oci commands (pause, resume, kill) return the return value
- Added support and tests for OCI image command group (0.0.54)
- client now has version() function to call get_singularity_version
- added return_result (boolean) to client run_command function.
Expand Down
15 changes: 9 additions & 6 deletions spython/main/base/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,17 @@ def run_command(self, cmd,
quiet = self.quiet

result = run_cmd(cmd, sudo=sudo, capture=capture, quiet=quiet)
message = result['message']

# If one line is returned, squash dimension
if len(result['message']) == 1:
result['message'] = result['message'][0]

# If the user wants to return the result, just return it
if return_result is True:
return result

# On success, return result
if result['return_code'] == 0:
if len(result['message']) == 1:
result['message'] = result['message'][0]
return result['message']

# For client (internal) calls, we want the return code
if return_result is True:
return result
return result
9 changes: 7 additions & 2 deletions spython/main/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def execute(self,
contain = False,
bind = None,
stream = False,
nv = False):
nv = False,
return_result=False):

''' execute: send a command to a container

Expand All @@ -37,6 +38,8 @@ def execute(self,
This option allows you to map directories on your host system to
directories within your container using bind mounts
nv: if True, load Nvidia Drivers in runtime (default False)
return_result: if True, return entire json object with return code
and message result (default is False)
'''
from spython.utils import check_install
check_install()
Expand Down Expand Up @@ -81,7 +84,9 @@ def execute(self,
cmd = cmd + [image] + command

if stream is False:
return self._run_command(cmd,sudo=sudo)
return self._run_command(cmd,
sudo=sudo,
return_result=return_result)
return stream_command(cmd, sudo=sudo)

bot.error('Please include a command (list) to execute.')
15 changes: 13 additions & 2 deletions spython/main/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def run(self,
contain = False,
bind = None,
stream = False,
nv = False):
nv = False,
return_result=False):

'''
run will run the container, with or withour arguments (which
Expand All @@ -38,6 +39,9 @@ def run(self,
directories within your container using bind mounts
stream: if True, return <generator> for the user to run
nv: if True, load Nvidia Drivers in runtime (default False)
return_result: if True, return entire json object with return code
and message result (default is False)

'''
from spython.utils import check_install
check_install()
Expand Down Expand Up @@ -76,10 +80,17 @@ def run(self,
cmd = cmd + args

if stream is False:
result = self._run_command(cmd, sudo=sudo)
result = self._run_command(cmd,
sudo=sudo,
return_result=return_result)
else:
return stream_command(cmd, sudo=sudo)

# If the user wants the raw result object
if return_result:
return result

# Otherwise, we parse the result if it was successful
if result:
result = result.strip('\n')

Expand Down
2 changes: 1 addition & 1 deletion spython/oci/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def _run_and_return(self, cmd, sudo=None):

# Show the response to the user, only if not quiet.
elif not self.quiet:
bot.print(result['message'][0])
bot.print(result['message'])

# Return the state object to the user
return result['return_code']
Expand Down
10 changes: 6 additions & 4 deletions spython/oci/cmd/states.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ def state(self, container_id=None, sudo=None, sync_socket=None):
cmd.append(container_id)

# Get the instance state
result = self._run_command(cmd, sudo=sudo, quiet=True, return_result=True)
result = self._run_command(cmd, sudo=sudo, quiet=True)

# If successful, a string is returned to parse
if isinstance(result, str):
return json.loads(result)
if result != None:

# If successful, a string is returned to parse
if isinstance(result, str):
return json.loads(result)


def _state_command(self, container_id=None, command='start', sudo=None):

Expand Down
6 changes: 6 additions & 0 deletions spython/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ def test_commands(self):
print(result)
self.assertTrue('tmp\nusr\nvar' in result)

print('Testing client.execute command with return code')
result = self.cli.execute(container,'ls /', return_result=True)
print(result)
self.assertTrue('tmp\nusr\nvar' in result['message'])
self.assertEqual(result['return_code'], 0)

print("Testing client.inspect command")
labels = self.cli.inspect(container)

Expand Down
8 changes: 7 additions & 1 deletion spython/tests/test_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ def test_instances(self):
result = self.cli.execute(myinstance, ['echo', 'hello'])
self.assertTrue('hello\n' == result)

print("...Case 4: Stop instances")
print('...Case 4: Return value from instance')
result = self.cli.execute(myinstance,'ls /', return_result=True)
print(result)
self.assertTrue('tmp\nusr\nvar' in result['message'])
self.assertEqual(result['return_code'], 0)

print("...Case 5: Stop instances")
myinstance.stop()
instances = self.cli.instances()
self.assertEqual(instances, [])
Expand Down
24 changes: 15 additions & 9 deletions spython/tests/test_oci.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,31 @@ def test_oci(self):
state = self.cli.oci.state(self.name, sudo=True)
self.assertEqual(state['status'], 'created')

print('...Case 5. Start container.')
print('...Case 5. Start container return value 0.')
state = self.cli.oci.start(self.name, sudo=True)
self.assertEqual(state, None)
self.assertEqual(state, 0)

print('...Case 6. Testing that state is now running.')
state = self.cli.oci.state(self.name, sudo=True)
self.assertEqual(state['status'], 'running')

print('...Case 6. Pause running container.')
print('...Case 7. Pause running container return value 0.')
state = self.cli.oci.pause(self.name, sudo=True)
self.assertEqual(state, None)
self.assertEqual(state, 0)

print('...Case 7. Resume paused container.')
print('...Case 8. Resume paused container return value 0.')
state = self.cli.oci.resume(self.name, sudo=True)
self.assertEqual(state, None)
self.assertEqual(state, 0)

print('...Case 8. Kill should work with running container.')
print('...Case 9. Kill container.')
state = self.cli.oci.kill(self.name, sudo=True)
self.assertTrue(state in [None, 255])
self.assertEqual(state, 0)

# Clean up the image (should still use sudo)
# Bug in singularity that kill doesn't kill completely - this returns
# 255. When testsupdated to 3.1.* add signal=K to run
result = self.cli.oci.delete(self.name, sudo=True)
self.assertTrue(result in [None, 255])
self.assertTrue(result in [0,255])


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion spython/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.


__version__ = "0.0.54"
__version__ = "0.0.55"
AUTHOR = 'Vanessa Sochat'
AUTHOR_EMAIL = 'vsochat@stanford.edu'
NAME = 'spython'
Expand Down