Skip to content

Commit

Permalink
Add percentage in nodes list
Browse files Browse the repository at this point in the history
Add filter by node name in app list
Add hostname to logs format
  • Loading branch information
eugenepaniot committed Jun 28, 2018
1 parent f69ed69 commit bcbc3d7
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 41 deletions.
38 changes: 24 additions & 14 deletions mesosrc/controllers/apps/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from collections import OrderedDict, defaultdict

from cement.core.controller import expose, CementBaseController


Expand All @@ -13,36 +12,47 @@ class Meta:
aliases = ['apps', 'app']
aliases_only = True

arguments = [
(['--app'], dict(help='Filter applications by marathon application id')),
(['--node'], dict(help='Filter applications by node hostname')),
]

@expose(hide=True)
def default(self):
self.list()

@expose(help="Get the list of running applications")
def list(self):
def pretty(data):
if 'apps' not in data:
return

for a in data['apps']:
for app in data:
tasksPerSlaves = defaultdict(int)

for t in a['tasks']:
for t in app['tasks']:
tasksPerSlaves[t['host']] += 1

ret = {
"ID": a['id'],
"Instances": a['instances'],
"Tasks staging, running": "%d/%d" % (a['tasksStaged'], a['tasksRunning']),
"ID": app['id'],
"Instances": app['instances'],
"Tasks running, staging": "%d/%d" % (app['tasksRunning'], app['tasksStaged']),
"Tasks healthy, unhealthy": "%d/%d" % (app['tasksHealthy'], app['tasksUnhealthy']),
"Tasks per slaves": '\n'.join("%s: %d" % (k, v) for (k, v) in tasksPerSlaves.items())
}

yield OrderedDict((k, ret[k])
for k in ['ID', 'Instances',
'Tasks staging, running',
'Tasks per slaves']
)

self.app.render(pretty(self.app.marathon.getApps()), headers="keys", tablefmt="fancy_grid")
'Tasks running, staging',
'Tasks healthy, unhealthy',
'Tasks per slaves'
])

if self.app.pargs.app:
data = [self.app.marathon.getAppByID(self.app.pargs.app)]
elif self.app.pargs.node:
data = [a for a in self.app.marathon.getAppsByNode(self.app.pargs.node)]
else:
data = self.app.marathon.getApps()

self.app.render(pretty(data), headers="keys", tablefmt="fancy_grid")

@expose(help="List all the tasks queued up or waiting to be scheduled", aliases=['q'])
def queue(self):
Expand Down
21 changes: 13 additions & 8 deletions mesosrc/controllers/nodes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from collections import OrderedDict
from cement.core.controller import expose, CementBaseController

from mesosrc.utils.core import percentage


class MesosNodeBaseController(CementBaseController):
class Meta:
Expand All @@ -9,7 +11,7 @@ class Meta:
stacked_type = 'nested'

description = "Mesos Nodes primitives"
aliases = ['nodes', 'node']
aliases = ['nodes', 'node', 'slave', 'slaves', 'agent', 'agents']
aliases_only = True

