Skip to content

Commit 23a8d36

Browse files
author
Davide Schiera
committed
create_dashboard, add_dashboard_panel, remove_dashboard_panel, find_dashboard_by
* create_dashboard: creates and empty dashboard * add_dashboard_panel: adds a panel to an existing dashboard (time series, top charts, number panel are supported) * remove_dashboard_panel: removes the panel with the specified name * find_dashboard_by: finds a dashboard with the given name Complete example of 1) create a dashboard, 2) find the dashboard by name, 3) add 3 panels, 4) remove a panel, 5) delete the dashboard.
1 parent ecaceb6 commit 23a8d36

File tree

2 files changed

+322
-0
lines changed

2 files changed

+322
-0
lines changed

examples/dashboard.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/usr/bin/env python
2+
#
3+
# TODO Description
4+
#
5+
6+
import os
7+
import sys
8+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..'))
9+
from sdcclient import SdcClient
10+
11+
#
12+
# Parse arguments
13+
#
14+
if len(sys.argv) != 2:
15+
print 'usage: %s <sysdig-token>' % sys.argv[0]
16+
print 'You can find your token at https://app.sysdigcloud.com/#/settings/user'
17+
sys.exit(1)
18+
19+
sdc_token = sys.argv[1]
20+
21+
#
22+
# Instantiate the SDC client
23+
#
24+
sdclient = SdcClient(sdc_token)
25+
26+
27+
#
28+
# Create an empty dashboard
29+
#
30+
dashboard_name = 'My Dashboard'
31+
dashboard_configuration = None
32+
res = sdclient.create_dashboard(dashboard_name)
33+
34+
# Check the result
35+
if res[0]:
36+
print 'Dashboard %d created successfully' % res[1]['dashboard']['id']
37+
dashboard_configuration = res[1]['dashboard']
38+
else:
39+
print res[1]
40+
sys.exit(1)
41+
42+
43+
#
44+
# Find a dashboard by name
45+
#
46+
res = sdclient.find_dashboard_by(dashboard_name)
47+
48+
# Check the result
49+
if res[0] and len(res[1]) > 0:
50+
print 'Dashboard found'
51+
dashboard_configuration = res[1][0]['dashboard']
52+
else:
53+
print res[1]
54+
sys.exit(1)
55+
56+
57+
#
58+
# Add a time series
59+
#
60+
panel_name = 'CPU Over Time'
61+
panel_type = 'timeSeries'
62+
metrics = [
63+
{ 'id': 'timestamp' },
64+
{ 'id': 'kubernetes.pod.name' },
65+
{ 'id': 'cpu.used.percent', 'aggregations': { 'time': 'avg', 'group': 'avg' } }
66+
]
67+
scope = 'kubernetes.namespace.name = "dev" and kubernetes.replicationController.name = "cassandra"'
68+
res = sdclient.add_dashboard_panel(dashboard_configuration, panel_name, panel_type, metrics, scope=scope)
69+
70+
# Check the result
71+
if res[0]:
72+
print 'Panel added successfully'
73+
dashboard_configuration = res[1]['dashboard']
74+
else:
75+
print res[1]
76+
sys.exit(1)
77+
78+
79+
#
80+
# Add a top bar chart
81+
#
82+
panel_name = 'CPU by host'
83+
panel_type = 'top'
84+
metrics = [
85+
{ 'id': 'host.hostName' },
86+
{ 'id': 'cpu.used.percent', 'aggregations': { 'time': 'avg', 'group': 'avg' } }
87+
]
88+
sort_by = { 'metric': 'cpu.used.percent', 'mode': 'desc' }
89+
paging = { 'from': 0, 'to': 10 }
90+
res = sdclient.add_dashboard_panel(dashboard_configuration, panel_name, panel_type, metrics, sort_by=sort_by, paging=paging)
91+
92+
# Check the result
93+
if res[0]:
94+
print 'Panel added successfully'
95+
dashboard_configuration = res[1]['dashboard']
96+
else:
97+
print res[1]
98+
sys.exit(1)
99+
100+
101+
#
102+
# Add a number panel
103+
#
104+
panel_name = 'CPU'
105+
panel_type = 'number'
106+
metrics = [
107+
{ 'id': 'cpu.used.percent', 'aggregations': { 'time': 'avg', 'group': 'avg' } }
108+
]
109+
layout = { 'col': 6, 'row': 1, 'size_x': 2, 'size_y': 3 }
110+
res = sdclient.add_dashboard_panel(dashboard_configuration, panel_name, panel_type, metrics, layout=layout)
111+
112+
# Check the result
113+
if res[0]:
114+
print 'Panel added successfully'
115+
dashboard_configuration = res[1]['dashboard']
116+
else:
117+
print res[1]
118+
sys.exit(1)
119+
120+
121+
#
122+
# Remove a panel
123+
#
124+
res = sdclient.remove_dashboard_panel(dashboard_configuration, 'CPU')
125+
126+
# Check the result
127+
if res[0]:
128+
print 'Panel removed successfully'
129+
dashboard_configuration = res[1]['dashboard']
130+
else:
131+
print res[1]
132+
sys.exit(1)
133+
134+
135+
#
136+
# Delete the dashboard
137+
#
138+
res = sdclient.delete_dashboard(dashboard_configuration)
139+
140+
# Check the result
141+
if res[0]:
142+
print 'Dashboard deleted successfully'
143+
else:
144+
print res[1]
145+
sys.exit(1)

