Merge pull request #61 from mesosphere/dcos-321-task-show

dcos-321 Implements showing tasks
This commit is contained in:
Sunil Shah
2015-03-06 09:08:53 -08:00
4 changed files with 128 additions and 35 deletions

View File

@@ -1,3 +1,5 @@
from __future__ import print_function
import abc
import collections
import json
@@ -60,13 +62,16 @@ def print_handler(event):
:type event: str, dict or dcos.api.errors.Error
"""
if isinstance(event, basestring):
if event is None:
# Do nothing
pass
elif isinstance(event, basestring):
print(event)
elif isinstance(event, collections.Mapping) or isinstance(event, list):
json.dump(event, sys.stdout, sort_keys=True, indent=2)
print('')
elif isinstance(event, errors.Error):
print(event.error())
print(event.error(), file=sys.stderr)
else:
logger.error(
'Unable to print event. Type not supported: %s, %r.',

View File

@@ -319,8 +319,8 @@ class Client(object):
def get_deployment(self, deployment_id):
"""Returns a deployment.
:param deployemnt_id: the id of the application to restart
:type deployemnt_id: str
:param deployment_id: the deployment id
:type deployment_id: str
:returns: a deployment
:rtype: (dict, Error)
"""
@@ -343,7 +343,7 @@ class Client(object):
def get_deployments(self, app_id=None):
"""Returns a list of deployments, optionally limited to an app.
:param app_id: the id of the application to restart
:param app_id: the id of the application
:type app_id: str
:returns: a list of deployments
:rtype: list of dict
@@ -422,13 +422,12 @@ class Client(object):
:param app_id: the id of the application to restart
:type app_id: str
:returns: a list of tasks
:rtype: list of dict
:rtype: (list of dict, dcos.api.errors.Error)
"""
url = self._create_url('v2/tasks')
response, error = http.get(url, response_to_error=_response_to_error)
if error is not None:
return (None, error)
@@ -443,6 +442,28 @@ class Client(object):
return (tasks, None)
def get_task(self, task_id):
"""Returns a task
:param task_id: the id of the task
:type task_id: str
:returns: a tasks
:rtype: (dict, dcos.api.errors.Error)
"""
url = self._create_url('v2/tasks')
response, error = http.get(url, response_to_error=_response_to_error)
if error is not None:
return (None, error)
task = next(
(task for task in response.json()['tasks']
if task_id == task['id']),
None)
return (task, None)
def normalize_app_id(app_id):
"""Normalizes the application id.

View File

@@ -14,6 +14,7 @@ Usage:
dcos app start [--force] <app-id> [<instances>]
dcos app stop [--force] <app-id>
dcos app task list [<app-id>]
dcos app task show <task-id>
dcos app update [--force] <app-id> [<properties>...]
dcos app version list [--max-count=<max-count>] <app-id>
@@ -45,6 +46,7 @@ Positional arguments:
<properties> Optional key-value pairs to be included in the
command. The separator between the key and value
must be the '=' character. E.g. cpus=2.0
<task-id> The task id
"""
import json
import os
@@ -120,6 +122,11 @@ def _cmds():
arg_keys=['<app-id>'],
function=_task_list),
cmds.Command(
hierarchy=['task', 'show'],
arg_keys=['<task-id>'],
function=_task_show),
cmds.Command(hierarchy=['info'], arg_keys=[], function=_info),
cmds.Command(
@@ -683,6 +690,33 @@ def _task_list(app_id):
return 0
def _task_show(task_id):
"""
:param task_id: the task id
:type task_id: str
:returns: process status
:rtype: int
"""
client = marathon.create_client(
config.load_from_path(
os.environ[constants.DCOS_CONFIG_ENV]))
task, err = client.get_task(task_id)
if err is not None:
emitter.publish(err)
return 1
if task is None:
emitter.publish(
errors.DefaultError("Task '{}' does not exist".format(task_id)))
return 1
emitter.publish(task)
return 0
def _update_from_stdin(app_id, force):
"""
:param app_id: the id of the application

View File