@expose(hide=True)
Expand Down Expand Up @@ -44,19 +46,22 @@ def get_resources(res):
ret = {
"ID": d['id'],
"Hostname": d['hostname'],
"Mesos Version / CCS Version": "%s/%s" % (d['version'], d['attributes'].get("ccs_version", "NA")),
"CPU (Total/Used)": "%s/%s" % (res_total['CPU'], res_used['CPU']),
"Memory (Total/Used),\nGB": "%s/%s" % (res_total['Memory'], res_used['Memory']),
"Tasks\nstaging, running, failed": "%d/%d/%d" % (ss_slave['TASK_STAGING'],
"Mesos Version/CCS Version": "%s/%s" % (d['version'], d['attributes'].get("ccs_version", "NA")),
"CPU (Total/Used, Used %)": "%s/%s, %.1f%%" % (res_total['CPU'], res_used['CPU'],
percentage(res_used['CPU'], res_total['CPU'])),
"Memory (Total/Used, Used %),\nGB": "%s/%s, %.1f%%" % (res_total['Memory'], res_used['Memory'],
percentage(res_used['Memory'],
res_total['Memory'])),
"Tasks\nstaging/running/failed": "%d/%d/%d" % (ss_slave['TASK_STAGING'],
ss_slave['TASK_RUNNING'],
ss_slave['TASK_FAILED']
)
}

yield OrderedDict((k, ret[k])
for k in ['ID', 'Hostname', 'CPU (Total/Used)',
'Memory (Total/Used),\nGB', 'Mesos Version / CCS Version',
'Tasks\nstaging, running, failed']
for k in ['ID', 'Hostname', 'CPU (Total/Used, Used %)',
'Memory (Total/Used, Used %),\nGB', 'Mesos Version/CCS Version',
'Tasks\nstaging/running/failed']
)

self.app.render(pretty(self.app.mesos.getSlaves()), headers="keys", tablefmt="fancy_grid")
4 changes: 2 additions & 2 deletions mesosrc/controllers/nodes/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ def safe_down(self):
apps = self.app.marathon.getApps()
for h in self.app.pargs.hostame.split(","):
if not self.app.mesos.getMaintenanceScheduleByHostname(h):
raise OperatorActionRequired("You should schedule maintenance for node '%s' first" % h)
raise OperatorActionRequired("You should schedule maintenance for the '%s' node first" % h)

for a in apps['apps']:
for a in apps:
for t in a['tasks']:
if t['host'] == h:
if a['id'] not in tasksPerHost:
Expand Down
18 changes: 9 additions & 9 deletions mesosrc/controllers/tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ def getColor(id, source=None):
add = attr('bold')

if self.app.pargs.colored:
u = str(uuid.uuid3(uuid.NAMESPACE_OID, id))
id = ''.join([i for i in u if i.isalpha()])
return fg(int(id, 36) % 256) + add
u = str(uuid.uuid3(uuid.NAMESPACE_OID, str(id)))
return fg(int(u.replace('-', ''), 36) % 256) + add
else:
return attr('reset')

Expand All @@ -66,7 +65,7 @@ def getDirectoryByID(state, id):
readedFiles = defaultdict(int)
while True:
try:
for task in self.app.marathon.getAppByID(self.app.pargs.app)['app']['tasks']:
for task in self.app.marathon.getAppByID(self.app.pargs.app)['tasks']:
mesos_task = self.app.mesos.getTaskByID(task['id'])['tasks'][0]

slave = self.app.mesos.getSlaveByID(mesos_task['slave_id'])['slaves'][0]
Expand Down Expand Up @@ -97,11 +96,12 @@ def getDirectoryByID(state, id):
if not data:
break

print("%s%s | %s | %s %s\n" % (
getColor(mesos_task['id']+mesos_task['slave_id'], f),
f, mesos_task['id'], data,
attr('reset')
))
print(u"%s%s | %s | %s | %s %s\n" %
(
getColor(mesos_task['id'], f),
f, mesos_task['id'], slave['hostname'], data,
attr('reset')
))

readedFiles[file] += len(data)

Expand Down
12 changes: 9 additions & 3 deletions mesosrc/drivers/MarathonRequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,18 @@ def getAddress(self):
return address

def getApps(self):
return self.urlOpenJsonToObject("/v2/apps?embed=apps.tasks")
return self.urlOpenJsonToObject("/v2/apps?embed=apps.tasks")['apps']

def getAppByID(self, id):
assert id, "Task ID is required"

return self.urlOpenJsonToObject("/v2/apps/%s?embed=apps.tasks" % id)
return self.urlOpenJsonToObject("/v2/apps/%s?embed=apps.tasks" % id)['app']

def getAppsByNode(self, node):
for app in self.getApps():
for task in app['tasks']:
if task['host'] == node:
yield app

def getQueue(self):
return self.urlOpenJsonToObject("/v2/queue")
Expand All @@ -73,7 +79,7 @@ def awaitForDeploymentID(self, id, maxTries=1800, rollBack=True):
raise MaxTriesExceeded(currentTries, maxTries, "Deployment %s failed" % id)

currentTries += 1
if currentTries % 3 == 0:
if currentTries % 5 == 0:
self.logger.info("Awaiting(%d/%d) for deploymentId: %s" % (currentTries, maxTries,
id))
sleep(1)
Expand Down
11 changes: 11 additions & 0 deletions mesosrc/utils/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,14 @@ def to_bool(value):
return valid[lower_value]
else:
raise ValueError('invalid literal for boolean: "%s"' % value)


def percentage(part, whole):
try:
part = float(part)
whole = float(whole)
except ValueError:
whole = 1
part = 0

return 100 * float(part)/float(whole)
7 changes: 2 additions & 5 deletions mesosrccli
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ except ImportError:
from ConfigParser import NoSectionError

import requests
import traceback
import sys

from cement.ext.ext_colorlog import ColorLogHandler
Expand Down Expand Up @@ -100,20 +99,18 @@ class MesosLogHandler(ColorLogHandler):

config_defaults = dict(
file=None,
level='DBEUG',
level='INFO',
to_console=True,
rotate=False,
max_bytes=512000,
max_files=4,
colorize_file_log=False,
colorize_console_log=True,
)


class MesosBaseController(CementBaseController):
class Meta:
label = 'base'
description = "Mesos RingCentral CLI"
description = "RingCentral Mesos CLI"
stacked_on = 'base'

@expose(hide=True)
Expand Down

0 comments on commit bcbc3d7

Please sign in to comment.