+
+import datetime
+import os
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from sfa.rspecs.rspec_parser import parse_rspec
+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("<font color='green'>Sliver status refreshed.</font>", timeout=5000)
+ else:
+ self.setStatus("<font color='red'>Sliver status failed: %s</font>" % (faultString))
+
+ self.updateView()
+
+ def setStatus(self, msg, timeout=None):
+ self.parent().setStatus(msg, timeout)
+
+ def checkRunningProcess(self):
+ if self.process.isRunning():
+ self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
+ 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("<font color='red'>Slice not set yet!</font>")
+ return
+
+ if self.process.isRunning():
+ self.setStatus("<font color='red'>There is already a process running. Please wait.</font>")
+ 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)
+
+ 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
+