import datetime import os from PyQt4.QtCore import * from PyQt4.QtGui import * from sface.config import config from sface.sfirenew import RenewWindow from sface.sfiprocess import SfiProcess from sface.screens.sfascreen import SfaScreen from sface.sfidata import SfiData NAME_COLUMN = 0 GENI_STATUS_COLUMN = 1 class StatusView(QTreeView): def __init__(self, parent): QTreeView.__init__(self, parent) self.setAnimated(True) self.setItemsExpandable(True) self.setRootIsDecorated(True) self.setAlternatingRowColors(True) self.setAttribute(Qt.WA_MacShowFocusRect, 0) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setToolTip("Double click on a row to change its status. Right click on a host to add a tag.") class StatusFilterProxyModel(QSortFilterProxyModel): def __init__(self, parent=None): QSortFilterProxyModel.__init__(self, parent) self.hostname_filter_regex = None self.geni_status_filter = None def setHostNameFilter(self, hostname): self.hostname_filter_regex = QRegExp(hostname) self.invalidateFilter() def setNodeStatusFilter(self, status): if (status == "all"): self.geni_status_filter = None else: self.geni_status_filter = status self.invalidateFilter() def filterAcceptsRow(self, sourceRow, source_parent): if self.hostname_filter_regex: name_data = self.sourceModel().index(sourceRow, NAME_COLUMN, source_parent).data().toString() if (self.hostname_filter_regex.indexIn(name_data) < 0): return False if self.geni_status_filter: geni_status_data = self.sourceModel().index(sourceRow, GENI_STATUS_COLUMN, source_parent).data().toString() if (geni_status_data != self.geni_status_filter): return False return True class StatusWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self.process = SfiProcess(self) self.slicename = QLabel("", self) self.updateSliceName() self.slicename.setScaledContents(False) filterlabel = QLabel ("Filter: ", self) filterbox = QComboBox(self) filterbox.addItems(["all", "ready", "failed"]) searchlabel = QLabel ("Search: ", self) searchlabel.setScaledContents(False) searchbox = QLineEdit(self) searchbox.setAttribute(Qt.WA_MacShowFocusRect, 0) self.urn = QLabel("", self) self.login = QLabel("", self) toplayout1 = QHBoxLayout() toplayout1.addWidget(self.slicename, 0, Qt.AlignLeft) toplayout1.addStretch() toplayout1.addWidget(filterlabel, 0, Qt.AlignRight) toplayout1.addWidget(filterbox, 0, Qt.AlignRight) toplayout1.addWidget(searchlabel, 0, Qt.AlignRight) toplayout1.addWidget(searchbox, 0, Qt.AlignRight) toplayout2 = QHBoxLayout() toplayout2.addWidget(self.urn, 0, Qt.AlignRight) toplayout2.addWidget(self.login, 0, Qt.AlignRight) toplayout2.addStretch() toplayout = QVBoxLayout() toplayout.addLayout(toplayout1) toplayout.addLayout(toplayout2) self.statusView = StatusView(self) self.statusModel = QStandardItemModel(0, 4, self) self.filterModel = StatusFilterProxyModel(self) refresh = QPushButton("Refresh", self) refresh.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) bottomlayout = QHBoxLayout() bottomlayout.addWidget(refresh, 0, Qt.AlignLeft) bottomlayout.addStretch() layout = QVBoxLayout() layout.addLayout(toplayout) layout.addWidget(self.statusView) layout.addLayout(bottomlayout) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.connect(refresh, SIGNAL('clicked()'), self.refresh) self.connect(searchbox, SIGNAL('textChanged(QString)'), self.search) self.connect(filterbox, SIGNAL('currentIndexChanged(QString)'), self.filter) self.updateView() def sliverStatusFinished(self): self.disconnect(self.process, SIGNAL('finished()'), self.sliverStatusFinished) faultString = self.process.getFaultString() if not faultString: self.setStatus("Sliver status refreshed.", timeout=5000) else: self.setStatus("Sliver status failed: %s" % (faultString)) self.updateView() def setStatus(self, msg, timeout=None): self.parent().setStatus(msg, timeout) def checkRunningProcess(self): if self.process.isRunning(): self.setStatus("There is already a process running. Please wait.") return True return False def search(self, search_string): self.filterModel.setHostNameFilter(str(search_string)) def filter(self, filter_string): self.filterModel.setNodeStatusFilter(str(filter_string)) def itemStatus(self, item): statusItem = item.parent().child(item.row(), MEMBERSHIP_STATUS_COLUMN) return str(statusItem.data(Qt.DisplayRole).toString()) def itemText(self, item): return str(item.data(Qt.DisplayRole).toString()) def refresh(self): if not config.getSlice(): self.setStatus("Slice not set yet!") return if self.process.isRunning(): self.setStatus("There is already a process running. Please wait.") return self.connect(self.process, SIGNAL('finished()'), self.sliverStatusFinished) self.process.sliverStatus() self.setStatus("Refreshing Sliver Status. This will take some time...") def updateView(self): self.statusModel.clear() sliverStatus = SfiData().getSliverStatus() if not sliverStatus: return None geni_urn = sliverStatus.get("geni_urn","") self.urn.setText("URN: " + geni_urn) login = sliverStatus.get("pl_login","") self.login.setText("Login: " + login) rootItem = self.statusModel.invisibleRootItem() resources = sliverStatus.get("geni_resources", []) for resource in resources: # try to pick the most useful thing name = resource.get("pl_hostname","") if not name: name = resource.get("geni_urn","") if not name: continue status = resource.get("geni_status","") error = resource.get("error", "") lastContact = resource.get("pl_last_contact", "") # some of these return None, and we need to convert that back to # an empty string if not status: status = "" if not error: error = "" if not lastContact: lastContact = "" nameItem = QStandardItem(QString(name)) statusItem = QStandardItem(QString(status)) errorItem = QStandardItem(QString(error)) lastContact = QStandardItem(QString(lastContact)) rootItem.appendRow([nameItem, statusItem, errorItem, lastContact]) self.filterModel.setSourceModel(self.statusModel) self.filterModel.setDynamicSortFilter(True) self.filterModel.sort(NAME_COLUMN) headers = QStringList() << "URN" << "Status" << "Error" << "Last Contact" self.statusModel.setHorizontalHeaderLabels(headers) self.statusView.setModel(self.filterModel) self.statusView.expandAll() self.statusView.resizeColumnToContents(0) self.statusView.collapseAll() def updateSliceName(self): self.slicename.setText("Slice : %s" % (config.getSlice() or "None")) class StatusScreen(SfaScreen): def __init__(self, parent): SfaScreen.__init__(self, parent) slice = StatusWidget(self) self.init(slice, "Status", "Sliver Status") def rspecUpdated(self): pass def configurationChanged(self): self.widget.updateSliceName() self.widget.updateView() def nodeSelectionChanged(self, hostname): pass