def run(): return [["pass", tangelo.abspath("/blah/yay.html")], ["fail", tangelo.abspath("blah/yay.html")], ["fail", tangelo.abspath("/../blah/yay.html")], ["pass", tangelo.abspath("/~roni/blah")], ["fail", tangelo.abspath("/~roni/..")], ["fail", tangelo.abspath("~roni/blah")]]
def run(path=""): if len(path) == 0: return {"error": "missing required argument 'path'"} path = tangelo.abspath(path) if path is None: return {"error": "illegal web path"} try: with open(path) as f: spec = json.loads(f.read()) except (OSError, IOError): return {"status": "could not open file", "result": {}} except ValueError as e: return {"error": "could not parse JSON - %s" % (e.message)} return {"status": "OK", "result": spec}
def run(path=""): if len(path) == 0: return {"error": "missing required argument 'path'"} if path[0] not in ["/", "~"]: return {"error": "path must refer to an absolute web path"} path = tangelo.abspath(path) try: with open(path) as f: spec = json.loads(f.read()) except (OSError, IOError): return {"status": "could not open file", "result": {}} except ValueError as e: return {"error": "could not parse JSON - %s" % (e.message)} return {"status": "OK", "result": spec}
def vtkweb(self, *pargs, **kwargs): # TODO(choudhury): Implement a PUT method that expands the pool of # usable port numbers. # Be sure there was a vtkpython executable specified via the # environment, and a value provided for self.here. if self.vtkpython is None: return json.dumps({ "status": "failed", "reason": "no vtkpython executable was specified at Tangelo startup" }) if self.here is None: return json.dumps({ "status": "failed", "reason": "no 'here' argument provided to Tangelo object constructor" }) # Get keyword arguments. progargs = kwargs.get("progargs", "") timeout = kwargs.get("timeout", 0) # Convert the positional args to a list. pargs = list(pargs) # Dispatch a RESTful action. method = cherrypy.request.method if method == "GET": # If there is no key argument, send back a list of all the keys. if len(pargs) == 0: response = self.vtkweb_processes.keys() else: # Extract the key argument. key = pargs[0] # Check for the key in the process table. if key not in self.vtkweb_processes: return json.dumps({"status": "failed", "reason": "Requested key not in process table"}) # Retrieve the entry. rec = self.vtkweb_processes[key] response = { "status": "complete", "process": "running", "port": rec["port"], "stdout": rec["stdout"].readlines(), "stderr": rec["stderr"].readlines() } returncode = rec["process"].poll() if returncode is not None: # Since the process has ended, delete the process object. del self.vtkweb_processes[key] # Fill out the report response. response["process"] = "terminated" response["returncode"] = returncode # Make a report to the user. return json.dumps(response) elif method == "POST": if len(pargs) == 0: return json.dumps({"status": "incomplete", "reason": "missing path to vtkweb script"}) # Form the web path from the pargs components progpath = os.path.sep.join(pargs) # Verify that all required arguments are present. if len(pargs) == 0: return json.dumps({"status": "incomplete", "reason": "Missing program URL"}) # Check the user arguments. userargs = progargs.split() if "--port" in userargs: return json.dumps({"status": "incomplete", "reason": "You may not specify --port in this interface"}) # Verify that the program path is legal. if not tangelo.legal_path(progpath)[0]: return json.dumps({"status": "incomplete", "reason": "Illegal program URL"}) # Obtain a filesystem path to the requested program. progfile = tangelo.abspath(progpath) # Obtain an available port. port = tangelo.util.get_free_port() # Generate a unique key. key = tangelo.util.generate_key(self.vtkweb_processes.keys()) def launch_failure(msg): # On launch failure, report the failure to the user. return json.dumps({"status": "failed", "reason": msg}) # Launch the requested process. try: cmdline = [self.vtkpython, self.here + "/bin/vtkweb-launcher.py", progfile, "--port", str(port)] + userargs tangelo.log("starting a vtkweb process: %s" % (" ".join(cmdline))) process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: return launch_failure(e.strerror) except IOError as e: return launch_failure(e.strerror) # Capture the new process's stdout and stderr streams in # non-blocking readers. stdout = tangelo.util.NonBlockingReader(process.stdout) stderr = tangelo.util.NonBlockingReader(process.stderr) # Read from stdout to look for the signal that the process has # started properly. class FactoryStarted: pass class Failed: pass class Timeout: pass signal = "Starting factory" timeout = 10 sleeptime = 0.5 wait = 0 saved_lines = [] try: while True: lines = stdout.readlines() saved_lines += lines for line in lines: if line == "": # This indicates that stdout has closed without # starting the process. raise Failed() elif signal in line: # This means that the server has started. raise FactoryStarted() # If neither failure nor success occurred in the last block of # lines from stdout, either time out, or try again after a short # delay. if wait >= timeout: raise Timeout() wait += sleeptime time.sleep(sleeptime) except Timeout: return json.dumps({ "status": "failed", "reason": "process startup timed out" }) except Failed: return json.dumps({ "status": "failed", "reason": "process did not start up properly", "stdout": saved_lines, "stderr": stderr.readlines()}) except FactoryStarted: stdout.pushlines(saved_lines) # Create a websocket handler path dedicated to this process. host = cherrypy.server.socket_host if host == "0.0.0.0": host = "localhost" wshandler = tangelo.websocket.WebSocketRelay(host, port, key) cherrypy.tree.mount(tangelo.websocket.WebSocketHandler(), "/%s" % (key), config={"/ws": { "tools.websocket.on": True, "tools.websocket.handler_cls": wshandler, "tools.websocket.protocols": ["wamp"] } }) # Log the new process in the process table, including non-blocking # stdout and stderr readers. self.vtkweb_processes[key] = { "port": port, "process": process, "stdout": stdout, "stderr": stderr } # Form the websocket URL from the hostname/port used in the request, # and the newly generated key. url = "ws://%s/%s/ws" % (cherrypy.request.base.split("//")[1], key) return json.dumps({"status": "complete", "key": key, "url": url}) elif method == "DELETE": # TODO(choudhury): shut down a vtkweb process by key after a given # timeout. # Make sure there's a key. if len(pargs) == 0: return json.dumps({"status": "incomplete", "reason": "'key' argument is REQUIRED"}) # Extract the key. key = pargs[0] tangelo.log("shutting down %s" % (key)) # Check for the key in the process table. if key not in self.vtkweb_processes: tangelo.log("key not found") return json.dumps({"status": "failed", "reason": "no such key in process table"}) # Terminate the process. tangelo.log("terminating process") proc = self.vtkweb_processes[key] proc["process"].terminate() proc["process"].wait() tangelo.log("terminated") # Remove the process entry from the table. del self.vtkweb_processes[key] return json.dumps({"status": "complete"}) else: raise cherrypy.HTTPError(405, "Method not allowed")