Add support for new Tempmon Appliance table, etc.
This commit is contained in:
parent
aa97a36167
commit
40a8761feb
|
@ -44,8 +44,10 @@
|
||||||
<%def name="render_main_fields(form)">
|
<%def name="render_main_fields(form)">
|
||||||
${form.render_field_readonly('client')}
|
${form.render_field_readonly('client')}
|
||||||
${form.render_field_readonly('config_key')}
|
${form.render_field_readonly('config_key')}
|
||||||
|
${form.render_field_readonly('appliance')}
|
||||||
${form.render_field_readonly('appliance_type')}
|
${form.render_field_readonly('appliance_type')}
|
||||||
${form.render_field_readonly('description')}
|
${form.render_field_readonly('description')}
|
||||||
|
${form.render_field_readonly('location')}
|
||||||
${form.render_field_readonly('device_path')}
|
${form.render_field_readonly('device_path')}
|
||||||
${form.render_field_readonly('notes')}
|
${form.render_field_readonly('notes')}
|
||||||
${form.render_field_readonly('enabled')}
|
${form.render_field_readonly('enabled')}
|
||||||
|
|
|
@ -30,6 +30,7 @@ from .core import MasterView
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
|
config.include('tailbone.views.tempmon.appliances')
|
||||||
config.include('tailbone.views.tempmon.clients')
|
config.include('tailbone.views.tempmon.clients')
|
||||||
config.include('tailbone.views.tempmon.probes')
|
config.include('tailbone.views.tempmon.probes')
|
||||||
config.include('tailbone.views.tempmon.readings')
|
config.include('tailbone.views.tempmon.readings')
|
||||||
|
|
93
tailbone/views/tempmon/appliances.py
Normal file
93
tailbone/views/tempmon/appliances.py
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2018 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Views for tempmon appliances
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from rattail_tempmon.db import model as tempmon
|
||||||
|
|
||||||
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
|
from tailbone.views.tempmon import MasterView
|
||||||
|
|
||||||
|
|
||||||
|
class TempmonApplianceView(MasterView):
|
||||||
|
"""
|
||||||
|
Master view for tempmon appliances.
|
||||||
|
"""
|
||||||
|
model_class = tempmon.Appliance
|
||||||
|
model_title = "TempMon Appliance"
|
||||||
|
model_title_plural = "TempMon Appliances"
|
||||||
|
route_prefix = 'tempmon.appliances'
|
||||||
|
url_prefix = '/tempmon/appliances'
|
||||||
|
|
||||||
|
grid_columns = [
|
||||||
|
'name',
|
||||||
|
'location',
|
||||||
|
]
|
||||||
|
|
||||||
|
form_fields = [
|
||||||
|
'name',
|
||||||
|
'location',
|
||||||
|
'clients',
|
||||||
|
'probes',
|
||||||
|
]
|
||||||
|
|
||||||
|
def configure_grid(self, g):
|
||||||
|
super(TempmonApplianceView, self).configure_grid(g)
|
||||||
|
g.set_sort_defaults('name')
|
||||||
|
|
||||||
|
def configure_form(self, f):
|
||||||
|
super(TempmonApplianceView, self).configure_form(f)
|
||||||
|
|
||||||
|
# clients
|
||||||
|
if self.viewing:
|
||||||
|
f.set_renderer('clients', self.render_clients)
|
||||||
|
else:
|
||||||
|
f.remove_field('clients')
|
||||||
|
|
||||||
|
# probes
|
||||||
|
if self.viewing:
|
||||||
|
f.set_renderer('probes', self.render_probes)
|
||||||
|
elif self.creating or self.editing:
|
||||||
|
f.remove_field('probes')
|
||||||
|
|
||||||
|
def render_clients(self, appliance, field):
|
||||||
|
clients = {}
|
||||||
|
for probe in appliance.probes:
|
||||||
|
if probe.client.uuid not in clients:
|
||||||
|
clients[probe.client.uuid] = probe.client
|
||||||
|
|
||||||
|
if not clients:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
clients = sorted(clients.values(), key=lambda client: client.hostname)
|
||||||
|
items = [HTML.tag('li', c=[tags.link_to(client.hostname, self.request.route_url('tempmon.clients.view', uuid=client.uuid))])
|
||||||
|
for client in clients]
|
||||||
|
return HTML.tag('ul', c=items)
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
TempmonApplianceView.defaults(config)
|
|
@ -28,14 +28,11 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rattail_tempmon.db import model as tempmon
|
from rattail_tempmon.db import model as tempmon
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import grids
|
|
||||||
from tailbone.views.tempmon import MasterView
|
from tailbone.views.tempmon import MasterView
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +65,7 @@ class TempmonClientView(MasterView):
|
||||||
'location',
|
'location',
|
||||||
'disk_type',
|
'disk_type',
|
||||||
'delay',
|
'delay',
|
||||||
|
'appliances',
|
||||||
'probes',
|
'probes',
|
||||||
'notes',
|
'notes',
|
||||||
'enabled',
|
'enabled',
|
||||||
|
@ -119,6 +117,12 @@ class TempmonClientView(MasterView):
|
||||||
# delay
|
# delay
|
||||||
f.set_helptext('delay', tempmon.Client.delay.__doc__)
|
f.set_helptext('delay', tempmon.Client.delay.__doc__)
|
||||||
|
|
||||||
|
# appliances
|
||||||
|
if self.viewing:
|
||||||
|
f.set_renderer('appliances', self.render_appliances)
|
||||||
|
else:
|
||||||
|
f.remove_field('appliances')
|
||||||
|
|
||||||
# probes
|
# probes
|
||||||
if self.viewing:
|
if self.viewing:
|
||||||
f.set_renderer('probes', self.render_probes)
|
f.set_renderer('probes', self.render_probes)
|
||||||
|
@ -149,44 +153,19 @@ class TempmonClientView(MasterView):
|
||||||
if query.count():
|
if query.count():
|
||||||
raise colander.Invalid(node, "Config key must be unique")
|
raise colander.Invalid(node, "Config key must be unique")
|
||||||
|
|
||||||
def render_probes(self, client, field):
|
def render_appliances(self, client, field):
|
||||||
if not client.probes:
|
appliances = {}
|
||||||
|
for probe in client.probes:
|
||||||
|
if probe.appliance and probe.appliance.uuid not in appliances:
|
||||||
|
appliances[probe.appliance.uuid] = probe.appliance
|
||||||
|
|
||||||
|
if not appliances:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
route_prefix = self.get_route_prefix()
|
appliances = sorted(appliances.values(), key=lambda a: a.name)
|
||||||
view_url = lambda p, i: self.request.route_url('tempmon.probes.view', uuid=p.uuid)
|
items = [HTML.tag('li', c=[tags.link_to(a.name, self.request.route_url('tempmon.appliances.view', uuid=a.uuid))])
|
||||||
actions = [
|
for a in appliances]
|
||||||
grids.GridAction('view', icon='zoomin', url=view_url),
|
return HTML.tag('ul', c=items)
|
||||||
]
|
|
||||||
if self.request.has_perm('tempmon.probes.edit'):
|
|
||||||
url = lambda p, i: self.request.route_url('tempmon.probes.edit', uuid=p.uuid)
|
|
||||||
actions.append(grids.GridAction('edit', icon='pencil', url=url))
|
|
||||||
|
|
||||||
g = grids.Grid(
|
|
||||||
key='{}.probes'.format(route_prefix),
|
|
||||||
data=client.probes,
|
|
||||||
columns=[
|
|
||||||
'description',
|
|
||||||
'critical_temp_min',
|
|
||||||
'good_temp_min',
|
|
||||||
'good_temp_max',
|
|
||||||
'critical_temp_max',
|
|
||||||
'status',
|
|
||||||
'enabled',
|
|
||||||
],
|
|
||||||
labels={
|
|
||||||
'critical_temp_min': "Crit. Min",
|
|
||||||
'good_temp_min': "Good Min",
|
|
||||||
'good_temp_max': "Good Max",
|
|
||||||
'critical_temp_max': "Crit. Max",
|
|
||||||
},
|
|
||||||
url=lambda p: self.request.route_url('tempmon.probes.view', uuid=p.uuid),
|
|
||||||
linked_columns=['description'],
|
|
||||||
main_actions=actions,
|
|
||||||
)
|
|
||||||
g.set_enum('status', self.enum.TEMPMON_PROBE_STATUS)
|
|
||||||
g.set_type('enabled', 'boolean')
|
|
||||||
return HTML.literal(g.render_grid())
|
|
||||||
|
|
||||||
def delete_instance(self, client):
|
def delete_instance(self, client):
|
||||||
# bulk-delete all readings first
|
# bulk-delete all readings first
|
||||||
|
|
|
@ -28,7 +28,9 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail_tempmon.db import Session as RawTempmonSession
|
from rattail_tempmon.db import Session as RawTempmonSession
|
||||||
|
|
||||||
from tailbone import views
|
from webhelpers2.html import HTML
|
||||||
|
|
||||||
|
from tailbone import views, grids
|
||||||
from tailbone.db import TempmonSession
|
from tailbone.db import TempmonSession
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,3 +42,45 @@ class MasterView(views.MasterView):
|
||||||
|
|
||||||
def get_bulk_delete_session(self):
|
def get_bulk_delete_session(self):
|
||||||
return RawTempmonSession()
|
return RawTempmonSession()
|
||||||
|
|
||||||
|
def render_probes(self, obj, field):
|
||||||
|
"""
|
||||||
|
This method is used by Appliance and Client views.
|
||||||
|
"""
|
||||||
|
if not obj.probes:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
route_prefix = self.get_route_prefix()
|
||||||
|
view_url = lambda p, i: self.request.route_url('tempmon.probes.view', uuid=p.uuid)
|
||||||
|
actions = [
|
||||||
|
grids.GridAction('view', icon='zoomin', url=view_url),
|
||||||
|
]
|
||||||
|
if self.request.has_perm('tempmon.probes.edit'):
|
||||||
|
url = lambda p, i: self.request.route_url('tempmon.probes.edit', uuid=p.uuid)
|
||||||
|
actions.append(grids.GridAction('edit', icon='pencil', url=url))
|
||||||
|
|
||||||
|
g = grids.Grid(
|
||||||
|
key='{}.probes'.format(route_prefix),
|
||||||
|
data=obj.probes,
|
||||||
|
columns=[
|
||||||
|
'description',
|
||||||
|
'critical_temp_min',
|
||||||
|
'good_temp_min',
|
||||||
|
'good_temp_max',
|
||||||
|
'critical_temp_max',
|
||||||
|
'status',
|
||||||
|
'enabled',
|
||||||
|
],
|
||||||
|
labels={
|
||||||
|
'critical_temp_min': "Crit. Min",
|
||||||
|
'good_temp_min': "Good Min",
|
||||||
|
'good_temp_max': "Good Max",
|
||||||
|
'critical_temp_max': "Crit. Max",
|
||||||
|
},
|
||||||
|
url=lambda p: self.request.route_url('tempmon.probes.view', uuid=p.uuid),
|
||||||
|
linked_columns=['description'],
|
||||||
|
main_actions=actions,
|
||||||
|
)
|
||||||
|
g.set_enum('status', self.enum.TEMPMON_PROBE_STATUS)
|
||||||
|
g.set_type('enabled', 'boolean')
|
||||||
|
return HTML.literal(g.render_grid())
|
||||||
|
|
|
@ -61,6 +61,7 @@ class TempmonProbeView(MasterView):
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'client',
|
'client',
|
||||||
'config_key',
|
'config_key',
|
||||||
|
'appliance',
|
||||||
'appliance_type',
|
'appliance_type',
|
||||||
'description',
|
'description',
|
||||||
'device_path',
|
'device_path',
|
||||||
|
@ -71,8 +72,10 @@ class TempmonProbeView(MasterView):
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'client',
|
'client',
|
||||||
'config_key',
|
'config_key',
|
||||||
|
'appliance',
|
||||||
'appliance_type',
|
'appliance_type',
|
||||||
'description',
|
'description',
|
||||||
|
'location',
|
||||||
'device_path',
|
'device_path',
|
||||||
'critical_temp_max',
|
'critical_temp_max',
|
||||||
'critical_max_timeout',
|
'critical_max_timeout',
|
||||||
|
@ -133,6 +136,18 @@ class TempmonProbeView(MasterView):
|
||||||
f.set_widget('client_uuid', dfwidget.SelectWidget(values=client_values))
|
f.set_widget('client_uuid', dfwidget.SelectWidget(values=client_values))
|
||||||
f.set_label('client_uuid', "Tempmon Client")
|
f.set_label('client_uuid', "Tempmon Client")
|
||||||
|
|
||||||
|
# appliance
|
||||||
|
f.set_renderer('appliance', self.render_appliance)
|
||||||
|
if self.creating or self.editing:
|
||||||
|
f.replace('appliance', 'appliance_uuid')
|
||||||
|
appliances = self.Session.query(tempmon.Appliance)\
|
||||||
|
.order_by(tempmon.Appliance.name)
|
||||||
|
appliance_values = [(appliance.uuid, appliance.name)
|
||||||
|
for appliance in appliances]
|
||||||
|
appliance_values.insert(0, ('', "(none)"))
|
||||||
|
f.set_widget('appliance_uuid', dfwidget.SelectWidget(values=appliance_values))
|
||||||
|
f.set_label('appliance_uuid', "Appliance")
|
||||||
|
|
||||||
# appliance_type
|
# appliance_type
|
||||||
f.set_enum('appliance_type', self.enum.TEMPMON_APPLIANCE_TYPE)
|
f.set_enum('appliance_type', self.enum.TEMPMON_APPLIANCE_TYPE)
|
||||||
|
|
||||||
|
@ -167,6 +182,14 @@ class TempmonProbeView(MasterView):
|
||||||
url = self.request.route_url('tempmon.clients.view', uuid=client.uuid)
|
url = self.request.route_url('tempmon.clients.view', uuid=client.uuid)
|
||||||
return tags.link_to(text, url)
|
return tags.link_to(text, url)
|
||||||
|
|
||||||
|
def render_appliance(self, probe, field):
|
||||||
|
appliance = probe.appliance
|
||||||
|
if not appliance:
|
||||||
|
return ""
|
||||||
|
text = six.text_type(appliance)
|
||||||
|
url = self.request.route_url('tempmon.appliances.view', uuid=appliance.uuid)
|
||||||
|
return tags.link_to(text, url)
|
||||||
|
|
||||||
def delete_instance(self, probe):
|
def delete_instance(self, probe):
|
||||||
# bulk-delete all readings first
|
# bulk-delete all readings first
|
||||||
readings = self.Session.query(tempmon.Reading)\
|
readings = self.Session.query(tempmon.Reading)\
|
||||||
|
|
Loading…
Reference in a new issue