--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.Composite import Composite
+from pyjamas.ui.RootPanel import RootPanel
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.HorizontalPanel import HorizontalPanel
+from pyjamas.ui.CaptionPanel import CaptionPanel
+from pyjamas.ui.TextBox import TextBox
+from pyjamas.ui.Button import Button
+from pyjamas.ui.HTML import HTML
+from pyjamas.ui.Grid import Grid
+from pyjamas.ui import HasAlignment
+from SfaData import SfaData
+
+class TopPanel(Composite):
+ panel = None
+
+ def __init__(self):
+ TopPanel.panel = self
+ Composite.__init__(self)
+ self.data = SfaData()
+
+ self.outer = HorizontalPanel()
+ self.inner = VerticalPanel()
+
+ self.outer.setHorizontalAlignment(HasAlignment.ALIGN_RIGHT)
+ self.inner.setHorizontalAlignment(HasAlignment.ALIGN_RIGHT)
+
+ # No links right now...
+ self.links = HorizontalPanel()
+ self.links.setSpacing(4)
+
+ self.outer.add(self.inner)
+ self.refresh()
+
+ self.initWidget(self.outer)
+
+ def onClick(self, sender):
+ pass
+
+ def refresh(self):
+ self.inner.clear()
+ self.inner.add(HTML("<b>User: %s</b>" % self.data.getUser()))
+ self.inner.add(HTML("<b>Slice: %s</b>" % self.data.getSlice()))
+ self.inner.add(self.links)
+
+class LabeledTextBox:
+ def __init__(self, label, initialText):
+ self.hp = CaptionPanel(label)
+ self.tb = TextBox()
+ self.tb.setWidth("100%")
+ self.tb.setText(initialText)
+ self.hp.add(self.tb)
+
+ def getText(self):
+ return self.tb.getText()
+
+ def getWidget(self):
+ return self.hp
+
+class Configure(Sink):
+ def __init__(self):
+ Sink.__init__(self)
+ self.data = SfaData()
+
+ panel = VerticalPanel()
+ panel.setWidth("100%")
+ panel.setWidth("100%")
+
+ self.userBox = LabeledTextBox("User HRN:", SfaData.user)
+ panel.add(self.userBox.getWidget())
+ self.sliceBox = LabeledTextBox("Slice HRN:", SfaData.slice)
+ panel.add(self.sliceBox.getWidget())
+
+ hp = HorizontalPanel()
+ applyButton = Button("Apply", self.apply)
+ hp.add(applyButton)
+ panel.add(hp)
+
+ self.initWidget(panel)
+
+ def apply(self, sender):
+ self.data.setUser(self.userBox.getText())
+ self.data.setSlice(self.sliceBox.getText())
+ TopPanel.panel.refresh()
+
+ def onShow(self):
+ pass
+
+def init():
+ return SinkInfo("Configure", "Configure SFA Federation GUI", Configure)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.HTML import HTML
+
+class Identities(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+
+ text="Not implemented yet"
+ self.initWidget(HTML(text, True))
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("Identities", "Manage SFA Identities", Identities)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.HTML import HTML
+
+class Info(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+
+ text="<div class='infoProse'>This is the SFA Federation GUI. "
+ text+="It allows users to manage their SFA identities and slices, "
+ text+="add resources from various testbeds to their slices, "
+ text+="and browse the SFA Registry.</p></div>"
+ self.initWidget(HTML(text, True))
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("Info", "Introduction to the SFA Federation GUI", Info)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.HTML import HTML
+
+class OpenCirrus(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+
+ text="Not implemented yet"
+ self.initWidget(HTML(text, True))
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("OpenCirrus", "Specify OpenCirrus Resources", OpenCirrus)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.TextArea import TextArea
+from pyjamas.ui.HTML import HTML
+from SfaData import PlanetLabData
+
+class PlanetLab(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+ self.panel = VerticalPanel()
+ self.panel.setSize("100%", "100%")
+ self.data = PlanetLabData()
+ self.rspec = self.data.getRSpec()
+
+ # Just to show that we can retrieve the RSpec
+ ta = TextArea()
+ ta.setSize("100%", "100%")
+ ta.setText(self.rspec)
+ self.panel.add(ta)
+
+ self.initWidget(self.panel)
+
+ def onShow(self):
+ # Do we want to refresh the RSpec?
+ pass
+
+
+
+def init():
+ return SinkInfo("PlanetLab", "Specify PlanetLab Resources", PlanetLab)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.HTML import HTML
+
+class SfaBrowser(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+
+ text="Not implemented yet"
+ self.initWidget(HTML(text, True))
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("Browse SFA", "SFA Hierarchy Browser", SfaBrowser)
--- /dev/null
+import os
+from subprocess import call
+from sfa.util.rspecHelper import RSpec
+
+class SfaData:
+ authority = "plc.princeton"
+ user = "plc.princeton.acb"
+ slice = "plc.princeton.iias"
+
+ def __init__(self):
+ self.registry = None
+ self.slicemgr = None
+
+ def getAuthority(self):
+ return SfaData.authority
+
+ def getUser(self):
+ return SfaData.user
+
+ def setUser(self, user):
+ SfaData.user = user
+
+ # Should probably get authority from user record instead...
+ a = SfaData.user.split('.')
+ SfaData.authority = '.'.join(a[:len(a)-1])
+
+ def getSlice(self):
+ return SfaData.slice
+
+ def setSlice(self, slice):
+ SfaData.slice = slice
+
+ def getRecord(self):
+ pass
+
+ def getRSpec(self):
+ slice = self.getSlice()
+ call(["sfi.py", "-u", self.getUser(), "-a", self.getAuthority(),
+ "-r", self.registry, "-s", self.slicemgr, "resources",
+ "-o", slice, slice])
+ filename = os.path.expanduser("~/.sfi/" + slice + ".rspec")
+ f = open(filename, "r")
+ xml = f.read()
+ f.close()
+ return xml
+
+class ViniData(SfaData):
+ def __init__(self):
+ SfaData.__init__(self)
+ self.registry = "http://www.planet-lab.org:12345"
+ self.slicemgr = "http://www.vini-veritas.net:12347"
+
+ def getRSpec(self):
+ xml = SfaData.getRSpec(self)
+ return RSpec(xml)
+
+class PlanetLabData(SfaData):
+ def __init__(self):
+ SfaData.__init__(self)
+ self.registry = "http://www.planet-lab.org:12345"
+ self.slicemgr = "http://www.planet-lab.org:12347"
+
+class OpenCirrusData(SfaData):
+ def __init__(self):
+ SfaData.__init__(self)
+ self.registry = "http://www.planet-lab.org:12345"
+ self.slicemgr = "http://www.planet-lab.org:12347"
+
--- /dev/null
+import pyjd # this is dummy in pyjs
+
+from pyjamas.ui.Button import Button
+from pyjamas.ui.RootPanel import RootPanel
+from pyjamas.ui.HTML import HTML
+from pyjamas.ui.DockPanel import DockPanel
+from pyjamas.ui import HasAlignment
+from pyjamas.ui.Hyperlink import Hyperlink
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas import Window
+from SinkList import SinkList
+from Configure import TopPanel
+from pyjamas import History
+import Info
+import Slices
+import Identities
+import PlanetLab
+import VINI
+import OpenCirrus
+import SfaBrowser
+import Configure
+
+class SfaGUI:
+ def onHistoryChanged(self, token):
+ info = self.sink_list.find(token)
+ if info:
+ self.show(info, False)
+ else:
+ self.showInfo()
+
+ def onModuleLoad(self):
+ self.tp = TopPanel()
+ self.tp.setWidth("100%")
+
+ self.curInfo=''
+ self.curSink=None
+ self.description=HTML()
+ self.sink_list=SinkList()
+ self.panel=DockPanel()
+ self.loadSinks()
+ self.sinkContainer = DockPanel()
+ self.sinkContainer.setStyleName("ks-Sink")
+
+ vp=VerticalPanel()
+ vp.setWidth("100%")
+ vp.setHeight("100%")
+ vp.add(self.description)
+ vp.add(self.sinkContainer)
+
+ self.description.setStyleName("ks-Info")
+
+ self.panel.add(self.sink_list, DockPanel.WEST)
+ self.panel.add(vp, DockPanel.CENTER)
+
+ self.panel.setCellVerticalAlignment(self.sink_list, HasAlignment.ALIGN_TOP)
+ self.panel.setCellWidth(vp, "100%")
+ self.panel.setCellHeight(vp, "100%")
+
+ History.addHistoryListener(self)
+ RootPanel().add(self.tp)
+ RootPanel().add(self.panel)
+
+ #Show the initial screen.
+ initToken = History.getToken()
+ if len(initToken):
+ self.onHistoryChanged(initToken)
+ else:
+ self.showInfo()
+
+ def show(self, info, affectHistory):
+ if info == self.curInfo: return
+ self.curInfo = info
+
+ if self.curSink <> None:
+ self.curSink.onHide()
+ self.sinkContainer.remove(self.curSink)
+
+ self.curSink = info.getInstance()
+ self.sink_list.setSinkSelection(info.getName())
+ self.description.setHTML(info.getDescription())
+
+ if (affectHistory):
+ History.newItem(info.getName())
+
+ self.sinkContainer.add(self.curSink, DockPanel.CENTER)
+ self.sinkContainer.setCellWidth(self.curSink, "100%")
+ self.sinkContainer.setCellHeight(self.curSink, "100%")
+ self.sinkContainer.setCellVerticalAlignment(self.curSink, HasAlignment.ALIGN_TOP)
+ self.curSink.onShow()
+
+ def loadSinks(self):
+ self.sink_list.addSink(Info.init())
+ self.sink_list.addSink(Identities.init())
+ self.sink_list.addSink(Slices.init())
+ self.sink_list.addSink(PlanetLab.init())
+ self.sink_list.addSink(VINI.init())
+ self.sink_list.addSink(OpenCirrus.init())
+ self.sink_list.addSink(SfaBrowser.init())
+ self.sink_list.addSink(Configure.init())
+
+ def showInfo(self):
+ self.show(self.sink_list.find("Info"), False)
+
+
+
+
+if __name__ == '__main__':
+ pyjd.setup("public/SfaGUI.html")
+ app = SfaGUI()
+ app.onModuleLoad()
+ pyjd.run()
--- /dev/null
+from pyjamas.ui.Composite import Composite
+
+class Sink(Composite):
+ def __init__(self):
+ Composite.__init__(self)
+
+ def onHide(self):
+ pass
+
+ def onShow(self):
+ pass
+
+ def baseURL(self):
+ return ""
+
+class SinkInfo:
+ def __init__(self, name, desc, object_type):
+ self.name=name
+ self.description=desc
+ self.object_type=object_type
+ self.instance=None
+
+ def createInstance(self):
+ return self.object_type()
+
+ def getDescription(self):
+ return self.description
+
+ def getInstance(self):
+ if self.instance==None:
+ self.instance=self.createInstance()
+ return self.instance
+
+ def getName(self):
+ return self.name
+
--- /dev/null
+from pyjamas.ui.Composite import Composite
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.Hyperlink import Hyperlink
+
+class SinkList(Composite):
+ def __init__(self):
+ Composite.__init__(self)
+
+ self.vp_list=VerticalPanel()
+ self.sinks=[]
+ self.selectedSink=-1
+
+ self.initWidget(self.vp_list)
+ self.setStyleName("ks-List")
+
+ def addSink(self, info):
+ name = info.getName()
+ link = Hyperlink(name, False, name)
+ link.setStyleName("ks-SinkItem")
+ self.vp_list.add(link)
+ self.sinks.append(info)
+
+ def find(self, sinkName):
+ for info in self.sinks:
+ if info.getName()==sinkName:
+ return info
+ return None
+
+ def setSinkSelection(self, name):
+ if self.selectedSink <> -1:
+ self.vp_list.getWidget(self.selectedSink).removeStyleName("ks-SinkItem-selected")
+
+ for i in range(len(self.sinks)):
+ info = self.sinks[i]
+ if (info.getName()==name):
+ self.selectedSink = i
+ widget=self.vp_list.getWidget(self.selectedSink)
+ widget.addStyleName("ks-SinkItem-selected")
+ return
+
+
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.HTML import HTML
+
+class Slices(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+
+ text="Not implemented yet"
+ self.initWidget(HTML(text, True))
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("Slices", "Manage SFA Slices", Slices)
--- /dev/null
+from Sink import Sink, SinkInfo
+from pyjamas.ui.horizsplitpanel import HorizontalSplitPanel
+from pyjamas.ui.CaptionPanel import CaptionPanel
+from pyjamas.ui.ListBox import ListBox
+from pyjamas.ui.HTML import HTML
+from SfaData import ViniData
+
+class VINI(Sink):
+ def __init__(self):
+
+ Sink.__init__(self)
+ self.panel = HorizontalSplitPanel()
+ self.panel.setSize("100%", "100%")
+ self.panel.setSplitPosition("50%")
+ self.data = ViniData()
+ self.rspec = self.data.getRSpec()
+
+ leftcap = CaptionPanel("Available nodes")
+ leftcap.setSize("90%", "90%")
+ leftlist = ListBox(MultipleSelect=True)
+ leftlist.setSize("100%", "100%")
+ available = self.rspec.get_node_list()
+ for i in available:
+ leftlist.addItem(i)
+ leftcap.add(leftlist)
+
+ rightcap = CaptionPanel("Selected nodes")
+ rightcap.setSize("90%", "90%")
+ rightlist = ListBox(MultipleSelect=True)
+ rightlist.setSize("100%", "100%")
+ slivers = self.rspec.get_sliver_list()
+ for i in slivers:
+ rightlist.addItem(i)
+ rightcap.add(rightlist)
+
+ self.panel.setLeftWidget(leftcap)
+ self.panel.setRightWidget(rightcap)
+
+ self.initWidget(self.panel)
+
+ def onShow(self):
+ pass
+
+
+def init():
+ return SinkInfo("VINI", "Specify VINI Resources", VINI)
--- /dev/null
+#!/bin/sh
+../../bin/pyjsbuild $@ SfaGUI
--- /dev/null
+body {
+ background-color: white;
+ color: black;
+ font-family: Arial, sans-serif;
+ font-size: smaller;
+ margin: 20px 20px 20px 20px;
+}
+
+code {
+ font-size: small;
+}
+
+a {
+ color: darkblue;
+}
+
+a:visited {
+ color: darkblue;
+}
+
+.gwt-BorderedPanel {
+}
+
+.gwt-Button {
+}
+
+.gwt-Canvas {
+}
+
+.gwt-CheckBox {
+ font-size: smaller;
+}
+
+.gwt-DialogBox {
+ sborder: 8px solid #C3D9FF;
+ border: 2px outset;
+ background-color: white;
+}
+
+.gwt-DialogBox .Caption {
+ background-color: #C3D9FF;
+ padding: 3px;
+ margin: 2px;
+ font-weight: bold;
+ cursor: default;
+}
+
+.gwt-FileUpload {
+}
+
+.gwt-Frame {
+}
+
+.gwt-HorizontalSplitter .Bar {
+ width: 8px;
+ background-color: #C3D9FF;
+}
+
+.gwt-VerticalSplitter .Bar {
+ height: 8px;
+ background-color: #C3D9FF;
+}
+
+.gwt-HTML {
+ font-size: smaller;
+}
+
+.gwt-Hyperlink {
+}
+
+.gwt-Image {
+}
+
+.gwt-Label {
+ font-size: smaller;
+}
+
+.gwt-ListBox {
+}
+
+.gwt-MenuBar {
+ background-color: #C3D9FF;
+ border: 1px solid #87B3FF;
+ cursor: default;
+}
+
+.gwt-MenuBar .gwt-MenuItem {
+ padding: 1px 4px 1px 4px;
+ font-size: smaller;
+ cursor: default;
+}
+
+.gwt-MenuBar .gwt-MenuItem-selected {
+ background-color: #E8EEF7;
+}
+
+.gwt-PasswordTextBox {
+}
+
+.gwt-RadioButton {
+ font-size: smaller;
+}
+
+.gwt-TabPanel {
+}
+
+.gwt-TabPanelBottom {
+ border-left: 1px solid #87B3FF;
+}
+
+.gwt-TabBar {
+ background-color: #C3D9FF;
+ font-size: smaller;
+}
+
+.gwt-TabBar .gwt-TabBarFirst {
+ height: 100%;
+ border-bottom: 1px solid #87B3FF;
+ padding-left: 3px;
+}
+
+.gwt-TabBar .gwt-TabBarRest {
+ border-bottom: 1px solid #87B3FF;
+ padding-right: 3px;
+}
+
+.gwt-TabBar .gwt-TabBarItem {
+ border-top: 1px solid #C3D9FF;
+ border-bottom: 1px solid #87B3FF;
+ padding: 2px;
+ cursor: pointer;
+ cursor: hand;
+}
+
+.gwt-TabBar .gwt-TabBarItem-selected {
+ font-weight: bold;
+ background-color: #E8EEF7;
+ border-top: 1px solid #87B3FF;
+ border-left: 1px solid #87B3FF;
+ border-right: 1px solid #87B3FF;
+ border-bottom: 1px solid #E8EEF7;
+ padding: 2px;
+ cursor: default;
+}
+
+.gwt-TextArea {
+}
+
+.gwt-TextBox {
+}
+
+.gwt-Tree {
+}
+
+.gwt-Tree .gwt-TreeItem {
+ font-size: smaller;
+}
+
+.gwt-Tree .gwt-TreeItem-selected {
+ background-color: #C3D9FF;
+}
+
+.gwt-StackPanel {
+}
+
+.gwt-StackPanel .gwt-StackPanelItem {
+ background-color: #C3D9FF;
+ cursor: pointer;
+ cursor: hand;
+}
+
+.gwt-StackPanel .gwt-StackPanelItem-selected {
+}
+
+/* -------------------------------------------------------------------------- */
+.ks-Sink {
+ border: 8px solid #C3D9FF;
+ background-color: #E8EEF7;
+ width: 100%;
+ height: 24em;
+}
+
+.ks-Info {
+ background-color: #C3D9FF;
+ padding: 10px 10px 2px 10px;
+ font-size: smaller;
+}
+
+.ks-List {
+ margin-top: 8px;
+ margin-bottom: 8px;
+ font-size: smaller;
+}
+
+.ks-List .ks-SinkItem {
+ width: 100%;
+ padding: 0.3em;
+ padding-right: 16px;
+ cursor: pointer;
+ cursor: hand;
+}
+
+.ks-List .ks-SinkItem-selected {
+ background-color: #C3D9FF;
+}
+
+.ks-images-Image {
+ margin: 8px;
+}
+
+.ks-images-Button {
+ margin: 8px;
+ cursor: pointer;
+ cursor: hand;
+}
+
+.ks-layouts {
+ margin: 8px;
+}
+
+.ks-layouts-Label {
+ background-color: #C3D9FF;
+ font-weight: bold;
+ margin-top: 1em;
+ padding: 2px 0px 2px 0px;
+ width: 100%;
+}
+
+.ks-layouts-Scroller {
+ height: 128px;
+ border: 2px solid #C3D9FF;
+ padding: 8px;
+ margin: 8px;
+}
+
+.ks-popups-Popup {
+ background-color: white;
+ border: 1px solid #87B3FF;
+ padding: 4px;
+}
+
+.infoProse {
+ margin: 8px;
+}
+
+/******************************************************
+* DisclosurePanel
+******************************************************/
+.gwt-DisclosurePanel
+{
+ background-color : #ddf;
+ border : 1px solid #009;
+}
+.gwt-DisclosurePanel .header
+{
+ font-size : 70%;
+ cursor : pointer;
+ cursor : hand;
+}
+.gwt-DisclosurePanel-closed
+{
+}
+.gwt-DisclosurePanel-closed .header
+{
+}
+.gwt-DisclosurePanel-open
+{
+}
+.gwt-DisclosurePanel-open .header
+{
+}
+.gwt-DisclosurePanel-open .content
+{
+}
+
+.gwt-HorizontalSplitPanel {
+}
+
+.gwt-HorizontalSplitPanel .hsplitter {
+ cursor: move;
+ border: 0px;
+ background: #91c0ef url(images/vborder.png) repeat-x;
+}
+
+.gwt-VerticalSplitPanel {
+}
+
+.gwt-VerticalSplitPanel .vsplitter {
+ cursor: move;
+ border: 0px;
+ background: #91c0ef url(images/hborder.png) repeat-x;
+}
--- /dev/null
+<html>
+ <head>
+ <meta name="pygwt:module" content="SfaGUI">
+ <link rel='stylesheet' href='SfaGUI.css'>
+ <title>SFA Federation GUI</title>
+ </head>
+ <body bgcolor="white">
+ <script language="javascript" src="bootstrap.js"></script>
+
+ <iframe id='__pygwt_historyFrame' style='width:0;height:0;border:0'></iframe>
+ </body>
+</html>
+
--- /dev/null
+.gwt-HorizontalSplitPanel {
+}
+
+.gwt-HorizontalSplitPanel .hsplitter {
+ cursor: move;
+ border: 0px;
+ background: #91c0ef url(images/vborder.png) repeat-x;
+}
+.gwt-VerticalSplitPanel {
+}
+
+.gwt-VerticalSplitPanel .vsplitter {
+ cursor: move;
+ border: 0px;
+ background: #91c0ef url(images/hborder.png) repeat-x;
+}