dcos node
This commit is contained in:
0
cli/dcoscli/node/__init__.py
Normal file
0
cli/dcoscli/node/__init__.py
Normal file
92
cli/dcoscli/node/main.py
Normal file
92
cli/dcoscli/node/main.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""Manage DCOS nodes
|
||||
|
||||
Usage:
|
||||
dcos node --info
|
||||
dcos node [--json]
|
||||
|
||||
Options:
|
||||
-h, --help Show this screen
|
||||
--info Show a short description of this subcommand
|
||||
--json Print json-formatted nodes
|
||||
--version Show version
|
||||
"""
|
||||
|
||||
import dcoscli
|
||||
import docopt
|
||||
from dcos import cmds, emitting, errors, mesos, util
|
||||
from dcos.errors import DCOSException
|
||||
from dcoscli import tables
|
||||
|
||||
logger = util.get_logger(__name__)
|
||||
emitter = emitting.FlatEmitter()
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
return _main()
|
||||
except DCOSException as e:
|
||||
emitter.publish(e)
|
||||
return 1
|
||||
|
||||
|
||||
def _main():
|
||||
util.configure_logger_from_environ()
|
||||
|
||||
args = docopt.docopt(
|
||||
__doc__,
|
||||
version="dcos-node version {}".format(dcoscli.version))
|
||||
|
||||
return cmds.execute(_cmds(), args)
|
||||
|
||||
|
||||
def _cmds():
|
||||
"""
|
||||
:returns: All of the supported commands
|
||||
:rtype: [Command]
|
||||
"""
|
||||
|
||||
return [
|
||||
cmds.Command(
|
||||
hierarchy=['node', '--info'],
|
||||
arg_keys=[],
|
||||
function=_info),
|
||||
|
||||
cmds.Command(
|
||||
hierarchy=['node'],
|
||||
arg_keys=['--json'],
|
||||
function=_list),
|
||||
]
|
||||
|
||||
|
||||
def _info():
|
||||
"""Print node cli information.
|
||||
|
||||
:returns: process return code
|
||||
:rtype: int
|
||||
"""
|
||||
|
||||
emitter.publish(__doc__.split('\n')[0])
|
||||
return 0
|
||||
|
||||
|
||||
def _list(json_):
|
||||
"""List dcos nodes
|
||||
|
||||
:param json_: If true, output json.
|
||||
Otherwise, output a human readable table.
|
||||
:type json_: bool
|
||||
:returns: process return code
|
||||
:rtype: int
|
||||
"""
|
||||
|
||||
client = mesos.MesosClient()
|
||||
slaves = client.get_state_summary()['slaves']
|
||||
if json_:
|
||||
emitter.publish(slaves)
|
||||
else:
|
||||
table = tables.slave_table(slaves)
|
||||
output = str(table)
|
||||
if output:
|
||||
emitter.publish(output)
|
||||
else:
|
||||
emitter.publish(errors.DefaultError('No slaves found.'))
|
||||
@@ -91,7 +91,7 @@ def _service(inactive, is_json):
|
||||
"""List dcos services
|
||||
|
||||
:param inactive: If True, include completed tasks
|
||||
:type completed: bool
|
||||
:type inactive: bool
|
||||
:param is_json: If true, output json.
|
||||
Otherwise, output a human readable table.
|
||||
:type is_json: bool
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
from collections import OrderedDict
|
||||
|
||||
from dcos import util
|
||||
from dcos import mesos, util
|
||||
|
||||
|
||||
def task_table(tasks):
|
||||
@@ -276,3 +276,21 @@ def package_search_table(search_results):
|
||||
tb.align['DESCRIPTION'] = 'l'
|
||||
|
||||
return tb
|
||||
|
||||
|
||||
def slave_table(slaves):
|
||||
"""Returns a PrettyTable representation of the provided DCOS slaves
|
||||
|
||||
:param slaves: slaves to render. dicts from /mesos/state-summary
|
||||
:type slaves: [dict]
|
||||
:rtype: PrettyTable
|
||||
"""
|
||||
|
||||
fields = OrderedDict([
|
||||
('HOSTNAME', lambda s: s['hostname']),
|
||||
('IP', lambda s: mesos.parse_pid(s['pid'])[1]),
|
||||
('ID', lambda s: s['id'])
|
||||
])
|
||||
|
||||
tb = util.table(fields, slaves, sortby="HOSTNAME")
|
||||
return tb
|
||||
|
||||
@@ -97,6 +97,7 @@ setup(
|
||||
'dcos-package=dcoscli.package.main:main',
|
||||
'dcos-service=dcoscli.service.main:main',
|
||||
'dcos-task=dcoscli.task.main:main',
|
||||
'dcos-node=dcoscli.node.main:main'
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
40
cli/tests/fixtures/node.py
vendored
Normal file
40
cli/tests/fixtures/node.py
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
def slave_fixture():
|
||||
""" Slave node fixture.
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
return {
|
||||
"TASK_ERROR": 0,
|
||||
"TASK_FAILED": 0,
|
||||
"TASK_FINISHED": 0,
|
||||
"TASK_KILLED": 0,
|
||||
"TASK_LOST": 0,
|
||||
"TASK_RUNNING": 0,
|
||||
"TASK_STAGING": 0,
|
||||
"TASK_STARTING": 0,
|
||||
"active": True,
|
||||
"attributes": {},
|
||||
"framework_ids": [],
|
||||
"hostname": "dcos-01",
|
||||
"id": "20150630-004309-1695027628-5050-1649-S0",
|
||||
"offered_resources": {
|
||||
"cpus": 0,
|
||||
"disk": 0,
|
||||
"mem": 0
|
||||
},
|
||||
"pid": "slave(1)@172.17.8.101:5051",
|
||||
"registered_time": 1435625024.42234,
|
||||
"resources": {
|
||||
"cpus": 4,
|
||||
"disk": 10823,
|
||||
"mem": 2933,
|
||||
"ports": ("[1025-2180, 2182-3887, 3889-5049, 5052-8079, " +
|
||||
"8082-8180, 8182-65535]")
|
||||
},
|
||||
"used_resources": {
|
||||
"cpus": 0,
|
||||
"disk": 0,
|
||||
"mem": 0
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ Available DCOS commands:
|
||||
\tconfig \tGet and set DCOS CLI configuration properties
|
||||
\thelp \tDisplay command line usage information
|
||||
\tmarathon \tDeploy and manage applications on the DCOS
|
||||
\tnode \tManage DCOS nodes
|
||||
\tpackage \tInstall and manage DCOS software packages
|
||||
\tservice \tManage DCOS services
|
||||
\ttask \tManage DCOS tasks
|
||||
|
||||
@@ -39,6 +39,7 @@ Available DCOS commands:
|
||||
\tconfig \tGet and set DCOS CLI configuration properties
|
||||
\thelp \tDisplay command line usage information
|
||||
\tmarathon \tDeploy and manage applications on the DCOS
|
||||
\tnode \tManage DCOS nodes
|
||||
\tpackage \tInstall and manage DCOS software packages
|
||||
\tservice \tManage DCOS services
|
||||
\ttask \tManage DCOS tasks
|
||||
|
||||
44
cli/tests/integrations/test_node.py
Normal file
44
cli/tests/integrations/test_node.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import json
|
||||
|
||||
import dcos.util as util
|
||||
from dcos.util import create_schema
|
||||
|
||||
from ..fixtures.node import slave_fixture
|
||||
from .common import assert_command, assert_lines, exec_command
|
||||
|
||||
|
||||
def test_help():
|
||||
stdout = b"""Manage DCOS nodes
|
||||
|
||||
Usage:
|
||||
dcos node --info
|
||||
dcos node [--json]
|
||||
|
||||
Options:
|
||||
-h, --help Show this screen
|
||||
--info Show a short description of this subcommand
|
||||
--json Print json-formatted nodes
|
||||
--version Show version
|
||||
"""
|
||||
assert_command(['dcos', 'node', '--help'], stdout=stdout)
|
||||
|
||||
|
||||
def test_info():
|
||||
stdout = b"Manage DCOS nodes\n"
|
||||
assert_command(['dcos', 'node', '--info'], stdout=stdout)
|
||||
|
||||
|
||||
def test_node():
|
||||
returncode, stdout, stderr = exec_command(['dcos', 'node', '--json'])
|
||||
|
||||
assert returncode == 0
|
||||
assert stderr == b''
|
||||
|
||||
nodes = json.loads(stdout.decode('utf-8'))
|
||||
schema = create_schema(slave_fixture())
|
||||
for node in nodes:
|
||||
assert not util.validate_json(node, schema)
|
||||
|
||||
|
||||
def test_node_table():
|
||||
assert_lines(['dcos', 'node'], 2)
|
||||
@@ -7,8 +7,7 @@ import pytest
|
||||
|
||||
from ..fixtures.service import framework_fixture
|
||||
from .common import (assert_command, assert_lines, delete_zk_nodes,
|
||||
exec_command, get_services, service_shutdown,
|
||||
watch_all_deployments)
|
||||
get_services, service_shutdown, watch_all_deployments)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
@@ -50,8 +49,6 @@ def test_info():
|
||||
|
||||
|
||||
def test_service():
|
||||
returncode, stdout, stderr = exec_command(['dcos', 'service', '--json'])
|
||||
|
||||
services = get_services(1)
|
||||
|
||||
schema = _get_schema(framework_fixture())
|
||||
@@ -63,17 +60,6 @@ def test_service_table():
|
||||
assert_lines(['dcos', 'service'], 2)
|
||||
|
||||
|
||||
def _get_schema(service):
|
||||
schema = create_schema(service.dict())
|
||||
schema['required'].remove('reregistered_time')
|
||||
schema['required'].remove('pid')
|
||||
schema['properties']['offered_resources']['required'].remove('ports')
|
||||
schema['properties']['resources']['required'].remove('ports')
|
||||
schema['properties']['used_resources']['required'].remove('ports')
|
||||
|
||||
return schema
|
||||
|
||||
|
||||
def test_service_inactive(zk_znode):
|
||||
# install cassandra
|
||||
stdout = b"""The Apache Cassandra DCOS Service implementation is alpha \
|
||||
@@ -122,3 +108,14 @@ Thank you for installing the Apache Cassandra DCOS Service.
|
||||
|
||||
# assert marathon is only listed with --inactive
|
||||
get_services(1, ['--inactive'])
|
||||
|
||||
|
||||
def _get_schema(service):
|
||||
schema = create_schema(service.dict())
|
||||
schema['required'].remove('reregistered_time')
|
||||
schema['required'].remove('pid')
|
||||
schema['properties']['offered_resources']['required'].remove('ports')
|
||||
schema['properties']['resources']['required'].remove('ports')
|
||||
schema['properties']['used_resources']['required'].remove('ports')
|
||||
|
||||
return schema
|
||||
|
||||
2
cli/tests/unit/data/node.txt
Normal file
2
cli/tests/unit/data/node.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
HOSTNAME IP ID
|
||||
dcos-01 172.17.8.101 20150630-004309-1695027628-5050-1649-S0
|
||||
@@ -2,6 +2,7 @@ from dcoscli import tables
|
||||
|
||||
from ..fixtures.marathon import (app_fixture, app_task_fixture,
|
||||
deployment_fixture, group_fixture)
|
||||
from ..fixtures.node import slave_fixture
|
||||
from ..fixtures.package import package_fixture, search_result_fixture
|
||||
from ..fixtures.service import framework_fixture
|
||||
from ..fixtures.task import task_fixture
|
||||
@@ -55,6 +56,12 @@ def test_package_search_table():
|
||||
'tests/unit/data/package_search.txt')
|
||||
|
||||
|
||||
def test_node_table():
|
||||
_test_table(tables.slave_table,
|
||||
slave_fixture,
|
||||
'tests/unit/data/node.txt')
|
||||
|
||||
|
||||
def _test_table(table_fn, fixture_fn, path):
|
||||
table = table_fn([fixture_fn()])
|
||||
with open(path) as f:
|
||||
|
||||
@@ -90,6 +90,16 @@ class MesosClient:
|
||||
url = self.slave_url(slave_id, 'state.json')
|
||||
return http.get(url).json()
|
||||
|
||||
def get_state_summary(self):
|
||||
"""Get the Mesos master state summary json object
|
||||
|
||||
:returns: Mesos' master state summary json object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
url = self.master_url('master/state-summary')
|
||||
return http.get(url).json()
|
||||
|
||||
def shutdown_framework(self, framework_id):
|
||||
"""Shuts down a Mesos framework
|
||||
|
||||
@@ -696,6 +706,20 @@ class MesosFile(object):
|
||||
return "{0}:{1}".format(self._task['id'], self._path)
|
||||
|
||||
|
||||
def parse_pid(pid):
|
||||
""" Parse the mesos pid string,
|
||||
|
||||
:param pid: pid of the form "id@ip:port"
|
||||
:type pid: str
|
||||
:returns: parsed pid
|
||||
:rtype: (str, str, str)
|
||||
"""
|
||||
|
||||
id_, second = pid.split('@')
|
||||
ip, port = second.split(':')
|
||||
return id_, ip, port
|
||||
|
||||
|
||||
def _merge(d, keys):
|
||||
""" Merge multiple lists from a dictionary into one iterator.
|
||||
e.g. _merge({'a': [1, 2], 'b': [3]}, ['a', 'b']) ->
|
||||
|
||||
Reference in New Issue
Block a user