Revision 81010134 daemons/ganeti-noded

b/daemons/ganeti-noded
28 28
import sys
29 29
import resource
30 30
import traceback
31
import BaseHTTPServer
32
import simplejson
31 33

  
32 34
from optparse import OptionParser
33 35

  
......
40 42
from ganeti import ssconf
41 43
from ganeti import utils
42 44

  
43
from twisted.spread import pb
44
from twisted.internet import reactor
45
from twisted.cred import checkers, portal
46
from OpenSSL import SSL
47 45

  
48

  
49
class ServerContextFactory:
50
  """SSL context factory class that uses a given certificate.
51

  
52
  """
53
  @staticmethod
54
  def getContext():
55
    """Return a customized context.
56

  
57
    The context will be set to use our certificate.
58

  
59
    """
60
    ctx = SSL.Context(SSL.TLSv1_METHOD)
61
    ctx.use_certificate_file(constants.SSL_CERT_FILE)
62
    ctx.use_privatekey_file(constants.SSL_CERT_FILE)
63
    return ctx
64

  
65
class ServerObject(pb.Avatar):
46
class ServerObject(BaseHTTPServer.BaseHTTPRequestHandler):
66 47
  """The server implementation.
67 48

  
68 49
  This class holds all methods exposed over the RPC interface.
69 50

  
70 51
  """
71
  def __init__(self, name):
72
    self.name = name
73

  
74
  def perspectiveMessageReceived(self, broker, message, args, kw):
75
    """Custom message dispatching function.
76

  
77
    This function overrides the pb.Avatar function in order to provide
78
    a simple form of exception passing (as text only).
52
  def do_PUT(self):
53
    """Handle a post request.
79 54

  
80 55
    """
81
    args = broker.unserialize(args, self)
82
    kw = broker.unserialize(kw, self)
83
    method = getattr(self, "perspective_%s" % message)
84
    tb = None
85
    state = None
56
    path = self.path
57
    if path.startswith("/"):
58
      path = path[1:]
59
    mname = "perspective_%s" % path
60
    if not hasattr(self, mname):
61
      self.send_error(404)
62
      return False
63

  
64
    method = getattr(self, mname)
86 65
    try:
87
      state = method(*args, **kw)
88
    except:
89
      tb = traceback.format_exc()
66
      body_length = int(self.headers.get('Content-Length', '0'))
67
    except ValueError:
68
      self.send_error(400, 'No Content-Length header or invalid format')
69
      return False
90 70

  
91
    return broker.serialize((tb, state), self, method, args, kw)
71
    try:
72
      body = self.rfile.read(body_length)
73
    except socket.error, err:
74
      logger.Error("Socket error while reading: %s" % str(err))
75
      return
76
    try:
77
      params = simplejson.loads(body)
78
      result = method(params)
79
      payload = simplejson.dumps(result)
80
    except Exception, err:
81
      self.send_error(500, "Error: %s" % str(err))
82
      return False
83
    self.send_response(200)
84
    self.send_header('Content-Length', str(len(payload)))
85
    self.end_headers()
86
    self.wfile.write(payload)
87
    return True
88

  
89
  def log_message(self, format, *args):
90
    """Log a request to the log.
91

  
92
    This is the same as the parent, we just log somewhere else.
93

  
94
    """
95
    msg = ("%s - - [%s] %s\n" %
96
           (self.address_string(),
97
            self.log_date_time_string(),
98
            format % args))
99
    logger.Debug(msg)
92 100

  
93 101
  # the new block devices  --------------------------
94 102

  
......
487 495
    return utils.TestDelay(duration)
488 496

  
489 497

  
490
class MyRealm:
491
  """Simple realm that forwards all requests to a ServerObject.
492

  
493
  """
494
  __implements__ = portal.IRealm
495

  
496
  def requestAvatar(self, avatarId, mind, *interfaces):
497
    """Return an avatar based on our ServerObject class.
498

  
499
    """
500
    if pb.IPerspective not in interfaces:
501
      raise NotImplementedError
502
    return pb.IPerspective, ServerObject(avatarId), lambda:None
503

  
504

  
505 498
def ParseOptions():
506 499
  """Parse the command line options.
507 500

  
......
550 543
  logger.SetupLogging(twisted_workaround=True, debug=options.debug,
551 544
                      program="ganeti-noded")
552 545

  
553
  p = portal.Portal(MyRealm())
554
  p.registerChecker(
555
    checkers.InMemoryUsernamePasswordDatabaseDontUse(master_node=pwdata))
556
  reactor.listenSSL(port, pb.PBServerFactory(p), ServerContextFactory())
557
  reactor.run()
546
  httpd = BaseHTTPServer.HTTPServer(('', port), ServerObject)
547
  httpd.serve_forever()
558 548

  
559 549

  
560 550
def createDaemon():

Also available in: Unified diff