starcluster.webtools

Package starcluster :: Module webtools |
[hide private]
[frames] | no frames]

# Source Code for Module starcluster.webtools

      1  #!/usr/bin/env python
      2  import os
      3  import sys
      4  import shlex
      5  import optparse
      6  import mimetypes
      7  import posixpath
      8  import webbrowser
      9  import subprocess
     10  import BaseHTTPServer as httpserv
     11
     12  from starcluster import templates
     13  from starcluster import exception
     14  from starcluster.logger import log
     15
     16  ERROR_MSG = """\
     17  <head>
     18  <title>DOH!</title>
     19  </head>
     20  <body>
     21  <pre>
     22   _  _    ___  _  _
     23  | || |  / _ \| || |
     24  | || |_| | | | || |_
     25  |__   _| |_| |__   _|
     26     |_|  \___/   |_|
     27
     28  </pre>
     29  <h1>Error response</h1>
     30  <p>Error code %(code)d.
     31  <p>Message: %(message)s.
     32  <p>Error code explanation: %(code)s = %(explain)s.
     33  </body>
     34  """
     35
     36
     37 -class StoppableHttpServer(httpserv.HTTPServer):
     38      """http server that reacts to self.stop flag"""
     39
     40 -    def serve_forever(self):
     41          """Handle one request at a time until stopped."""
     42          self.stop = False
     43          while not self.stop:
     44              self.handle_request()
     45
     46
     47 -class BaseHandler(httpserv.BaseHTTPRequestHandler):
     48      error_message_format = ERROR_MSG
     49
     50 -    def do_GET(self):
     51          print 'GET not supported'
     52
     53 -    def do_POST(self):
     54          print 'POSTing not supported'
     55
     56 -    def do_shutdown(self):
     57          log.info("Shutting down server...")
     58          self.send_response(200)
     59          self.send_header('Content-type', 'text/html')
     60          self.end_headers()
     61          self.server.stop = True
     62
     63
     64 -class DocrootHandler(BaseHandler):
     65
     66 -    def do_GET(self):
     67          try:
     68              docroot = globals()['DOCUMENTROOT']
     69              fname = posixpath.join(docroot, self.path[1:])
     70              #remove query args. query args are ignored in static server
     71              fname = fname.split('?')[0]
     72              if fname.endswith('/') or os.path.isdir(fname):
     73                  fname = posixpath.join(fname, 'index.html')
     74              f = open(fname)  # self.path has /test.html
     75              content_type = mimetypes.guess_type(fname)[0]
     76              self.send_response(200)
     77              self.send_header('Content-type', content_type)
     78              self.end_headers()
     79              while True:
     80                  data = f.read(2097152)
     81                  if not data:
     82                      break
     83                  self.wfile.write(data)
     84              #self.wfile.write(f.read())
     85              f.close()
     86              return
     87          except IOError:
     88              self.send_error(404, 'File Not Found: %s' % self.path)
     89
     90
     91 -class TemplateHandler(DocrootHandler):
     92      """
     93      Simple GET handler that loads and renders files/templates within a package
     94      under the starcluster.templates package. You can set the _root_template_pkg
     95      attribute on this class before passing to BaseHTTPServer to specify a
     96      starcluster.templates subpackage to render templates from. Defaults to
     97      rendering starcluster.templates (ie '/')
     98      """
     99      _root_template_pkg = '/'
    100      _tmpl_context = {}
    101      _bin_exts = ('.ico', '.gif', '.jpg', '.png')
    102
    103 -    def do_GET(self):
    104          relpath = self.path[1:].split('?')[0]
    105          if relpath == "shutdown":
    106              self.do_shutdown()
    107              return
    108          fullpath = posixpath.join(self._root_template_pkg, relpath)
    109          try:
    110              if relpath.endswith(self._bin_exts):
    111                  data = templates.get_resource(fullpath).read()
    112              else:
    113                  tmpl = templates.get_template(fullpath)
    114                  data = tmpl.render(**self._tmpl_context)
    115              content_type = mimetypes.guess_type(os.path.basename(relpath))[0]
    116              self.send_response(200)
    117              self.send_header('Content-type', content_type)
    118              self.end_headers()
    119              self.wfile.write(data)
    120          except IOError, templates.TemplateNotFound:
    121              self.send_error(404, 'File Not Found: %s' % self.path)
    122              return
    123
    124
    125 -def get_template_server(root_template_pkg='/', interface="localhost",
    126                          port=None, context={}):
    127      TemplateHandler._root_template_pkg = root_template_pkg
    128      TemplateHandler._tmpl_context = context
    129      server = get_webserver(interface=interface, port=port,
    130                             handler=TemplateHandler)
    131      return server
    132
    133
    134 -def get_webserver(interface="localhost", port=None, handler=DocrootHandler):
    135      if port is None:
    136          port = 0
    137      server = StoppableHttpServer((interface, port), handler)
    138      return server
    139
    140
    141 -class BackgroundBrowser(webbrowser.GenericBrowser):
    142      """Class for all browsers which are to be started in the background."""
    143 -    def open(self, url, new=0, autoraise=1):
    144          cmdline = [self.name] + [arg.replace("%s", url)
    145                                   for arg in self.args]
    146          try:
    147              if sys.platform[:3] == 'win':
    148                  p = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
    149              else:
    150                  setsid = getattr(os, 'setsid', None)
    151                  if not setsid:
    152                      setsid = getattr(os, 'setpgrp', None)
    153                  p = subprocess.Popen(cmdline, close_fds=True,
    154                                       preexec_fn=setsid, stdout=subprocess.PIPE)
    155              return (p.poll() is None)
    156          except OSError:
    157              return False
    158
    159
    160 -def _is_exe(fpath):
    161      return os.path.exists(fpath) and os.access(fpath, os.X_OK)
    162
    163
    164 -def _which(program):
    165      fpath, fname = os.path.split(program)
    166      if fpath:
    167          if _is_exe(program):
    168              return program
    169      else:
    170          for path in os.environ["PATH"].split(os.pathsep):
    171              exe_file = os.path.join(path, program)
    172              if _is_exe(exe_file):
    173                  return exe_file
    174
    175
    176 -def open_browser(url, browser_cmd=None):
    177      if browser_cmd:
    178          cmd = shlex.split(browser_cmd)
    179          arg0 = cmd[0]
    180          if not _which(arg0):
    181              raise exception.BaseException("browser %s does not exist" % arg0)
    182          if "%s" not in browser_cmd:
    183              cmd.append("%s")
    184          browser = BackgroundBrowser(cmd)
    185      else:
    186          # use 'default' browser from webbrowser module
    187          browser = webbrowser.get()
    188      browser_name = getattr(browser, 'name', None)
    189      if not browser_name:
    190          browser_name = getattr(browser, '_name', 'UNKNOWN')
    191      log.info("Browsing %s using '%s'..." % (url, browser_name))
    192      return browser.open(url)
    193
    194
    195 -def main(path, interface="localhost", port=8080):
    196      try:
    197          docroot = os.path.realpath(path)
    198          globals()['DOCUMENTROOT'] = docroot
    199          server = get_webserver(interface=interface, port=port,
    200                                 handler=DocrootHandler)
    201          log.info('Starting httpserver...')
    202          log.info('Document_root = %s' % docroot)
    203          server.serve_forever()
    204      except KeyboardInterrupt:
    205          print '^C received, shutting down server'
    206          server.socket.close()
    207
    208
    209  if __name__ == '__main__':
    210      parser = optparse.OptionParser()
    211      parser.add_option("-i", "--interface", dest="interface", action="store",
    212                        default="localhost")
    213      parser.add_option("-p", "--port", dest="port", action="store", type="int",
    214                        default=8080)
    215      opts, args = parser.parse_args()
    216      if len(args) != 1:
    217          parser.error('usage:  webserver.py <document_root>')
    218      path = args[0]
    219      main(path, **opts.__dict__)
    220