sdcclient/_client.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import json
33
import requests
4+
import copy
45

56
class SdcClient:
67
userinfo = None
@@ -345,6 +346,182 @@ def get_dashboards(self):
345346
return [False, self.lasterr]
346347
return [True, r.json()]
347348

349+
def find_dashboard_by(self, name=None):
350+
r = self.get_dashboards()
351+
if r[0] == False:
352+
return r
353+
else:
354+
def filterFn(json):
355+
return json['name'] == name
356+
def set(dashboard_configuration):
357+
return { 'dashboard': dashboard_configuration }
358+
359+
dashboards = map(set, filter(filterFn, r[1]['dashboards']))
360+
return [True, dashboards]
361+
362+
def create_dashboard(self, name):
363+
dashboard_configuration = {
364+
'name': name,
365+
'schema': 1,
366+
'items': []
367+
}
368+
369+
#
370+
# Create the new dashboard
371+
#
372+
r = requests.post(self.url + '/ui/dashboards', headers=self.hdrs, data=json.dumps({ 'dashboard': dashboard_configuration }))
373+
if not self.__checkResponse(r):
374+
return [False, self.lasterr]
375+
else:
376+
return [True, r.json()]
377+
378+
def add_dashboard_panel(self, dashboard, name, type, metrics, scope=None, sort_by=None, paging=None, layout=None):
379+
panel_configuration = {
380+
'name': name,
381+
'showAs': None,
382+
'showAsType': None,
383+
'format': None,
384+
'metrics': [],
385+
'filter': None,
386+
'gridConfiguration': {
387+
'col': 1,
388+
'row': 1,
389+
'size_x': 12,
390+
'size_y': 6
391+
}
392+
}
393+
394+
#
395+
# Convert list of metrics to format used by Sysdig Cloud
396+
#
397+
property_names = {}
398+
for i, metric in enumerate(metrics):
399+
property_name = 'v' if 'aggregations' in metric else 'k'
400+
property_names[metric['id']] = property_name + str(i)
401+
402+
panel_configuration['metrics'].append({
403+
'metricId': metric['id'],
404+
'aggregation': metric['aggregations']['time'] if 'aggregations' in metric else None,
405+
'groupAggregation': metric['aggregations']['group'] if 'aggregations' in metric else None,
406+
'propertyName': property_name + str(i)
407+
})
408+
#
409+
# Convert scope to format used by Sysdig Cloud
410+
#
411+
if scope != None:
412+
filter_expressions = scope.strip(' \t\n\r?!.').split(" and ")
413+
filters = []
414+
415+
for filter_expression in filter_expressions:
416+
values = filter_expression.strip(' \t\n\r?!.').split("=")
417+
if len(values) != 2:
418+
return [False, "invalid scope format"]
419+
filters.append({
420+
'metric': values[0].strip(' \t\n\r?!.'),
421+
'op': '=',
422+
'value': values[1].strip(' \t\n\r"?!.'),
423+
'filters': None
424+
})
425+
426+
if len(filters) > 0:
427+
panel_configuration['filter'] = {
428+
'filters': {
429+
'logic': 'and',
430+
'filters': filters
431+
}
432+
}
433+
434+
#
435+
# Configure panel type
436+
#
437+
if type == 'timeSeries':
438+
panel_configuration['showAs'] = 'timeSeries'
439+
panel_configuration['showAsType'] = 'line'
440+
elif type == 'number':
441+
panel_configuration['showAs'] = 'summary'
442+
panel_configuration['showAsType'] = 'summary'
443+
elif type == 'top':
444+
panel_configuration['showAs'] = 'top'
445+
panel_configuration['showAsType'] = 'bars'
446+
447+
if sort_by == None:
448+
panel_configuration['sorting'] = [{
449+
'id': 'v0',
450+
'mode': 'desc'
451+
}]
452+
else:
453+
panel_configuration['sorting'] = [{
454+
'id': property_names[sort_by['metric']],
455+
'mode': sort_by['mode']
456+
}]
457+
458+
if paging == None:
459+
panel_configuration['paging'] = {
460+
'from': 0,
461+
'to': 10
462+
}
463+
else:
464+
panel_configuration['paging'] = paging
465+
466+
467+
#
468+
# Configure layout
469+
#
470+
if layout != None:
471+
panel_configuration['gridConfiguration'] = layout
472+
473+
#
474+
# Clone existing dashboard...
475+
#
476+
dashboard_configuration = copy.deepcopy(dashboard)
477+
dashboard_configuration['id'] = None
478+
479+
#
480+
# ... and add the new panel
481+
#
482+
dashboard_configuration['items'].append(panel_configuration)
483+
484+
#
485+
# Update dashboard
486+
#
487+
r = requests.put(self.url + '/ui/dashboards/' + str(dashboard['id']), headers=self.hdrs, data=json.dumps({ 'dashboard': dashboard_configuration }))
488+
if not self.__checkResponse(r):
489+
return [False, self.lasterr]
490+
else:
491+
return [True, r.json()]
492+
493+
def remove_dashboard_panel(self, dashboard, panel_name):
494+
#
495+
# Clone existing dashboard...
496+
#
497+
dashboard_configuration = copy.deepcopy(dashboard)
498+
dashboard_configuration['id'] = None
499+
500+
#
501+
# ... find the panel
502+
#
503+
def filterFn(panel):
504+
return panel['name'] == panel_name
505+
panels = filter(filterFn, dashboard_configuration['items'])
506+
507+
if len(panels) > 0:
508+
#
509+
# ... and remove it
510+
#
511+
for panel in panels:
512+
dashboard_configuration['items'].remove(panel)
513+
514+
#
515+
# Update dashboard
516+
#
517+
r = requests.put(self.url + '/ui/dashboards/' + str(dashboard['id']), headers=self.hdrs, data=json.dumps({ 'dashboard': dashboard_configuration }))
518+
if not self.__checkResponse(r):
519+
return [False, self.lasterr]
520+
else:
521+
return [True, r.json()]
522+
else:
523+
return [False, 'Not found']
524+
348525
def create_dashboard_from_template(self, newdashname, template, scope):
349526
if scope is None:
350527
scope = []

0 commit comments

Comments
 (0)