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
|
"""List dcos services
|
||||||
|
|
||||||
:param inactive: If True, include completed tasks
|
:param inactive: If True, include completed tasks
|
||||||
:type completed: bool
|
:type inactive: bool
|
||||||
:param is_json: If true, output json.
|
:param is_json: If true, output json.
|
||||||
Otherwise, output a human readable table.
|
Otherwise, output a human readable table.
|
||||||
:type is_json: bool
|
:type is_json: bool
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import copy
|
import copy
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from dcos import util
|
from dcos import mesos, util
|
||||||
|
|
||||||
|
|
||||||
def task_table(tasks):
|
def task_table(tasks):
|
||||||
@@ -276,3 +276,21 @@ def package_search_table(search_results):
|
|||||||
tb.align['DESCRIPTION'] = 'l'
|
tb.align['DESCRIPTION'] = 'l'
|
||||||
|
|
||||||
return tb
|
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-package=dcoscli.package.main:main',
|
||||||
'dcos-service=dcoscli.service.main:main',
|
'dcos-service=dcoscli.service.main:main',
|
||||||
'dcos-task=dcoscli.task.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
|
\tconfig \tGet and set DCOS CLI configuration properties
|
||||||
\thelp \tDisplay command line usage information
|
\thelp \tDisplay command line usage information
|
||||||
\tmarathon \tDeploy and manage applications on the DCOS
|
\tmarathon \tDeploy and manage applications on the DCOS
|
||||||
|
\tnode \tManage DCOS nodes
|
||||||
\tpackage \tInstall and manage DCOS software packages
|
\tpackage \tInstall and manage DCOS software packages
|
||||||
\tservice \tManage DCOS services
|
\tservice \tManage DCOS services
|
||||||
\ttask \tManage DCOS tasks
|
\ttask \tManage DCOS tasks
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ Available DCOS commands:
|
|||||||
\tconfig \tGet and set DCOS CLI configuration properties
|
\tconfig \tGet and set DCOS CLI configuration properties
|
||||||
\thelp \tDisplay command line usage information
|
\thelp \tDisplay command line usage information
|
||||||
\tmarathon \tDeploy and manage applications on the DCOS
|
\tmarathon \tDeploy and manage applications on the DCOS
|
||||||
|
\tnode \tManage DCOS nodes
|
||||||
\tpackage \tInstall and manage DCOS software packages
|
\tpackage \tInstall and manage DCOS software packages
|
||||||
\tservice \tManage DCOS services
|
\tservice \tManage DCOS services
|
||||||
\ttask \tManage DCOS tasks
|
\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 ..fixtures.service import framework_fixture
|
||||||
from .common import (assert_command, assert_lines, delete_zk_nodes,
|
from .common import (assert_command, assert_lines, delete_zk_nodes,
|
||||||
exec_command, get_services, service_shutdown,
|
get_services, service_shutdown, watch_all_deployments)
|
||||||
watch_all_deployments)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
@@ -50,8 +49,6 @@ def test_info():
|
|||||||
|
|
||||||
|
|
||||||
def test_service():
|
def test_service():
|
||||||
returncode, stdout, stderr = exec_command(['dcos', 'service', '--json'])
|
|
||||||
|
|
||||||
services = get_services(1)
|
services = get_services(1)
|
||||||
|
|
||||||
schema = _get_schema(framework_fixture())
|
schema = _get_schema(framework_fixture())
|
||||||
@@ -63,17 +60,6 @@ def test_service_table():
|
|||||||
assert_lines(['dcos', 'service'], 2)
|
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):
|
def test_service_inactive(zk_znode):
|
||||||
# install cassandra
|
# install cassandra
|
||||||
stdout = b"""The Apache Cassandra DCOS Service implementation is alpha \
|
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
|
# assert marathon is only listed with --inactive
|
||||||
get_services(1, ['--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,
|
from ..fixtures.marathon import (app_fixture, app_task_fixture,
|
||||||
deployment_fixture, group_fixture)
|
deployment_fixture, group_fixture)
|
||||||
|
from ..fixtures.node import slave_fixture
|
||||||
from ..fixtures.package import package_fixture, search_result_fixture
|
from ..fixtures.package import package_fixture, search_result_fixture
|
||||||
from ..fixtures.service import framework_fixture
|
from ..fixtures.service import framework_fixture
|
||||||
from ..fixtures.task import task_fixture
|
from ..fixtures.task import task_fixture
|
||||||
@@ -55,6 +56,12 @@ def test_package_search_table():
|
|||||||
'tests/unit/data/package_search.txt')
|
'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):
|
def _test_table(table_fn, fixture_fn, path):
|
||||||
table = table_fn([fixture_fn()])
|
table = table_fn([fixture_fn()])
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
|
|||||||
@@ -90,6 +90,16 @@ class MesosClient:
|
|||||||
url = self.slave_url(slave_id, 'state.json')
|
url = self.slave_url(slave_id, 'state.json')
|
||||||
return http.get(url).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):
|
def shutdown_framework(self, framework_id):
|
||||||
"""Shuts down a Mesos framework
|
"""Shuts down a Mesos framework
|
||||||
|
|
||||||
@@ -696,6 +706,20 @@ class MesosFile(object):
|
|||||||
return "{0}:{1}".format(self._task['id'], self._path)
|
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):
|
def _merge(d, keys):
|
||||||
""" Merge multiple lists from a dictionary into one iterator.
|
""" Merge multiple lists from a dictionary into one iterator.
|
||||||
e.g. _merge({'a': [1, 2], 'b': [3]}, ['a', 'b']) ->
|
e.g. _merge({'a': [1, 2], 'b': [3]}, ['a', 'b']) ->
|
||||||
|
|||||||
Reference in New Issue
Block a user