@@ -22,6 +22,7 @@ def test_help():
dcos app start [--force] <app-id> [<instances>]
dcos app stop [--force] <app-id>
dcos app task list [<app-id>]
dcos app task show <task-id>
dcos app update [--force] <app-id> [<properties>...]
dcos app version list [--max-count=<max-count>] <app-id>
@@ -53,6 +54,7 @@ Positional arguments:
<properties> Optional key-value pairs to be included in the
command. The separator between the key and value
must be the '=' character. E.g. cpus=2.0
<task-id> The task id
"""
assert stderr == b''
@@ -108,8 +110,8 @@ def test_add_bad_json_app():
stdin=fd)
assert returncode == 1
assert stdout == b'Error loading JSON.\n'
assert stderr == b''
assert stdout == b''
assert stderr == b'Error loading JSON.\n'
def test_add_existing_app():
@@ -164,9 +166,9 @@ def test_show_missing_relative_app_version():
['dcos', 'app', 'show', '--app-version=-2', 'zero-instance-app'])
assert returncode == 1
assert (stdout ==
assert stdout == b''
assert (stderr ==
b"Application 'zero-instance-app' only has 2 version(s).\n")
assert stderr == b''
_remove_app('zero-instance-app')
@@ -182,9 +184,9 @@ def test_show_missing_absolute_app_version():
'zero-instance-app'])
assert returncode == 1
assert (stdout ==
assert stdout == b''
assert (stderr ==
b"Error: App '/zero-instance-app' does not exist\n")
assert stderr == b''
_remove_app('zero-instance-app')
@@ -200,10 +202,10 @@ def test_show_bad_app_version():
'zero-instance-app'])
assert returncode == 1
assert (stdout ==
assert stdout == b''
assert (stderr ==
(b'Error: Invalid format: "20:39:32.972Z" is malformed at '
b'":39:32.972Z"\n'))
assert stderr == b''
_remove_app('zero-instance-app')
@@ -218,8 +220,8 @@ def test_show_bad_relative_app_version():
['dcos', 'app', 'show', '--app-version=2', 'zero-instance-app'])
assert returncode == 1
assert (stdout == b"Relative versions must be negative: 2\n")
assert stderr == b''
assert stdout == b''
assert (stderr == b"Relative versions must be negative: 2\n")
_remove_app('zero-instance-app')
@@ -229,8 +231,8 @@ def test_start_missing_app():
['dcos', 'app', 'start', 'missing-id'])
assert returncode == 1
assert stdout == b"Error: App '/missing-id' does not exist\n"
assert stderr == b''
assert stdout == b''
assert stderr == b"Error: App '/missing-id' does not exist\n"
def test_start_app():
@@ -259,8 +261,8 @@ def test_stop_missing_app():
['dcos', 'app', 'stop', 'missing-id'])
assert returncode == 1
assert stdout == b"Error: App '/missing-id' does not exist\n"
assert stderr == b''
assert stdout == b''
assert stderr == b"Error: App '/missing-id' does not exist\n"
def test_stop_app():
@@ -298,8 +300,8 @@ def test_update_missing_app():
['dcos', 'app', 'update', 'missing-id'])
assert returncode == 1
assert stdout == b"Error: App '/missing-id' does not exist\n"
assert stderr == b''
assert stdout == b''
assert stderr == b"Error: App '/missing-id' does not exist\n"
def test_update_missing_field():
@@ -309,10 +311,10 @@ def test_update_missing_field():
['dcos', 'app', 'update', 'zero-instance-app', 'missing="a string"'])
assert returncode == 1
assert stdout.decode('utf-8').startswith(
assert stdout == b''
assert stderr.decode('utf-8').startswith(
"The property 'missing' does not conform to the expected format. "
"Possible values are: ")
assert stderr == b''
_remove_app('zero-instance-app')
@@ -324,10 +326,10 @@ def test_update_bad_type():
['dcos', 'app', 'update', 'zero-instance-app', 'cpus="a string"'])
assert returncode == 1
assert stdout.decode('utf-8').startswith(
assert stderr.decode('utf-8').startswith(
"Unable to parse 'a string' as a float: could not convert string to "
"float: ")
assert stderr == b''
assert stdout == b''
_remove_app('zero-instance-app')
@@ -375,8 +377,8 @@ def test_restarting_missing_app():
['dcos', 'app', 'restart', 'missing-id'])
assert returncode == 1
assert stdout == b"Error: App '/missing-id' does not exist\n"
assert stderr == b''
assert stdout == b''
assert stderr == b"Error: App '/missing-id' does not exist\n"
def test_restarting_app():
@@ -400,8 +402,8 @@ def test_list_version_missing_app():
['dcos', 'app', 'version', 'list', 'missing-id'])
assert returncode == 1
assert stdout == b"Error: App '/missing-id' does not exist\n"
assert stderr == b''
assert stdout == b''
assert stderr == b"Error: App '/missing-id' does not exist\n"
def test_list_version_negative_max_count():
@@ -409,8 +411,8 @@ def test_list_version_negative_max_count():
['dcos', 'app', 'version', 'list', 'missing-id', '--max-count=-1'])
assert returncode == 1
assert stdout == b'Maximum count must be a positive number: -1\n'
assert stderr == b''
assert stdout == b''
assert stderr == b'Maximum count must be a positive number: -1\n'
def test_list_version_app():
@@ -468,9 +470,9 @@ def test_rollback_missing_deployment():
['dcos', 'app', 'deployment', 'rollback', 'missing-deployment'])
assert returncode == 1
assert (stdout ==
assert stdout == b''
assert (stderr ==
b'Error: DeploymentPlan missing-deployment does not exist\n')
assert stderr == b''
def test_rollback_deployment():
@@ -557,6 +559,37 @@ def test_list_missing_app_tasks():
_remove_app('zero-instance-app')
def test_show_missing_task():
returncode, stdout, stderr = exec_command(
['dcos', 'app', 'task', 'show', 'missing-id'])
stderr = stderr.decode('utf-8')
assert returncode == 1
assert stdout == b''
assert stderr.startswith("Task '")
assert stderr.endswith("' does not exist\n")
def test_show_task():
_add_app('tests/data/marathon/zero_instance_sleep.json')
_start_app('zero-instance-app', 3)
result = _list_deployments(1, 'zero-instance-app')
_watch_deployment(result[0]['id'], 60)
result = _list_tasks(3, 'zero-instance-app')
returncode, stdout, stderr = exec_command(
['dcos', 'app', 'task', 'show', result[0]['id']])
result = json.loads(stdout.decode('utf-8'))
assert returncode == 0
assert result['appId'] == '/zero-instance-app'
assert stderr == b''
_remove_app('zero-instance-app')
def _list_apps(app_id=None):
returncode, stdout, stderr = exec_command(['dcos', 'app', 'list'])