You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by kl...@apache.org on 2018/11/03 00:04:04 UTC
[mesos] branch master updated: Updated new CLI task attach/exec
exit strategy.
This is an automated email from the ASF dual-hosted git repository.
klueska pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
The following commit(s) were added to refs/heads/master by this push:
new 25beea1 Updated new CLI task attach/exec exit strategy.
25beea1 is described below
commit 25beea12f9f12143e6df7b0ad2d272d4116c217c
Author: Kevin Klues <kl...@gmail.com>
AuthorDate: Fri Nov 2 19:55:44 2018 -0400
Updated new CLI task attach/exec exit strategy.
This code was pulled directly from:
https://github.com/dcos/dcos-core-cli/blob/
9d10e9d6fb2b16e46b58d67b7e9d79b2505f3451/
python/lib/dcos/dcos/mesos.py
Review: https://reviews.apache.org/r/69208/
---
src/python/cli_new/lib/cli/mesos.py | 48 ++++++++++++++++++++++++-
src/python/cli_new/lib/cli/plugins/task/main.py | 15 +++-----
src/python/cli_new/lib/cli/tests/task.py | 32 +++++++++++++++++
3 files changed, 84 insertions(+), 11 deletions(-)
diff --git a/src/python/cli_new/lib/cli/mesos.py b/src/python/cli_new/lib/cli/mesos.py
index 4a5777b..c4e5902 100644
--- a/src/python/cli_new/lib/cli/mesos.py
+++ b/src/python/cli_new/lib/cli/mesos.py
@@ -255,7 +255,7 @@ class TaskIO():
# Allow an exit sequence to be used to break the CLIs attachment to
# the remote task. Depending on the call, this may be disabled, or
# the exit sequence to be used may be overwritten.
- self.supports_exit_sequence = True
+ self.supports_exit_sequence = False
self.exit_sequence = b'\x10\x11' # Ctrl-p, Ctrl-q
self.exit_sequence_detected = False
@@ -285,6 +285,18 @@ class TaskIO():
self._run()
+ if not self.exit_sequence_detected:
+ # We are only able to get the 'exit_status' of tasks launched via
+ # the default executor (i.e. as pods rather than via the command
+ # executor). In the future, mesos will deprecate the command
+ # executor in favor of the default executor, so this check will
+ # be able to go away. In the meantime, we will always return '0'
+ # for tasks launched via the command executor.
+ if "parent" in self.container_id:
+ return self._wait()
+
+ return 0
+
def exec(self, _cmd, _args=None, _interactive=False, _tty=False):
"""
Execute a new process inside of a given task by redirecting
@@ -324,6 +336,8 @@ class TaskIO():
self._run()
+ return self._wait()
+
def _run(self):
"""
Run the helper threads in this class which enable streaming
@@ -362,6 +376,7 @@ class TaskIO():
try:
if self.interactive:
+ self.supports_exit_sequence = True
tty.setraw(fd, when=termios.TCSANOW)
# To force a redraw of the remote terminal, we first resize it
# to 0 before setting it to the actual size of our local
@@ -386,6 +401,37 @@ class TaskIO():
# pylint: disable=raising-bad-type
raise self.exception
+ def _wait(self):
+ """
+ Wait for the container associated with this class (through
+ 'container_id') to exit and return its exit status.
+ """
+ message = {
+ 'type': 'WAIT_CONTAINER',
+ 'wait_container': {
+ 'container_id': self.container_id}}
+ req_extra_args = {
+ 'additional_headers': {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'}}
+ try:
+ resource = mesos.http.Resource(self.agent_url)
+ response = resource.request(
+ mesos.http.METHOD_POST,
+ data=json.dumps(message),
+ retry=False,
+ timeout=None,
+ **req_extra_args)
+ except MesosException as exception:
+ raise CLIException(
+ "Error waiting for command to complete: {error}"
+ .format(error=exception))
+
+ exit_status = response.json()["wait_container"]["exit_status"]
+ if os.WIFSIGNALED(exit_status):
+ return os.WTERMSIG(exit_status) + 128
+ return os.WEXITSTATUS(exit_status)
+
def _thread_wrapper(self, func):
"""
A wrapper around all threads used in this class.
diff --git a/src/python/cli_new/lib/cli/plugins/task/main.py b/src/python/cli_new/lib/cli/plugins/task/main.py
index 5866a23..0536ccb 100644
--- a/src/python/cli_new/lib/cli/plugins/task/main.py
+++ b/src/python/cli_new/lib/cli/plugins/task/main.py
@@ -78,8 +78,7 @@ class Task(PluginBase):
.format(error=exception))
task_io = TaskIO(master, argv["<task-id>"])
- task_io.attach(argv["--no-stdin"])
- return 0
+ return task_io.attach(argv["--no-stdin"])
def exec(self, argv):
@@ -93,14 +92,10 @@ class Task(PluginBase):
.format(error=exception))
task_io = TaskIO(master, argv["<task-id>"])
- task_io.exec(argv["<command>"],
- argv["<args>"],
- argv["--interactive"],
- argv["--tty"])
-
- # TODO(ArmandGrillet): We should not return 0 here but
- # whatever the result of `<command> [<args>...]` was.
- return 0
+ return task_io.exec(argv["<command>"],
+ argv["<args>"],
+ argv["--interactive"],
+ argv["--tty"])
def list(self, argv):
"""
diff --git a/src/python/cli_new/lib/cli/tests/task.py b/src/python/cli_new/lib/cli/tests/task.py
index ad11bd8..f033b4a 100644
--- a/src/python/cli_new/lib/cli/tests/task.py
+++ b/src/python/cli_new/lib/cli/tests/task.py
@@ -80,6 +80,38 @@ class TestTaskPlugin(CLITestCase):
agent.kill()
master.kill()
+ def test_exec_exit_status(self):
+ """
+ Basic test for the task `exec()` sub-command exit status.
+ """
+ # Launch a master, agent, and task.
+ master = Master()
+ master.launch()
+
+ agent = Agent()
+ agent.launch()
+
+ task = Task({"command": "sleep 1000"})
+ task.launch()
+
+ tasks = running_tasks(master)
+ if not tasks:
+ raise CLIException("Unable to find running tasks on master"
+ " '{master}'".format(master=master.addr))
+
+ returncode, _, _ = exec_command(
+ ["mesos", "task", "exec", tasks[0]["id"], "true"])
+ self.assertEqual(returncode, 0)
+
+ returncode, _, _ = exec_command(
+ ["mesos", "task", "exec", tasks[0]["id"], "bash", "-c", "exit 10"])
+ self.assertEqual(returncode, 10)
+
+ # Kill the task, agent, and master.
+ task.kill()
+ agent.kill()
+ master.kill()
+
def test_exec_interactive(self):
"""