from sface.config import config
from sface.sfiprocess import SfiProcess
#from sface.sfithread import SfiThread
+from sface.sliceview import SliceView, SliceModel
class SfiRenewer(QObject):
def __init__(self, hrn, newExpiration, parent=None):
self.renewProcess = SfiProcess(self)
self.connect(self.renewProcess, SIGNAL('finished()'), self.finishedGetRecord)
- self.renewProcess.getRecord(hrn=config.getSlice(), filename="/tmp/slicerecord")
+ self.renewProcess.getRecord(hrn=hrn, filename="/tmp/slicerecord")
def finishedGetRecord(self):
- faultString = self.renewProcess.getFaultString()
- if faultString:
- self.emitFinished("fault", faultString)
+ self.faultString = self.renewProcess.getFaultString()
+ if self.faultString:
+ self.emitFinished("fault", self.faultString)
return
f = open("/tmp/slicerecord", "r")
exp = re.compile('expires="[^"]*"')
if exp.search(data)==None:
# didn't find it
- self.emitFinished("failure", "failed to find expiration in slice record")
+ self.faultString = "failed to find expiration in slice record"
+ self.emitFinished("failure", self.faultString)
return
# change the expiration time
self.renewProcess.updateRecord("/tmp/slicerecord")
def finishedUpdateRecord(self):
- faultString = self.renewProcess.getFaultString()
- if faultString:
- self.emitFinished("fault", faultString)
+ self.faultString = self.renewProcess.getFaultString()
+ if self.faultString:
+ self.emitFinished("fault", self.faultString)
return
# we have to force sfi.py to download an updated slice credential
self.renewProcess.renewSlivers(self.newExpiration.strftime("%Y-%m-%dT%H:%M:%SZ"))
def finishedRenewSlivers(self):
- faultString = self.renewProcess.getFaultString()
- if faultString:
- self.emitFinished("fault", faultString)
+ self.faultString = self.renewProcess.getFaultString()
+ if self.faultString:
+ self.emitFinished("fault", self.faultString)
return
self.emitFinished("success")
self.statusMsg = statusMsg
self.emit(SIGNAL("finished()"))
+ def getFaultString(self):
+ return self.faultString
+
class RenewWindow(QDialog):
- def __init__(self, parent=None):
+ def __init__(self, batch=False, parent=None):
super(RenewWindow, self).__init__(parent)
self.setWindowTitle("Renew Slivers")
+ self.batch = batch
+
self.renewProcess = None
+ durationLabel = QLabel("Duration:")
self.duration = QComboBox()
self.expirations = []
self.duration.setCurrentIndex(0)
+ if self.batch:
+ sliceLabel = QLabel("Slices:")
+ self.sliceView = SliceView()
+
self.status = QLabel("")
self.status.setMaximumWidth(640)
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
+ if not self.batch:
+ self.buttonBox.addButton("Batch", QDialogButtonBox.ActionRole)
+
layout = QVBoxLayout()
+ layout.addWidget(durationLabel)
layout.addWidget(self.duration)
+ if self.batch:
+ layout.addWidget(sliceLabel)
+ layout.addWidget(self.sliceView)
layout.addWidget(self.status)
layout.addWidget(self.buttonBox)
self.setLayout(layout)
- #self.status.hide()
-
self.connect(self.buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
self.connect(self.buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))
+ self.connect(self.buttonBox, SIGNAL("clicked(QAbstractButton *)"), self.clicked)
- def accept(self):
- self.setStatus("Renewing Slice...")
+ if self.batch:
+ self.sliceModel = SliceModel()
+ self.refreshAuthority()
- self.renewProcess = SfiRenewer(config.getSlice(), self.get_new_expiration(), self)
- self.connect(self.renewProcess, SIGNAL('finished()'), self.renewFinished)
+ def clicked(self, button):
+ if button.text() == "Batch":
+ # close ourself, and reopen the batch renew window
+ self.close()
+ dlg = RenewWindow(batch=True, parent=self.parent())
+ dlg.exec_()
+
+ def accept(self):
+ if self.batch:
+ self.slicesToRenew = self.sliceModel.getSelectedSlices()
+ if self.slicesToRenew == []:
+ QMessageBox.warning(self, "No Slices", "Please add at least on slice by double-clicking on a slice name")
+ return
+ else:
+ self.slicesToRenew = [config.getSlice()]
self.duration.setEnabled(False)
self.buttonBox.setEnabled(False)
+ if self.batch:
+ self.sliceView.setEnabled(False)
+
+ self.renewNextSlice()
def setStatus(self, x):
self.status.setText(x)
+ def renewNextSlice(self):
+ self.sliceName = self.slicesToRenew.pop(0)
+ self.renewProcess = SfiRenewer(self.sliceName, self.get_new_expiration(), self)
+ self.connect(self.renewProcess, SIGNAL('finished()'), self.renewFinished)
+ self.setStatus("<font color='green'>Renewing: %s.</font>" % self.sliceName)
+
def renewFinished(self):
- if self.renewProcess.status == "success":
- color = "green"
- # give the user the <close> button
- self.buttonBox.clear()
- self.buttonBox.addButton(QDialogButtonBox.Close)
- else:
- color = "red"
+ self.disconnect(self.renewProcess, SIGNAL('finished()'), self.renewFinished)
- if self.renewProcess.statusMsg:
- self.setStatus("<font color='%s'>Renew %s: %s</font>" % (color, self.renewProcess.status, self.renewProcess.statusMsg))
+ faultString = self.renewProcess.getFaultString()
+ if faultString:
+ self.setStatus("<font color='red'>Renew %s Error: %s</font>" % (self.sliceName, faultString))
+ self.buttonBox.setEnabled(True)
else:
- self.setStatus("<font color='%s'>Renew %s</font>" % (color, self.renewProcess.status))
-
- self.buttonBox.setEnabled(True)
+ self.setStatus("<font color='green'>Renew %s Success</font>" % self.sliceName)
- self.disconnect(self.renewProcess, SIGNAL('finished()'), self.renewFinished)
- self.renewProcess = None
+ if (self.slicesToRenew != []):
+ self.renewNextSlice()
+ else:
+ # give the user the <close> button
+ self.buttonBox.clear()
+ self.buttonBox.addButton(QDialogButtonBox.Close)
+ self.buttonBox.setEnabled(True)
def get_new_expiration(self):
index = self.duration.currentIndex()
return self.expirations[index]
+
+ def refreshAuthority(self):
+ self.process = SfiProcess(self)
+ self.connect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
+
+ self.process.listRecords(config.getAuthority(), None, config.getAuthorityListFile())
+ self.setStatus("Refreshing slice list. This will take a moment...")
+
+ def getAuthorityRecordFinished(self):
+ self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
+
+ faultString = self.process.getFaultString()
+ if not faultString:
+ self.setStatus("<font color='green'>Slice list refreshed.</font>")
+ self.updateSliceView()
+ else:
+ self.setStatus("<font color='red'>Authority rec refresh error: %s</font>" % (faultString))
+
+ def updateSliceView(self):
+ self.sliceModel.updateModel()
+
+ self.sliceView.setModel(self.sliceModel)
+ self.sliceView.resizeColumnToContents(0)
+
--- /dev/null
+import datetime
+import os
+import pickle
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from sfa.util.record import SfaRecord, SliceRecord, AuthorityRecord
+from sface.config import config
+
+NAME_COLUMN = 0
+MEMBERSHIP_STATUS_COLUMN = 1
+
+# maximum length of a name to display before clipping
+NAME_MAX_LEN = 48
+
+slice_status = { "in": "Selected",
+ "out": "Not Selected"}
+
+color_status = { "in": QColor.fromRgb(0, 250, 250), }
+
+class SliceNameDelegate(QStyledItemDelegate):
+ def __init__(self, parent):
+ QStyledItemDelegate.__init__(self, parent)
+
+ def displayText(self, value, locale):
+ data = str(QStyledItemDelegate.displayText(self, value, locale))
+ if (len(data)>NAME_MAX_LEN):
+ data = data[:(NAME_MAX_LEN-3)] + "..."
+ return QString(data)
+
+ def paint(self, painter, option, index):
+ model = index.model()
+ data = str(self.displayText(index.data(), QLocale()))
+ status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
+ status_data = status_index.data().toString()
+
+ fm = QFontMetrics(option.font)
+ rect = QRect(option.rect)
+
+ rect.setHeight(rect.height() - 2)
+ rect.setWidth(fm.width(QString(data)) + 6)
+ rect.setX(rect.x() + 5)
+ rect.setY(rect.y() - 1)
+
+ textRect = QRect(option.rect)
+ textRect.setWidth(fm.width(QString(data)) + 6)
+ textRect.setX(rect.x())
+
+ x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width()
+
+ path = QPainterPath()
+ path.addRoundedRect(x - 1, y + 1, w, h, 4, 4)
+
+ painter.save()
+ painter.setRenderHint(QPainter.Antialiasing)
+
+ if option.state & QStyle.State_Selected:
+ painter.fillRect(option.rect, option.palette.color(QPalette.Active, QPalette.Highlight))
+
+ color = None
+ for x in slice_status.keys():
+ if (slice_status[x] == status_data) and (x in color_status):
+ color = color_status[x]
+
+ if color != None:
+ painter.fillPath(path, color)
+ painter.setPen(QColor.fromRgb(0, 0, 0))
+ painter.drawText(textRect, Qt.AlignVCenter, QString(data))
+
+ painter.restore()
+
+class SliceView(QTableView):
+ def __init__(self, parent=None):
+ QTableView.__init__(self, parent)
+
+ self.setSelectionBehavior(QAbstractItemView.SelectRows)
+ self.setSelectionMode(QAbstractItemView.SingleSelection)
+ 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.")
+
+ self.setItemDelegateForColumn(0, SliceNameDelegate(self))
+
+ def keyPressEvent(self, event):
+ if (event.key() == Qt.Key_Space):
+ self.toggleSelection()
+ else:
+ QTableView.keyPressEvent(self, event)
+
+ def mouseDoubleClickEvent(self, event):
+ self.toggleSelection()
+
+ def toggleSelection(self):
+ index = self.currentIndex()
+ model = index.model()
+ status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
+ status_data = status_index.data().toString()
+ node_index = model.index(index.row(), NAME_COLUMN, index.parent())
+ node_data = node_index.data().toString()
+
+ if status_data == slice_status['in']:
+ model.setData(status_index, QString(slice_status['out']))
+ else:
+ model.setData(status_index, QString(slice_status['in']))
+
+ model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), node_index, node_index)
+
+ def currentChanged(self, current, previous):
+ model = current.model()
+ node_index = model.index(current.row(), 0, current.parent())
+ node_data = node_index.data().toString()
+
+class SliceModel(QStandardItemModel):
+ def __init__(self, rows=0, columns=4, parent=None):
+ QStandardItemModel.__init__(self, rows, columns, parent)
+
+ def updateModel(self):
+ self.clear()
+
+ slice_names = []
+
+ i=0
+ while (os.path.exists(config.getAuthorityListFile(i))):
+ rec = self.readSliceRecord(i)
+ if rec:
+ name = str(rec.get_name())
+ if (rec.get_type() == "slice"):
+ slice_names.append(name)
+ i=i+1
+
+ rootItem = self.invisibleRootItem()
+
+ for name in slice_names:
+ rootItem.appendRow([self.readOnlyItem(name),
+ self.readOnlyItem(slice_status["out"])])
+
+ headers = QStringList() << "Slice Name" << "Status"
+ self.setHorizontalHeaderLabels(headers)
+
+ def readOnlyItem(self, x):
+ item = QStandardItem(QString(x))
+ item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
+ return item
+
+ def getSelectedSlices(self):
+ slices = []
+ item = self.invisibleRootItem()
+ children = item.rowCount()
+ for row in range(0, children):
+ childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
+ childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
+
+ if (childStatus == slice_status['in']):
+ slices.append(childName)
+
+ return slices
+
+ def readSliceRecord(self, i):
+ rec_file = config.getAuthorityListFile(i)
+ if os.path.exists(rec_file):
+ xml = open(rec_file).read()
+ rec = SliceRecord()
+ rec.load_from_string(xml)
+ return rec
+ return None
+