Skip to content

Commit

Permalink
Merge pull request #195 from mesosphere/dcos-514-deployment-list
Browse files Browse the repository at this point in the history
DCOS-514: use readable tables in the output of many commands
  • Loading branch information
mgummelt committed Jun 4, 2015
2 parents 060eb3c + 5025920 commit c14e44d
Show file tree
Hide file tree
Showing 28 changed files with 978 additions and 337 deletions.
91 changes: 40 additions & 51 deletions cli/dcoscli/marathon/main.py
Expand Up @@ -13,25 +13,31 @@
dcos marathon app stop [--force] <app-id>
dcos marathon app update [--force] <app-id> [<properties>...]
dcos marathon app version list [--max-count=<max-count>] <app-id>
dcos marathon deployment list [<app-id>]
dcos marathon deployment list [--json <app-id>]
dcos marathon deployment rollback <deployment-id>
dcos marathon deployment stop <deployment-id>
dcos marathon deployment watch [--max-count=<max-count>]
[--interval=<interval>] <deployment-id>
dcos marathon task list [<app-id>]
dcos marathon task list [--json <app-id>]
dcos marathon task show <task-id>
dcos marathon group add [<group-resource>]
dcos marathon group list
dcos marathon group list [--json]
dcos marathon group show [--group-version=<group-version>] <group-id>
dcos marathon group remove [--force] <group-id>
Options:
-h, --help Show this screen
--info Show a short description of this
subcommand
--json Print json-formatted tasks
--version Show version
--force This flag disable checks in Marathon
during update operations
--app-version=<app-version> This flag specifies the application
version to use for the command. The
application version (<app-version>) can be
Expand All @@ -42,6 +48,7 @@
integer and they represent the version
from the currently deployed application
definition
--group-version=<group-version> This flag specifies the group version to
use for the command. The group version
(<group-version>) can be specified as an
Expand All @@ -51,38 +58,48 @@
specified as a negative integer and they
represent the version from the currently
deployed group definition
--config-schema Show the configuration schema for the
Marathon subcommand
--max-count=<max-count> Maximum number of entries to try to fetch
and return
--interval=<interval> Number of seconds to wait between actions
Positional Arguments:
<app-id> The application id
<app-resource> The application resource; for a detailed
description see (https://mesosphere.github.io/
marathon/docs/rest-api.html#post-/v2/apps)
<deployment-id> The deployment id
<group-id> The group id
<group-resource> The group resource; for a detailed description
see (https://mesosphere.github.io/marathon/docs
/rest-api.html#post-/v2/groups)
<instances> The number of instances to start
<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 sys
import time
from collections import OrderedDict

import dcoscli
import docopt
import pkg_resources
from dcos import cmds, emitting, jsonitem, marathon, options, util
from dcos.errors import DCOSException
from dcoscli import tables

logger = util.get_logger(__name__)
emitter = emitting.FlatEmitter()
Expand Down Expand Up @@ -120,7 +137,7 @@ def _cmds():

cmds.Command(
hierarchy=['marathon', 'deployment', 'list'],
arg_keys=['<app-id>'],
arg_keys=['<app-id>', '--json'],
function=_deployment_list),

cmds.Command(
Expand All @@ -140,7 +157,7 @@ def _cmds():

cmds.Command(
hierarchy=['marathon', 'task', 'list'],
arg_keys=['<app-id>'],
arg_keys=['<app-id>', '--json'],
function=_task_list),

cmds.Command(
Expand Down Expand Up @@ -195,7 +212,7 @@ def _cmds():

cmds.Command(
hierarchy=['marathon', 'group', 'list'],
arg_keys=[],
arg_keys=['--json'],
function=_group_list),

cmds.Command(
Expand Down Expand Up @@ -319,37 +336,6 @@ def _add(app_resource):
return 0


def _app_table(apps):
def get_cmd(app):
if app["cmd"] is not None:
return app["cmd"]
else:
return app["args"]

def get_container(app):
if app["container"] is not None:
return app["container"]["type"]
else:
return "null"

fields = OrderedDict([
("id", lambda a: a["id"]),
("mem", lambda a: a["mem"]),
("cpus", lambda a: a["cpus"]),
("deployments", lambda a: len(a["deployments"])),
("instances", lambda a: "{}/{}".format(a["tasksRunning"],
a["instances"])),
("container", get_container),
("cmd", get_cmd)
])

tb = util.table(fields, apps)
tb.align["CMD"] = "l"
tb.align["ID"] = "l"

return tb


def _list(json_):
"""
:param json_: output json if True
Expand All @@ -361,26 +347,22 @@ def _list(json_):
client = marathon.create_client()
apps = client.get_apps()

if json_:
emitter.publish(apps)
else:
table = _app_table(apps)
output = str(table)
if output:
emitter.publish(output)
emitting.publish_table(emitter, apps, tables.app_table, json_)
return 0


def _group_list():
def _group_list(json_):
"""
:param json_: output json if True
:type json_: bool
:returns: process status
:rtype: int
"""

client = marathon.create_client()
groups = client.get_groups()

emitter.publish(groups)
emitting.publish_table(emitter, groups, tables.group_table, json_)
return 0


Expand Down Expand Up @@ -665,10 +647,12 @@ def _version_list(app_id, max_count):
return 0


def _deployment_list(app_id):
def _deployment_list(app_id, json_):
"""
:param app_id: the application id
:type app_id: str
:param json_: output json if True
:type json_: bool
:returns: process status
:rtype: int
"""
Expand All @@ -677,7 +661,10 @@ def _deployment_list(app_id):

deployments = client.get_deployments(app_id)

emitter.publish(deployments)
emitting.publish_table(emitter,
deployments,
tables.deployment_table,
json_)
return 0


Expand Down Expand Up @@ -743,18 +730,20 @@ def _deployment_watch(deployment_id, max_count, interval):
return 0


def _task_list(app_id):
def _task_list(app_id, json_):
"""
:param app_id: the id of the application
:type app_id: str
:param json_: output json if True
:type json_: bool
:returns: process status
:rtype: int
"""

client = marathon.create_client()
tasks = client.get_tasks(app_id)

emitter.publish(tasks)
emitting.publish_table(emitter, tasks, tables.app_task_table, json_)
return 0


Expand Down
31 changes: 19 additions & 12 deletions cli/dcoscli/package/main.py
Expand Up @@ -7,8 +7,8 @@
dcos package info
dcos package install [--cli | [--app --app-id=<app_id>]]
[--options=<file> --yes] <package_name>
dcos package list [--endpoints --app-id=<app-id> <package_name>]
dcos package search [<query>]
dcos package list [--json --endpoints --app-id=<app-id> <package_name>]
dcos package search [--json <query>]
dcos package sources
dcos package uninstall [--cli | [--app --app-id=<app-id> --all]]
<package_name>
Expand Down Expand Up @@ -53,6 +53,7 @@
import pkg_resources
from dcos import cmds, emitting, marathon, options, package, subcommand, util
from dcos.errors import DCOSException
from dcoscli import tables

logger = util.get_logger(__name__)

Expand Down Expand Up @@ -107,12 +108,12 @@ def _cmds():

cmds.Command(
hierarchy=['package', 'list'],
arg_keys=['--endpoints', '--app-id', '<package_name>'],
arg_keys=['--json', '--endpoints', '--app-id', '<package_name>'],
function=_list),

cmds.Command(
hierarchy=['package', 'search'],
arg_keys=['<query>'],
arg_keys=['--json', '<query>'],
function=_search),

cmds.Command(
Expand Down Expand Up @@ -358,9 +359,11 @@ def _install(package_name, options_path, app_id, cli, app, yes):
return 0


def _list(endpoints, app_id, package_name):
"""Show installed apps
def _list(json_, endpoints, app_id, package_name):
"""List installed apps
:param json_: output json if True
:type json_: bool
:param endpoints: Whether to include a list of
endpoints as port-host pairs
:type endpoints: boolean
Expand Down Expand Up @@ -391,8 +394,7 @@ def _list(endpoints, app_id, package_name):

results.append(pkg_info)

emitter.publish(results)

emitting.publish_table(emitter, results, tables.package_table, json_)
return 0


Expand Down Expand Up @@ -424,9 +426,11 @@ def _matches_app_id(app_id, pkg_info):
return app_id is None or app_id in pkg_info.get('apps')


def _search(query):
def _search(json_, query):
"""Search for matching packages.
:param json_: output json if True
:type json_: bool
:param query: The search term
:type query: str
:returns: Process status
Expand All @@ -436,10 +440,13 @@ def _search(query):
query = ''

config = util.get_config()
results = package.search(query, config)

emitter.publish([r.as_dict() for r in results])
results = [index_entry.as_dict()
for index_entry in package.search(query, config)]

emitting.publish_table(emitter,
results,
tables.package_search_table,
json_)
return 0


Expand Down
46 changes: 2 additions & 44 deletions cli/dcoscli/service/main.py
Expand Up @@ -22,15 +22,11 @@
<service-id> The ID for the DCOS Service
"""


from collections import OrderedDict

import blessings
import dcoscli
import docopt
import prettytable
from dcos import cmds, emitting, mesos, util
from dcos.errors import DCOSException
from dcoscli import tables

logger = util.get_logger(__name__)
emitter = emitting.FlatEmitter()
Expand Down Expand Up @@ -89,44 +85,6 @@ def _info():
return 0


def _service_table(services):
"""Returns a PrettyTable representation of the provided services.
:param services: services to render
:type services: [Framework]
:rtype: TaskTable
"""

term = blessings.Terminal()

table_generator = OrderedDict([
("name", lambda s: s['name']),
("host", lambda s: s['hostname']),
("active", lambda s: s['active']),
("tasks", lambda s: len(s['tasks'])),
("cpu", lambda s: s['resources']['cpus']),
("mem", lambda s: s['resources']['mem']),
("disk", lambda s: s['resources']['disk']),
("ID", lambda s: s['id']),
])

tb = prettytable.PrettyTable(
[k.upper() for k in table_generator.keys()],
border=False,
max_table_width=term.width,
hrules=prettytable.NONE,
vrules=prettytable.NONE,
left_padding_width=0,
right_padding_width=1
)

for service in services:
row = [fn(service) for fn in table_generator.values()]
tb.add_row(row)

return tb


# TODO (mgummelt): support listing completed services as well.
# blocked on framework shutdown.
def _service(inactive, is_json):
Expand All @@ -146,7 +104,7 @@ def _service(inactive, is_json):
if is_json:
emitter.publish([service.dict() for service in services])
else:
table = _service_table(services)
table = tables.service_table(services)
output = str(table)
if output:
emitter.publish(output)
Expand Down

0 comments on commit c14e44d

Please sign in to comment.