setup for basic openstack dashing
setup client handling for multiple services and regions shows cpu and ram totals across all given regions, shows cpu and ram per region can connect and show nagios status
This commit is contained in:
parent
bd9532d5ea
commit
493a398901
BIN
dashie.png
BIN
dashie.png
Binary file not shown.
Before Width: | Height: | Size: 164 KiB |
Binary file not shown.
Before Width: | Height: | Size: 43 KiB |
|
@ -49,7 +49,8 @@
|
|||
.widget.widget-progress-bars .outer-progress-bar .inner-progress-bar {
|
||||
background-color: #2391ab;
|
||||
border-radius: 0.35em;
|
||||
color: #ffffff; }
|
||||
color: #ffffff;
|
||||
white-space: pre; }
|
||||
.widget.widget-progress-bars .zebra-stripe {
|
||||
background-color: #57c3dd; }
|
||||
|
||||
|
@ -87,18 +88,12 @@
|
|||
.hotness4 {
|
||||
background-color: #FF003C; }
|
||||
|
||||
.widget-image {
|
||||
background-color: #4b4b4b; }
|
||||
|
||||
.widget-image {
|
||||
background-color: #FFFFFF; }
|
||||
|
||||
.widget-clock {
|
||||
background-color: #666666; }
|
||||
|
||||
.widget-clock {
|
||||
background-color: #dc5945; }
|
||||
|
||||
.widget-meter {
|
||||
background-color: #9c4274; }
|
||||
.widget-meter input.meter {
|
||||
|
@ -111,6 +106,39 @@
|
|||
.widget-meter .updated-at {
|
||||
color: rgba(0, 0, 0, 0.3); }
|
||||
|
||||
.widget-nagios li {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-top: 25px; }
|
||||
.widget-nagios li h3 {
|
||||
font-size: 60px;
|
||||
font-weight: bold; }
|
||||
.widget-nagios li h4 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase; }
|
||||
p .widget-nagios li.updated-at {
|
||||
font-size: 10px; }
|
||||
.widget-nagios li.green {
|
||||
background-color: #86d751; }
|
||||
.widget-nagios li.green p.updated-at {
|
||||
color: #c0eaa4; }
|
||||
.widget-nagios li.yellow {
|
||||
background-color: #edde43; }
|
||||
.widget-nagios li.yellow p.updated-at {
|
||||
color: #f6eea0; }
|
||||
.widget-nagios li.red {
|
||||
background-color: #e3394f; }
|
||||
.widget-nagios li.red p.updated-at {
|
||||
color: #f0929e; }
|
||||
.widget-nagios li.error {
|
||||
background-color: #f75f00; }
|
||||
.widget-nagios li.error p.updated-at {
|
||||
color: #ff9c5e; }
|
||||
|
||||
.widget-usage-gauge {
|
||||
background-color: #ec223f; }
|
||||
.widget-usage-gauge .title {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
main:
|
||||
log_file: pydashie.log
|
||||
openstack:
|
||||
regions:
|
||||
- 'region1'
|
||||
allocation:
|
||||
region1:
|
||||
vcpus_allocation_ratio: 2.0
|
||||
ram_allocation_ratio: 1.0
|
||||
# remove this amount per node available metric
|
||||
reserved_ram_per_node: 0
|
||||
reserved_vcpus_per_node: 0
|
||||
auth:
|
||||
auth_url: 'http://localhost:5000/v2.0'
|
||||
username: 'admin'
|
||||
password: 'openstack'
|
||||
project_name: 'demo'
|
||||
insecure: True
|
||||
nagios:
|
||||
services:
|
||||
region1:
|
||||
statfile: './region1-status.dat'
|
||||
host: 'region1-mon0'
|
||||
username: 'admin'
|
|
@ -1,12 +1,19 @@
|
|||
import datetime
|
||||
import json
|
||||
from math import ceil
|
||||
|
||||
from repeated_timer import RepeatedTimer
|
||||
|
||||
from novaclient.v1_1 import client as novaclient
|
||||
from cinderclient.v1 import client as cinderclient
|
||||
from keystoneclient.v2_0 import client as keystoneclient
|
||||
|
||||
|
||||
class DashieSampler(object):
|
||||
def __init__(self, app, interval):
|
||||
def __init__(self, app, interval, conf=None):
|
||||
self._app = app
|
||||
self._os_clients = {}
|
||||
self._conf = conf
|
||||
self._timer = RepeatedTimer(interval, self._sample)
|
||||
|
||||
def stop(self):
|
||||
|
@ -26,7 +33,8 @@ class DashieSampler(object):
|
|||
|
||||
def _send_event(self, widget_id, body):
|
||||
body['id'] = widget_id
|
||||
body['updatedAt'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S +0000')
|
||||
body['updatedAt'] = (datetime.datetime.now().
|
||||
strftime('%Y-%m-%d %H:%M:%S +0000'))
|
||||
formatted_json = 'data: %s\n\n' % (json.dumps(body))
|
||||
self._app.last_events[widget_id] = formatted_json
|
||||
for event_queue in self._app.events_queue.values():
|
||||
|
@ -36,3 +44,48 @@ class DashieSampler(object):
|
|||
data = self.sample()
|
||||
if data:
|
||||
self._send_event(self.name(), data)
|
||||
|
||||
def _convert(self, num):
|
||||
if num >= 1024 ** 3:
|
||||
return int(ceil(num / (1024 ** 3))), 'GB'
|
||||
elif num >= 1024 ** 2:
|
||||
return int(ceil(num / (1024 ** 2))), 'MB'
|
||||
elif num >= 1024:
|
||||
return int(ceil(num / (1024))), 'KB'
|
||||
else:
|
||||
return num, 'B'
|
||||
|
||||
def _client(self, service, region):
|
||||
if not self._os_clients.get(region):
|
||||
self._os_clients[region] = {}
|
||||
|
||||
if not self._os_clients[region].get(service):
|
||||
if service == 'compute':
|
||||
client = novaclient.Client(
|
||||
self._conf['auth']['username'],
|
||||
self._conf['auth']['password'],
|
||||
self._conf['auth']['project_name'],
|
||||
self._conf['auth']['auth_url'],
|
||||
region_name=region,
|
||||
insecure=self._conf['auth']['insecure'])
|
||||
self._os_clients[region][service] = client
|
||||
elif service == 'storage':
|
||||
client = cinderclient.Client(
|
||||
self._conf['auth']['username'],
|
||||
self._conf['auth']['password'],
|
||||
self._conf['auth']['project_name'],
|
||||
self._conf['auth']['auth_url'],
|
||||
region_name=region,
|
||||
insecure=self._conf['auth']['insecure'])
|
||||
self._os_clients[region][service] = client
|
||||
elif service == 'identity':
|
||||
client = keystoneclient.Client(
|
||||
username=self._conf['auth']['username'],
|
||||
password=self._conf['auth']['password'],
|
||||
project_name=self._conf['auth']['project_name'],
|
||||
auth_url=self._conf['auth']['auth_url'],
|
||||
region_name=region,
|
||||
insecure=self._conf['auth']['insecure'])
|
||||
self._os_clients[region][service] = client
|
||||
|
||||
return self._os_clients[region][service]
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
from example_samplers import (
|
||||
SynergySampler,
|
||||
HotnessSampler,
|
||||
CPUSampler,
|
||||
RAMSampler,
|
||||
RegionsRAMSampler,
|
||||
RegionsCPUSampler,
|
||||
NagiosSampler,
|
||||
BuzzwordsSampler,
|
||||
ConvergenceSampler,
|
||||
ProgressBarsSampler,
|
||||
UsageGaugeSampler,
|
||||
)
|
||||
|
||||
|
||||
def run(app, xyzzy):
|
||||
def run(args, conf, app, xyzzy):
|
||||
|
||||
samplers = [
|
||||
SynergySampler(xyzzy, 3),
|
||||
HotnessSampler(xyzzy, 3),
|
||||
BuzzwordsSampler(xyzzy, 2), # 10
|
||||
ConvergenceSampler(xyzzy, 1),
|
||||
ProgressBarsSampler(xyzzy, 5),
|
||||
UsageGaugeSampler(xyzzy, 3),
|
||||
CPUSampler(xyzzy, 10, conf['openstack']),
|
||||
RAMSampler(xyzzy, 10, conf['openstack']),
|
||||
RegionsCPUSampler(xyzzy, 10, conf['openstack']),
|
||||
RegionsRAMSampler(xyzzy, 10, conf['openstack']),
|
||||
NagiosSampler(xyzzy, 10, conf['nagios']),
|
||||
# BuzzwordsSampler(xyzzy, 2),
|
||||
# ConvergenceSampler(xyzzy, 1),
|
||||
]
|
||||
|
||||
try:
|
||||
app.run(debug=True,
|
||||
host='0.0.0.0',
|
||||
port=5000,
|
||||
host=args.ip,
|
||||
port=args.port,
|
||||
threaded=True,
|
||||
use_reloader=False,
|
||||
use_debugger=True
|
||||
|
|
|
@ -1,21 +1,39 @@
|
|||
import collections
|
||||
import random
|
||||
import nagios
|
||||
|
||||
from dashie_sampler import DashieSampler
|
||||
|
||||
|
||||
class SynergySampler(DashieSampler):
|
||||
class CPUSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SynergySampler, self).__init__(*args, **kwargs)
|
||||
super(CPUSampler, self).__init__(*args, **kwargs)
|
||||
self._last = 0
|
||||
|
||||
def name(self):
|
||||
return 'synergy'
|
||||
return 'cpu'
|
||||
|
||||
def sample(self):
|
||||
max_cpu = 0
|
||||
cur_cpu = 0
|
||||
|
||||
for region in self._conf['regions']:
|
||||
nova = self._client('compute', region)
|
||||
stats = nova.hypervisors.statistics()
|
||||
hypervisors = nova.hypervisors.list()
|
||||
|
||||
reserved = 0
|
||||
for hypervisor in hypervisors:
|
||||
reserved = reserved + self._conf['allocation'][region]['reserved_vcpus_per_node']
|
||||
|
||||
cpu_ratio = self._conf['allocation'][region]['vcpus_allocation_ratio']
|
||||
|
||||
max_cpu = max_cpu + (stats.vcpus * cpu_ratio) - reserved
|
||||
cur_cpu = cur_cpu + stats.vcpus_used
|
||||
|
||||
s = {'min': 0,
|
||||
'max': 100,
|
||||
'value': random.randint(0, 100),
|
||||
'max': max_cpu,
|
||||
'value': cur_cpu,
|
||||
'last': self._last}
|
||||
s['moreinfo'] = "%s/%s" % (s['value'], s['max'])
|
||||
s['current'] = s['value']
|
||||
|
@ -23,19 +41,143 @@ class SynergySampler(DashieSampler):
|
|||
return s
|
||||
|
||||
|
||||
class HotnessSampler(DashieSampler):
|
||||
class RAMSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HotnessSampler, self).__init__(*args, **kwargs)
|
||||
super(RAMSampler, self).__init__(*args, **kwargs)
|
||||
self._last = 0
|
||||
|
||||
def name(self):
|
||||
return 'hotness'
|
||||
return 'ram'
|
||||
|
||||
def sample(self):
|
||||
s = {'value': random.randint(0, 100),
|
||||
'current': random.randint(0, 100),
|
||||
max_ram = 0
|
||||
cur_ram = 0
|
||||
|
||||
for region in self._conf['regions']:
|
||||
nova = self._client('compute', region)
|
||||
stats = nova.hypervisors.statistics()
|
||||
hypervisors = nova.hypervisors.list()
|
||||
|
||||
reserved = 0
|
||||
for hypervisor in hypervisors:
|
||||
reserved = reserved + self._conf['allocation'][region]['reserved_ram_per_node']
|
||||
|
||||
ram_ratio = self._conf['allocation'][region]['ram_allocation_ratio']
|
||||
|
||||
max_ram = max_ram + (stats.memory_mb * ram_ratio * 1024 * 1024) - reserved
|
||||
cur_ram = cur_ram + stats.memory_mb_used * 1024 * 1024
|
||||
|
||||
ram_converted = self._convert(max_ram)
|
||||
ram_converted_used = self._convert(cur_ram)
|
||||
|
||||
s = {'min': 0,
|
||||
'max': ram_converted[0],
|
||||
'value': ram_converted_used[0],
|
||||
'last': self._last}
|
||||
self._last = s['current']
|
||||
s['moreinfo'] = "%s%s out of %s%s" % (ram_converted_used[0],
|
||||
ram_converted_used[1],
|
||||
ram_converted[0],
|
||||
ram_converted[1])
|
||||
s['current'] = s['value']
|
||||
self._last = s['value']
|
||||
return s
|
||||
|
||||
|
||||
class RegionsCPUSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RegionsCPUSampler, self).__init__(*args, **kwargs)
|
||||
|
||||
def name(self):
|
||||
return 'cpu_regions'
|
||||
|
||||
def sample(self):
|
||||
regions = []
|
||||
|
||||
for region in self._conf['regions']:
|
||||
nova = self._client('compute', region)
|
||||
stats = nova.hypervisors.statistics()
|
||||
hypervisors = nova.hypervisors.list()
|
||||
|
||||
reserved = 0
|
||||
for hypervisor in hypervisors:
|
||||
reserved = reserved + self._conf['allocation'][region]['reserved_vcpus_per_node']
|
||||
|
||||
cpu_ratio = self._conf['allocation'][region]['vcpus_allocation_ratio']
|
||||
|
||||
max_cpu = (stats.vcpus * cpu_ratio) - reserved
|
||||
cur_cpu = stats.vcpus_used
|
||||
|
||||
regions.append({'name': region, 'progress': (cur_cpu * 100.0) / max_cpu,
|
||||
'max': max_cpu, 'value': cur_cpu})
|
||||
|
||||
return {'progress_items': regions}
|
||||
|
||||
|
||||
class RegionsRAMSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RegionsRAMSampler, self).__init__(*args, **kwargs)
|
||||
|
||||
def name(self):
|
||||
return 'ram_regions'
|
||||
|
||||
def sample(self):
|
||||
regions = []
|
||||
|
||||
for region in self._conf['regions']:
|
||||
nova = self._client('compute', region)
|
||||
stats = nova.hypervisors.statistics()
|
||||
hypervisors = nova.hypervisors.list()
|
||||
|
||||
reserved = 0
|
||||
for hypervisor in hypervisors:
|
||||
reserved = reserved + self._conf['allocation'][region]['reserved_ram_per_node']
|
||||
|
||||
ram_ratio = self._conf['allocation'][region]['ram_allocation_ratio']
|
||||
|
||||
max_ram = (stats.memory_mb * ram_ratio * 1024 * 1024) - reserved
|
||||
cur_ram = stats.memory_mb_used * 1024 * 1024
|
||||
|
||||
ram_converted = self._convert(max_ram)[0]
|
||||
ram_converted_used = self._convert(cur_ram)[0]
|
||||
|
||||
regions.append({'name': region,
|
||||
'progress': ((ram_converted_used * 100.0) /
|
||||
ram_converted),
|
||||
'max': ram_converted, 'value': ram_converted_used})
|
||||
|
||||
return {'progress_items': regions}
|
||||
|
||||
|
||||
class NagiosSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(NagiosSampler, self).__init__(*args, **kwargs)
|
||||
self._last = 0
|
||||
|
||||
def name(self):
|
||||
return 'nagios'
|
||||
|
||||
def sample(self):
|
||||
|
||||
nagios.get_statusfiles(self._conf['services'])
|
||||
servicestatus = nagios.parse_status(self._conf['services'])
|
||||
|
||||
criticals = 0
|
||||
warnings = 0
|
||||
|
||||
for region in servicestatus:
|
||||
criticals = criticals + servicestatus[region]['critical']
|
||||
warnings = warnings + servicestatus[region]['warning']
|
||||
|
||||
status = 'green'
|
||||
|
||||
if criticals > 0:
|
||||
status = 'red'
|
||||
elif warnings > 0:
|
||||
status = 'yellow'
|
||||
|
||||
s = {'criticals': criticals,
|
||||
'warnings': warnings,
|
||||
'status': status}
|
||||
return s
|
||||
|
||||
|
||||
|
@ -75,22 +217,6 @@ class ConvergenceSampler(DashieSampler):
|
|||
return {'points': list(self.items)}
|
||||
|
||||
|
||||
class ProgressBarsSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProgressBarsSampler, self).__init__(*args, **kwargs)
|
||||
|
||||
def name(self):
|
||||
return 'progress_bars'
|
||||
|
||||
def sample(self):
|
||||
random_progress = []
|
||||
|
||||
for i in range(5):
|
||||
random_progress.append({'name': "Project %d" % i, 'progress': random.randint(0, 100)})
|
||||
|
||||
return {'title': "Progress Bars Title", 'progress_items': random_progress}
|
||||
|
||||
|
||||
class UsageGaugeSampler(DashieSampler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UsageGaugeSampler, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import Queue
|
||||
import yaml
|
||||
|
||||
from flask import (
|
||||
current_app,
|
||||
|
@ -12,8 +15,9 @@ from flask import (
|
|||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
logging.basicConfig()
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# we setup the log in __main__
|
||||
log = None
|
||||
|
||||
|
||||
@app.route("/")
|
||||
|
@ -53,6 +57,7 @@ def javascripts():
|
|||
'widgets/hotness/hotness.coffee',
|
||||
'widgets/progress_bars/progress_bars.coffee',
|
||||
'widgets/usage_gauge/usage_gauge.coffee',
|
||||
'widgets/nagios/nagios.coffee',
|
||||
]
|
||||
nizzle = True
|
||||
if not nizzle:
|
||||
|
@ -173,10 +178,35 @@ def close_stream(*args, **kwargs):
|
|||
|
||||
|
||||
def run_sample_app():
|
||||
a = argparse.ArgumentParser("Openstack-PyDashboard")
|
||||
|
||||
a.add_argument("-c", "--config", dest="config", help="Path to config file",
|
||||
required=True)
|
||||
a.add_argument("-i", "--interface", dest="ip",
|
||||
help="IP address to serve on.", default="0.0.0.0")
|
||||
a.add_argument("-p", "--port", help="port to serve on", default="6000")
|
||||
|
||||
args = a.parse_args()
|
||||
|
||||
conf = None
|
||||
|
||||
try:
|
||||
with open(args.config) as f:
|
||||
conf = yaml.load(f)
|
||||
except IOError as e:
|
||||
print "Couldn't load config file: %s" % e
|
||||
sys.exit(1)
|
||||
|
||||
logging.basicConfig(filename=conf['main']['log_file'],
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s %(message)s')
|
||||
global log
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
import SocketServer
|
||||
SocketServer.BaseServer.handle_error = close_stream
|
||||
import example_app
|
||||
example_app.run(app, xyzzy)
|
||||
example_app.run(args, conf, app, xyzzy)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# quick checker for nagios status
|
||||
|
||||
import paramiko
|
||||
from pynag.Parsers import status
|
||||
|
||||
|
||||
def get_statusfiles(services):
|
||||
# ssh to each server in the config, grab the status.dat and put it in
|
||||
# the location specified in the config
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
for region in services.keys():
|
||||
ssh.connect(services[region]['host'],
|
||||
username=services[region]['username'])
|
||||
ftp = ssh.open_sftp()
|
||||
ftp.get('/var/lib/icinga/status.dat', services[region]['statfile'])
|
||||
ftp.close()
|
||||
ssh.close()
|
||||
|
||||
|
||||
def parse_status(services):
|
||||
# parse the status.dat files listed in the config
|
||||
# return the status of the servers in a hash
|
||||
for region in services.keys():
|
||||
services[region]['warning'] = 0
|
||||
services[region]['critical'] = 0
|
||||
services[region]['unknown'] = 0
|
||||
s = status(services[region]['statfile'])
|
||||
s.parse()
|
||||
for service in s.data.get('servicestatus', []):
|
||||
if (int(service.get('scheduled_downtime_depth', None)) == 0
|
||||
and int(service.get('problem_has_been_acknowledged',
|
||||
None)) == 0):
|
||||
# get all the 'not OK' services
|
||||
if (int(service.get('current_state', None)) == 1):
|
||||
services[region]['warning'] += 1
|
||||
elif (int(service.get('current_state', None)) == 2):
|
||||
services[region]['critical'] += 1
|
||||
elif (int(service.get('current_state', None)) == 3):
|
||||
services[region]['unknown'] += 1
|
||||
|
||||
return services
|
|
@ -20,51 +20,38 @@
|
|||
<div id="container">
|
||||
<div class="gridster">
|
||||
<ul>
|
||||
<li data-row="1" data-col="1" data-sizex="2" data-sizey="1">
|
||||
- <div data-id="welcome" data-view="Text" data-title="Hello" data-text="This is your shiny new (python powered) dashboard." data-moreinfo="Protip: You can drag the widgets around!"></div>
|
||||
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
|
||||
<div data-id="clock" data-view="Clock" data-title="Clock"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="1" data-col="3" data-sizex="1" data-sizey="1">
|
||||
<div data-id="hotness" data-view="Hotness" data-title="Hotness" data-cool="40" data-warm="90"></div>
|
||||
<li data-row="1" data-col="2" data-sizex="1" data-sizey="1">
|
||||
<div data-id="nagios" data-view="Nagios" data-unordered="true" data-title="Icinga Prod" data-moreinfo="Unacknowledged events"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">
|
||||
<div data-id="clock" data-view="Clock" data-title="Clock"></div>
|
||||
</li>
|
||||
<div data-id="cpu" data-view="Meter" data-title="CPU"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="1" data-col="5" data-sizex="1" data-sizey="1">
|
||||
<div data-view="Image" data-image="/images/dashie.png"></div>
|
||||
<div data-id="ram" data-view="Meter" data-title="RAM"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="2" data-col="2" data-sizex="2" data-sizey="1">
|
||||
<div data-id="progress_bars" data-view="ProgressBars" data-title="Project Bars"></div>
|
||||
<div data-id="cpu_regions" data-view="ProgressBars" data-title="CPU usage per region"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="2" data-col="4" data-sizex="1" data-sizey="1">
|
||||
<div data-id="synergy" data-view="Meter" data-title="Synergy"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="2" data-col="5" data-sizex="1" data-sizey="1">
|
||||
<div data-id="synergy" data-view="Meter" data-title="Synergy"></div>
|
||||
<li data-row="2" data-col="4" data-sizex="2" data-sizey="1">
|
||||
<div data-id="ram_regions" data-view="ProgressBars" data-title="RAM usage per region"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="2" data-col="1" data-sizex="1" data-sizey="2">
|
||||
<div data-id="buzzwords" data-view="List" data-unordered="true" data-title="Buzzwords" data-moreinfo="Absolute ranking of pony preferences"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="3" data-col="2" data-sizex="2" data-sizey="1">
|
||||
<li data-row="4" data-col="2" data-sizex="2" data-sizey="1">
|
||||
<div data-id="convergence" data-view="Graph" data-title="Convergence" style="background-color:#ff9618"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="3" data-col="4" data-sizex="1" data-sizey="1">
|
||||
<div data-id="website_up" data-view="Text" data-title="Website"></div>
|
||||
</li>
|
||||
|
||||
<li data-row="3" data-col="5" data-sizex="1" data-sizey="1">
|
||||
<!-- <style scoped>.memcached_used_memory .gauge { height: 145px;}</style> -->
|
||||
<div data-id="usage_gauge" data-view="UsageGauge" style="background-color: #3e3735" data-title="Power !!"></div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class Dashing.Nagios extends Dashing.Widget
|
||||
|
||||
ready: ->
|
||||
# This is fired when the widget is done being rendered
|
||||
|
||||
onData: (data) ->
|
||||
# Handle incoming data
|
||||
# You can access the html node of this widget with `@node`
|
||||
# Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in.
|
|
@ -0,0 +1,21 @@
|
|||
<ul>
|
||||
<li data-bind-class="status">
|
||||
<h1 class="title" data-bind="title"></h1>
|
||||
<div data-showif="status | equals 'error'"> <!-- error -->
|
||||
<h4>Error querying Icinga</h4>
|
||||
</div> <!-- /no error -->
|
||||
<div data-hideif="status | equals 'error'"> <!-- no error -->
|
||||
<div>
|
||||
<h3 data-bind="criticals"></h3>
|
||||
<h4 data-showif="criticals | equals 1">critical</h4>
|
||||
<h4 data-hideif="criticals | equals 1">criticals</h4>
|
||||
</div>
|
||||
<div>
|
||||
<h3 data-bind="warnings"></h3>
|
||||
<h4 data-showif="warnings | equals 1">warning</h4>
|
||||
<h4 data-hideif="warnings | equals 1">warnings</h4>
|
||||
</div>
|
||||
<p class="updated-at" data-bind="updatedAtMessage"></p>
|
||||
</div> <!-- /no error -->
|
||||
</li>
|
||||
</ul>
|
|
@ -0,0 +1,72 @@
|
|||
$background: #444;
|
||||
$text: #fff;
|
||||
$success: #86d751;
|
||||
$warning: #edde43;
|
||||
$failure: #e3394f;
|
||||
$error: #f75f00;
|
||||
|
||||
.widget-nagios {
|
||||
li {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-top: 25px;
|
||||
|
||||
h3 {
|
||||
font-size: 60px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
p &.updated-at {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
&.green {
|
||||
background-color: $success;
|
||||
|
||||
p {
|
||||
&.updated-at {
|
||||
color: lighten($success, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
background-color: $warning;
|
||||
|
||||
p {
|
||||
&.updated-at {
|
||||
color: lighten($warning, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.red {
|
||||
background-color: $failure;
|
||||
|
||||
p {
|
||||
&.updated-at {
|
||||
color: lighten($failure, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: $error;
|
||||
|
||||
p {
|
||||
&.updated-at {
|
||||
color: lighten($error, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
class Dashing.ProgressBars extends Dashing.Widget
|
||||
|
||||
|
||||
@accessor 'title'
|
||||
|
||||
|
||||
ready: ->
|
||||
@drawWidget( @get('progress_items') )
|
||||
|
||||
|
||||
onData: (eventData) ->
|
||||
@drawWidget(eventData.progress_items)
|
||||
|
||||
|
||||
drawWidget: (progress_items) ->
|
||||
container = $(@node)
|
||||
rowsContainer = container.find('.rows-container')
|
||||
|
||||
|
||||
if progress_items.length == 0
|
||||
rowsContainer.empty()
|
||||
else
|
||||
|
@ -19,13 +19,13 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
rowHeight = 100 / progress_items.length
|
||||
counter = 0
|
||||
@clearIntervals()
|
||||
|
||||
|
||||
# Add or move rows for each project. Checks first if the row already exists.
|
||||
progress_items.forEach (item) =>
|
||||
normalizedItemName = item.name.replace(/\W+/g, "_")
|
||||
referenceRow = rowsContainer.children().eq(counter)
|
||||
existingRow = rowsContainer.find("."+normalizedItemName)
|
||||
|
||||
|
||||
if existingRow.length
|
||||
if referenceRow.attr("class").indexOf(normalizedItemName) == -1
|
||||
existingRow.detach().insertBefore(referenceRow)
|
||||
|
@ -37,28 +37,29 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
else
|
||||
rowsContainer.append(row)
|
||||
row.hide().fadeIn(1200)
|
||||
|
||||
|
||||
elem = rowsContainer.find("."+normalizedItemName+" .inner-progress-bar")
|
||||
if elem.length
|
||||
@animateProgressBarContent(elem[0], parseFloat(elem[0].style.width),
|
||||
parseFloat(item.progress), 1000)
|
||||
parseFloat(item.progress), parseFloat(item.value),
|
||||
parseFloat(item.max), 1000)
|
||||
++counter
|
||||
|
||||
|
||||
# Remove any nodes that were not in the new data, these will be the rows
|
||||
# at the end of the widget.
|
||||
currentNode = rowsContainer.children().eq(counter-1)
|
||||
while currentNode.next().length
|
||||
currentNode = currentNode.next()
|
||||
currentNode.fadeOut(100, -> $(this).remove() )
|
||||
|
||||
|
||||
# Set the height after rows were added/removed.
|
||||
rows = rowsContainer.children()
|
||||
percentageOfTotalHeight = 100 / progress_items.length
|
||||
applyCorrectedRowHeight(rows, percentageOfTotalHeight)
|
||||
|
||||
|
||||
applyZebraStriping(rows)
|
||||
|
||||
|
||||
|
||||
|
||||
#***/
|
||||
# Create a JQuery row object with the proper structure and base
|
||||
# settings for the item passed in.
|
||||
|
@ -73,35 +74,35 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
# @item - object representing an item and it's progress
|
||||
# /
|
||||
createRow = (item) ->
|
||||
|
||||
|
||||
row = ( $("<div/>")
|
||||
.attr("class", "row " + item.name.replace(/\W+/g, "_") ) )
|
||||
|
||||
|
||||
rowContent = ( $("<div/>")
|
||||
.attr("class", "row-content") )
|
||||
|
||||
|
||||
projectName = ( $("<div/>")
|
||||
.attr("class", "project-name")
|
||||
.text(item.name)
|
||||
.attr("title", item.name) )
|
||||
|
||||
|
||||
outerProgressBar = ( $("<div/>")
|
||||
.attr("class", "outer-progress-bar") )
|
||||
|
||||
|
||||
innerProgressBar = $("<div/>")
|
||||
.attr("class", "inner-progress-bar")
|
||||
.text("0%")
|
||||
innerProgressBar.css("width", "0%")
|
||||
|
||||
|
||||
# Put it all together.
|
||||
outerProgressBar.append(innerProgressBar)
|
||||
rowContent.append(projectName)
|
||||
rowContent.append(outerProgressBar)
|
||||
row.append(rowContent)
|
||||
|
||||
|
||||
return row
|
||||
|
||||
|
||||
|
||||
|
||||
#***/
|
||||
# Does calculations for the animation and sets up the javascript
|
||||
# interval to perform the animation.
|
||||
|
@ -109,20 +110,22 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
# @element - element that is going to be animated.
|
||||
# @from - the value that the element starts at.
|
||||
# @to - the value that the element is going to.
|
||||
# @value - the actual value (not percentage) to display.
|
||||
# @max - the max value (used for percentage).
|
||||
# @baseDuration - the minimum time the animation will perform.
|
||||
# /
|
||||
animateProgressBarContent: (element, from, to, baseDuration) ->
|
||||
animateProgressBarContent: (element, from, to, value, max, baseDuration) ->
|
||||
endpointDifference = (to-from)
|
||||
|
||||
|
||||
if endpointDifference != 0
|
||||
currentValue = from
|
||||
|
||||
|
||||
# Every x milliseconds, the function should run.
|
||||
stepInterval = 16.667
|
||||
|
||||
|
||||
# Change the duration based on the distance between points.
|
||||
duration = baseDuration + Math.abs(endpointDifference) * 25
|
||||
|
||||
|
||||
numberOfSteps = duration / stepInterval
|
||||
valueIncrement = endpointDifference / numberOfSteps
|
||||
|
||||
|
@ -130,29 +133,31 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
->
|
||||
currentValue += valueIncrement
|
||||
if Math.abs(currentValue - from) >= Math.abs(endpointDifference)
|
||||
setProgressBarValue(element, to)
|
||||
setProgressBarValue(element, to, value, max)
|
||||
clearInterval(interval)
|
||||
else
|
||||
setProgressBarValue(element, currentValue)
|
||||
setProgressBarValue(element, currentValue, value, max)
|
||||
stepInterval)
|
||||
|
||||
|
||||
@addInterval(interval)
|
||||
|
||||
|
||||
#***/
|
||||
# Sets the text and width of the element in question to the specified value
|
||||
# after making sure it is bounded between [0-100]
|
||||
#
|
||||
# @element - element to be set
|
||||
# @value - the numeric value to set the element to. This can be a float.
|
||||
# @literal - the actual value (not in percentage).
|
||||
# @max - the max value (which was used for percentage).
|
||||
# /
|
||||
setProgressBarValue = (element, value) ->
|
||||
setProgressBarValue = (element, value, literal, max) ->
|
||||
if (value > 100)
|
||||
value = 100
|
||||
else if (value < 0)
|
||||
value = 0
|
||||
element.textContent = Math.floor(value) + "%"
|
||||
element.textContent = Math.floor(value) + "% - " + Math.floor(literal) + "/" + Math.floor(max) + ""
|
||||
element.style.width = value + "%"
|
||||
|
||||
|
||||
#***/
|
||||
# Applies a percentage-based row height to the list of rows passed in.
|
||||
#
|
||||
|
@ -163,7 +168,7 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
height = percentageOfTotalHeight + "%"
|
||||
for row in rows
|
||||
row.style.height = height
|
||||
|
||||
|
||||
#***/
|
||||
# Adds a class to every other row to change the background color. This
|
||||
# was done mainly for readability.
|
||||
|
@ -178,7 +183,7 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
if isZebraStripe
|
||||
row.classList.add("zebra-stripe")
|
||||
isZebraStripe = !isZebraStripe
|
||||
|
||||
|
||||
#***/
|
||||
# Stops all javascript intervals from running and clears the list.
|
||||
#/
|
||||
|
@ -187,7 +192,7 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
for interval in @intervalList
|
||||
clearInterval(interval)
|
||||
@intervalList = []
|
||||
|
||||
|
||||
#***/
|
||||
# Adds a javascript interval to a list so that it can be tracked and cleared
|
||||
# ahead of time if the need arises.
|
||||
|
@ -197,4 +202,4 @@ class Dashing.ProgressBars extends Dashing.Widget
|
|||
addInterval: (interval) ->
|
||||
if !@intervalList
|
||||
@intervalList = []
|
||||
@intervalList.push(interval)
|
||||
@intervalList.push(interval)
|
||||
|
|
|
@ -87,6 +87,7 @@ $text-color: $base-color-lightest;
|
|||
background-color: $base-color-dark;
|
||||
border-radius: $row-size / 2;
|
||||
color: $white;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue