276 lines
10 KiB
Python
276 lines
10 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
import logging
|
|
import json
|
|
import pprint
|
|
|
|
from django.core.urlresolvers import reverse
|
|
from django.core.urlresolvers import reverse_lazy
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from horizon import exceptions
|
|
from horizon import forms
|
|
from horizon import tables
|
|
from horizon import messages
|
|
|
|
from openstack_dashboard import api
|
|
|
|
from openstack_dashboard.dashboards.admin.rackhd \
|
|
import forms as baremetal_forms
|
|
from openstack_dashboard.dashboards.admin.rackhd \
|
|
import tables as baremetal_tables
|
|
|
|
from openstack_dashboard.dashboards.admin.rackhd \
|
|
import json2html as j2h
|
|
|
|
from openstack_dashboard.dashboards.admin.rackhd import shovel
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
class IndexView(tables.DataTableView):
|
|
# A very simple class-based view...
|
|
table_class = baremetal_tables.BareMetalTable
|
|
template_name = "admin/rackhd/index.html"
|
|
page_title = _("Baremetal")
|
|
|
|
class NodeData:
|
|
def __init__(self, uuid, name, hwaddr, events, state):
|
|
self.id = uuid
|
|
self.name = name
|
|
self.uuid = uuid
|
|
self.hwaddr = hwaddr
|
|
self.events = events
|
|
self.state = state
|
|
|
|
def get_data(self):
|
|
data = []
|
|
try:
|
|
nodes = shovel.request_nodes_get()
|
|
i = 0
|
|
for n in nodes:
|
|
dmi = shovel.get_catalog_data_by_source(n['id'],'dmi')
|
|
name = dmi['System Information']['Product Name']
|
|
hwaddr = n['name']
|
|
id = n['id']
|
|
events = '0'
|
|
n = self._find_ironic_node(id)
|
|
if n is not None:
|
|
events = n['extra'].get('eventcnt','0')
|
|
state = 'Registered'
|
|
else:
|
|
state = 'Unregistered'
|
|
i += i +1
|
|
data.append(self.NodeData(id, name, hwaddr, events, state))
|
|
return data
|
|
except Exception, e:
|
|
print
|
|
LOG.error("Excepton in get_baremetal_data(): {0}".format(e))
|
|
return data
|
|
def _find_ironic_node(self, id):
|
|
# ISSUE: iterating all nodes because query by name (onrack id) isn't working in ironic?
|
|
nodes = shovel.get_ironic_nodes()
|
|
for n in nodes['nodes']:
|
|
if n['extra'].get('nodeid', None) == id:
|
|
return n
|
|
return None
|
|
|
|
class RegisterView(forms.ModalFormView):
|
|
context_object_name = 'baremetal'
|
|
template_name = 'admin/rackhd/register.html'
|
|
form_class = baremetal_forms.RegisterForm
|
|
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
|
page_title = _("Register Node")
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RegisterView, self).get_context_data(**kwargs)
|
|
context["baremetal"] = self.kwargs['baremetal']
|
|
return context
|
|
|
|
def get_initial(self):
|
|
id = self.kwargs['baremetal']
|
|
node = shovel.request_node_get(id)
|
|
list_drivers = shovel.get_driver_list()['drivers']
|
|
drivers = [ elem['name'] for elem in list_drivers ]
|
|
ports = str(node['name']).split(',')
|
|
|
|
list_images = shovel.get_images_list()['images']
|
|
images = [ elem['name'] for elem in list_images ]
|
|
initial = super(RegisterView, self).get_initial()
|
|
initial.update({'nodeid': self.kwargs['baremetal'], 'node': node, 'drivers': drivers,'images':images,'ports': ports})
|
|
return initial
|
|
|
|
|
|
class UnregisterView(forms.ModalFormView):
|
|
context_object_name = 'baremetal'
|
|
template_name = 'admin/rackhd/unregister.html'
|
|
form_class = baremetal_forms.UnregisterForm
|
|
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
|
page_title = _("Unegister Node")
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(UnregisterView, self).get_context_data(**kwargs)
|
|
context["baremetal"] = self.kwargs['baremetal']
|
|
return context
|
|
|
|
def get_initial(self):
|
|
id = self.kwargs['baremetal']
|
|
node = shovel.request_node_get(id)
|
|
initial = super(UnregisterView, self).get_initial()
|
|
initial.update({'nodeid': self.kwargs['baremetal'], 'node': node})
|
|
return initial
|
|
|
|
|
|
class FailoverView(forms.ModalFormView):
|
|
context_object_name = 'baremetal'
|
|
template_name = 'admin/rackhd/register.html'
|
|
form_class = baremetal_forms.RegisterForm
|
|
success_url = reverse_lazy('horizon:admin:rackhd:index')
|
|
page_title = _("Failover")
|
|
|
|
def _find_ironic_node(self, id):
|
|
nodes = shovel.get_ironic_nodes()
|
|
for n in nodes['nodes']:
|
|
if n['extra'].get('nodeid', None) == id:
|
|
return n
|
|
|
|
def _remove_node(self,id):
|
|
try:
|
|
result = shovel.unregister_node_del(id)
|
|
return True
|
|
except Exception:
|
|
redirect = reverse('horizon:admin:rackhd:index')
|
|
return False
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(FailoverView, self).get_context_data(**kwargs)
|
|
context["baremetal"] = self.kwargs['baremetal']
|
|
return context
|
|
|
|
def get_initial(self):
|
|
initial = super(FailoverView, self).get_initial()
|
|
current_id = self.kwargs['baremetal']
|
|
inode = self._find_ironic_node(current_id)
|
|
try:
|
|
if inode is not None:
|
|
failover = inode['extra'].get('failover', None)
|
|
if failover is not None:
|
|
node = shovel.request_node_get(failover)
|
|
list_drivers = shovel.get_driver_list()['drivers']
|
|
drivers = [ elem['name'] for elem in list_drivers ]
|
|
initial.update({'nodeid': self.kwargs['baremetal'], 'node': node, 'drivers': drivers})
|
|
else:
|
|
raise ValueError('Failover node not set')
|
|
else:
|
|
raise ValueError('Registered node not found')
|
|
except ValueError as e:
|
|
redirect = reverse('horizon:admin:rackhd:index')
|
|
messages.error(self.request, _(e.message))
|
|
raise Exception(e.message)
|
|
self._remove_node(current_id)
|
|
messages.success(self.request, _('Removed node {0}'.format(current_id)))
|
|
return initial
|
|
|
|
|
|
class BareMetalDetailView(tables.DataTableView):
|
|
table_class = baremetal_tables.BareMetalDetailsTable
|
|
template_name = 'admin/rackhd/detail.html'
|
|
page_title = _('Details')
|
|
|
|
class CatalogData:
|
|
def __init__(self, id, catalog):
|
|
self.id = id
|
|
self.catalog = catalog
|
|
|
|
def get_data(self):
|
|
uuid = self.kwargs['baremetal']
|
|
dmi = shovel.get_catalog_data_by_source(id = uuid, source = 'dmi')
|
|
scsi = shovel.get_catalog_data_by_source(id = uuid, source = 'lsscsi')
|
|
del dmi['Processor Information'] # don't feel like rendering this now
|
|
dmi.update({'Storage Information' : scsi})
|
|
|
|
catalog = json.dumps(dmi, sort_keys=True, indent=4, separators=(',', ': '))
|
|
data = [ self.CatalogData(id, j2h.json2html.convert( json = catalog, table_attributes="class=\"table-bordered table\"" )) ]
|
|
return data
|
|
|
|
|
|
class BareMetalEventView(tables.MultiTableView):
|
|
table_classes = (baremetal_tables.BareMetalLastEventTable,
|
|
baremetal_tables.BareMetalAllEventsTable,)
|
|
template_name = 'admin/rackhd/events.html'
|
|
page_title = _('Events')
|
|
name = _("Events")
|
|
slug = "events"
|
|
|
|
class HTMLData:
|
|
def __init__(self, id, html):
|
|
self.id = id
|
|
self.html = html
|
|
|
|
class SELEventData:
|
|
def __init__(self, id, type, value, logid, number, time, date, event):
|
|
self.id = id
|
|
self.date = date
|
|
self.event = event
|
|
self.logid = logid
|
|
self.sensor_num = number
|
|
self.sensor_type = type
|
|
self.time = time
|
|
self.value = value
|
|
|
|
def _find_ironic_node(self, id):
|
|
nodes = shovel.get_ironic_nodes()
|
|
for n in nodes['nodes']:
|
|
if n['extra'].get('nodeid', None) == id:
|
|
return n
|
|
|
|
def get_lastevent_data(self):
|
|
id = self.kwargs['baremetal']
|
|
try:
|
|
node = self._find_ironic_node(id)
|
|
if node is not None:
|
|
entry = node['extra']['events']
|
|
return [ self.SELEventData(id,
|
|
entry['sensorType'],
|
|
entry['value'],
|
|
str(int(entry['logId'], 16)),
|
|
entry['sensorNumber'],
|
|
entry['time'],
|
|
entry['date'],
|
|
entry['event']) ]
|
|
except:
|
|
pass
|
|
return []
|
|
|
|
def get_allevents_data(self):
|
|
id = self.kwargs['baremetal']
|
|
try:
|
|
sel = shovel.get_current_sel_data(id)[0].get('sel', [])
|
|
except KeyError as e:
|
|
redirect = reverse('horizon:admin:rackhd:index')
|
|
messages.error(self.request, _('No SEL data available, check node {0} poller task'.format(id)))
|
|
raise KeyError(e.message)
|
|
data = []
|
|
if False: # TODO: enable this, view is not iterating the data list correctly
|
|
for entry in sel:
|
|
data.append(self.SELEventData(id,
|
|
entry['sensorType'],
|
|
entry['value'],
|
|
str(int(entry['logId'], 16)),
|
|
entry['sensorNumber'],
|
|
entry['time'],
|
|
entry['date'],
|
|
entry['event'] ))
|
|
else: # build html
|
|
rsel = list(reversed(sel))
|
|
j = json.dumps({"":rsel}, sort_keys=True, indent=4, separators=(',', ': '))
|
|
return [ self.HTMLData(id, j2h.json2html.convert(json=j, table_attributes="class=\"table\"")) ]
|
|
return data |