Allow reconnecting to the same terminal session
[invirt/packages/invirt-web.git] / code / main.py
index 207ba98..77646c9 100755 (executable)
@@ -37,6 +37,7 @@ from invirt.config import structs as config
 from invirt.common import InvalidInput, CodeError
 
 from view import View, revertStandardError
+import ajaxterm
 
 
 static_dir = os.path.join(os.path.dirname(__file__), 'static')
@@ -124,11 +125,9 @@ class InvirtWeb(View):
     @cherrypy.tools.mako(filename="/list.mako")
     def list(self, result=None):
         """Handler for list requests."""
-        checkpoint.checkpoint('Getting list dict')
         d = getListDict(cherrypy.request.login, cherrypy.request.state)
         if result is not None:
             d['result'] = result
-        checkpoint.checkpoint('Got list dict')
         return d
     index=list
 
@@ -285,7 +284,6 @@ console will suffer artifacts.
                                           cherrypy.request.state,
                                           machine_id=machine_id).machine
             d = infoDict(cherrypy.request.login, cherrypy.request.state, machine)
-            checkpoint.checkpoint('Got infodict')
             return d
         index = info
 
@@ -391,22 +389,47 @@ console will suffer artifacts.
             else:
                 raise InvalidInput('back', back, 'Not a known back page.')
 
-    machine = MachineView()
+        atmulti = ajaxterm.Multiplex()
+        atsessions = {}
 
-class Checkpoint:
-    def __init__(self):
-        self.start_time = time.time()
-        self.checkpoints = []
+        @cherrypy.expose
+        @cherrypy.tools.mako(filename="/terminal.mako")
+        def terminal(self, machine_id):
+            machine = validation.Validate(cherrypy.request.login, cherrypy.request.state, machine_id=machine_id).machine
 
-    def checkpoint(self, s):
-        self.checkpoints.append((s, time.time()))
+            status = controls.statusInfo(machine)
+            has_vnc = hasVnc(status)
 
-    def __str__(self):
-        return ('Timing info:\n%s\n' %
-                '\n'.join(['%s: %s' % (d, t - self.start_time) for
-                           (d, t) in self.checkpoints]))
+            d = dict(on=status,
+                     has_vnc=has_vnc,
+                     machine=machine,
+                     hostname=cherrypy.request.local.name)
+            return d
+
+        @cherrypy.expose
+        def at(self, machine_id, k=None, c=0, force=0):
+            machine = validation.Validate(cherrypy.request.login, cherrypy.request.state, machine_id=machine_id).machine
+            if machine_id in self.atsessions:
+                term = self.atsessions[machine_id]
+            else:
+                print >>sys.stderr, "spawning new session for terminal to ",machine_id
+                term = self.atsessions[machine_id] = self.atmulti.create(
+                    ["ssh", "-e","none", "-l", machine.name, config.console.hostname]
+                    )
+            if k:
+                self.atmulti.proc_write(term,k)
+            time.sleep(0.002)
+            dump=self.atmulti.dump(term,c,int(force))
+            cherrypy.response.headers['Content-Type']='text/xml'
+            if isinstance(dump,str):
+                return dump
+            else:
+                print "Removing session for", machine_id
+                del self.atsessions[machine_id]
+                return '<?xml version="1.0"?><idem></idem>'
+
+    machine = MachineView()
 
-checkpoint = Checkpoint()
 
 class Defaults:
     """Class to store default values for fields."""
@@ -440,14 +463,11 @@ def hasVnc(status):
 
 def getListDict(username, state):
     """Gets the list of local variables used by list.tmpl."""
-    checkpoint.checkpoint('Starting')
     machines = state.machines
-    checkpoint.checkpoint('Got my machines')
     on = {}
     has_vnc = {}
     installing = {}
     xmlist = state.xmlist
-    checkpoint.checkpoint('Got uptimes')
     for m in machines:
         if m not in xmlist:
             has_vnc[m] = 'Off'
@@ -463,11 +483,9 @@ def getListDict(username, state):
                 has_vnc[m] = "ParaVM"
     max_memory = validation.maxMemory(username, state)
     max_disk = validation.maxDisk(username)
-    checkpoint.checkpoint('Got max mem/disk')
     defaults = Defaults(max_memory=max_memory,
                         max_disk=max_disk,
                         owner=username)
-    checkpoint.checkpoint('Got defaults')
     def sortkey(machine):
         return (machine.owner != username, machine.owner, machine.name)
     machines = sorted(machines, key=sortkey)
@@ -597,7 +615,6 @@ def modifyDict(username, state, machine_id, fields):
 def infoDict(username, state, machine):
     """Get the variables used by info.tmpl."""
     status = controls.statusInfo(machine)
-    checkpoint.checkpoint('Getting status info')
     has_vnc = hasVnc(status)
     if status is None:
         main_status = dict(name=machine.name,
@@ -611,7 +628,6 @@ def infoDict(username, state, machine):
         uptime = datetime.timedelta(seconds=int(time.time()-start_time))
         cpu_time_float = float(main_status.get('cpu_time', 0))
         cputime = datetime.timedelta(seconds=int(cpu_time_float))
-    checkpoint.checkpoint('Status')
     display_fields = [('name', 'Name'),
                       ('description', 'Description'),
                       ('owner', 'Owner'),
@@ -657,11 +673,7 @@ def infoDict(username, state, machine):
             pass
             #fields.append((disp, None))
 
-    checkpoint.checkpoint('Got fields')
-
-
     max_mem = validation.maxMemory(machine.owner, state, machine, False)
-    checkpoint.checkpoint('Got mem')
     max_disk = validation.maxDisk(machine.owner, machine)
     defaults = Defaults()
     for name in 'machine_id name description administrator owner memory contact'.split():
@@ -669,7 +681,6 @@ def infoDict(username, state, machine):
             setattr(defaults, name, getattr(machine, name))
     defaults.type = machine.type.type_id
     defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
-    checkpoint.checkpoint('Got defaults')
     d = dict(user=username,
              on=status is not None,
              machine=machine,