Commit f95e336d authored by Timothy Stack's avatar Timothy Stack

Change to the SSL version of the event scheduler.

  * db/libdb.py.in, xmlrpc/emulabserver.py.in: Only add the testbed
    library path to sys.path if it is not already there.

  * event/sched/GNUmakefile.in: Make the SSL version of the scheduler
    the default instead of the SSH version and statically link the
    executable.

  * event/sched/event-sched.c: Pass the default SSL port number (3069)
    to RPC_init.

  * event/sched/rpc.cc: Bring the SSL code up to date: read the cert
    from the user's home directory, make the connection persistent,
    and use TBROOT as the request path, so the development version of
    the XML-RPC library is used when appropriate.

  * xmlrpc/sslxmlrpc_server.py.in: Updated to let the user select from
    a set of allowed library paths where the 'emulabserver' module
    should be imported from.  Import the 'emulabserver' module after the
    fork so we always get the latest version of the module.  Twiddled
    the necessary bits to turn on persistent connection support.
parent 10cb8cc8
......@@ -10,10 +10,14 @@
#
import sys
sys.path.append("@prefix@/lib")
import os
import os, os.path
import pwd
TBPATH = os.path.join("@prefix@", "lib")
if TBPATH not in sys.path:
sys.path.append(TBPATH)
pass
import MySQLdb
from libtestbed import *
......
......@@ -11,7 +11,7 @@ SUBDIR = event/sched
include $(OBJDIR)/Makeconf
all: event-sched event-sched_rpc
all: event-sched event-sched_rrpc
include $(TESTBED_SRCDIR)/GNUmakerules
......@@ -50,7 +50,7 @@ event-sched_rpc: event-sched_rpc.o rpc.o queue.o event-sched.h \
event-sched_rrpc: event-sched_rpc.o rrpc.o queue.o event-sched.h \
../lib/libevent.a
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ event-sched_rpc.o \
$(CXX) $(CFLAGS) -static $(LDFLAGS) -o $@ event-sched_rpc.o \
rrpc.o queue.o $(ULXRLIBS) $(LIBS)
queue.o: event-sched.h
......@@ -62,12 +62,12 @@ rpc.o: rpc.cc rpc.h
rrpc.o: rpc.cc rpc.h
$(CXX) $(CXXFLAGS) -DSSLRPC $(ULXRINC) -c -o rrpc.o $<
install: event-sched_rpc
install: event-sched_rrpc
-mkdir -p $(INSTALL_DIR)/opsdir/sbin
$(INSTALL_PROGRAM) event-sched_rpc $(INSTALL_DIR)/opsdir/sbin/event-sched
$(INSTALL_PROGRAM) event-sched_rrpc $(INSTALL_DIR)/opsdir/sbin/event-sched
control-install: event-sched_rpc
$(INSTALL_PROGRAM) event-sched_rpc $(INSTALL_SBINDIR)/event-sched
control-install: event-sched_rrpc
$(INSTALL_PROGRAM) event-sched_rrpc $(INSTALL_SBINDIR)/event-sched
# not a client thing
client:
......
......@@ -154,7 +154,7 @@ main(int argc, char **argv)
if (!server)
server = "localhost";
#ifdef RPC
if (RPC_init(NULL, BOSSNODE, 0)) {
if (RPC_init(NULL, BOSSNODE, 3069)) {
fatal("could not connect to rpc server");
}
#endif
......
......@@ -50,15 +50,15 @@ main(int argc, char **argv)
int RPC_init(char *certpath, char *host, int port)
{
struct passwd *pwd;
int retval = -1;
pwd = getpwuid(getuid());
#ifdef SSHRPC
{
char identity_path[PATH_MAX];
struct passwd *pwd;
/* Construct the path to the identity and */
pwd = getpwuid(getuid());
snprintf(identity_path,
sizeof(identity_path),
"%s/.ssh/identity",
......@@ -115,13 +115,19 @@ int RPC_init(char *certpath, char *host, int port)
}
}
#else
/* XXX THIS IS OUT OF DATE */
{
ulxr::SSLConnection conn(false, host, port);
ulxr::HttpProtocol proto(&conn, conn.getHostName());
if (certpath == NULL)
certpath = "/usr/testbed/etc/client.pem";
conn.setCryptographyData("", certpath, certpath);
ulxr::SSLConnection *sslconn;
char buf[BUFSIZ];
rpc_data.conn = sslconn = new ulxr::SSLConnection(false, host, port);
rpc_data.proto = new ulxr::HttpProtocol(rpc_data.conn,
sslconn->getHostName());
rpc_data.proto->setPersistent(true);
if (certpath == NULL) {
snprintf(buf, sizeof(buf), "%s/.ssl/emulab.pem", pwd->pw_dir);
certpath = buf;
}
sslconn->setCryptographyData("", certpath, certpath);
}
#endif
return 0;
......@@ -150,12 +156,7 @@ RPC_invoke(char *pid, char *eid, char *method, emulab::EmulabResponse *er)
{
try
{
#ifdef SSHRPC
emulab::ServerProxy proxy(rpc_data.proto);
#else
/* XXX THIS IS OUT OF DATE */
emulab::ServerProxy proxy(rpc_data.proto, false, "/RPC2");
#endif
emulab::ServerProxy proxy(rpc_data.proto, false, TBROOT);
*er = proxy.invoke(method,
emulab::SPA_String, "proj", pid,
......
......@@ -22,15 +22,22 @@ import xmlrpclib
import signal
import types
import datetime
sys.path.append("@prefix@/lib")
from libdb import *
from libtestbed import SENDMAIL, TBOPS
from emulabclient import *
# Configure variables
TBDIR = "@prefix@"
BOSSNODE = "@BOSSNODE@"
BOSSEVENTPORT = "@BOSSEVENTPORT@"
OURDOMAIN = "@OURDOMAIN@"
USERNODE = "@USERNODE@"
TBPATH = os.path.join(TBDIR, "lib")
if TBPATH not in sys.path:
sys.path.append(TBPATH)
pass
from libdb import *
from libtestbed import SENDMAIL, TBOPS
from emulabclient import *
# Version
VERSION = 0.1
......
......@@ -6,21 +6,30 @@
#
import sys
import getopt
import os
import os, os.path
import traceback
import syslog
import string
import BaseHTTPServer
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
# Testbed specific stuff
sys.path.append("@prefix@/lib")
TBPATH = "@prefix@/lib"
if TBPATH not in sys.path:
sys.path.append(TBPATH)
pass
from libdb import *
from libtestbed import SENDMAIL, TBOPS
from emulabserver import *
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
from M2Crypto import SSL
from M2Crypto.SSL import SSLError
try:
from M2Crypto import SSL
from M2Crypto.SSL import SSLError
except ImportError, e:
sys.stderr.write("error: The py-m2crypto port is not installed\n")
sys.exit(1)
pass
# When debugging, runs in foreground printing to stdout instead of syslog
debug = 0
......@@ -43,9 +52,89 @@ ca_cert = "@prefix@/etc/emulab.pem"
DEFAULT_MODULE = "EmulabServer"
module = DEFAULT_MODULE
#
# "Standard" paths for the real and development versions of the software.
#
STD_PATH = "/usr/testbed"
STD_DEVEL_PATH = "/usr/testbed/devel"
#
# The set of paths that the user is allowed to specify in their request. The
# path specifies where the 'emulabserver' module will be loaded from. In
# reality, the path only has an effect on the first request in a persistent
# connection, any subsequent requests will reuse the same module.
#
ALLOWED_PATHS = [ STD_PATH, "@prefix@" ]
ALLOWED_PATHS.extend(map(lambda x: os.path.join(STD_DEVEL_PATH, x),
os.listdir(STD_DEVEL_PATH)))
# syslog facility
LOGFACIL = "@TBLOGFACIL@"
##
# Taken from the SimpleXMLRPCServer module in the python installation and
# modified to support persistent connections.
#
class MyXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Simple XML-RPC request handler class.
Handles all HTTP POST requests and attempts to decode them as
XML-RPC requests.
"""
##
# Change the default protocol so that persistent connections are the norm.
#
protocol_version = "HTTP/1.1"
##
# Handle a POST request from the user. This method was changed from the
# standard version to not close the
#
def do_POST(self):
"""Handles the HTTP POST request.
Attempts to interpret all HTTP POST requests as XML-RPC calls,
which are forwarded to the server's _dispatch method for handling.
"""
# Update PYTHONPATH with the user's requested path.
self.server.set_path(self.path)
try:
# get arguments
data = self.rfile.read(int(self.headers["content-length"]))
# In previous versions of SimpleXMLRPCServer, _dispatch
# could be overridden in this class, instead of in
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
# check to see if a subclass implements _dispatch and dispatch
# using that method if present.
response = self.server._marshaled_dispatch(
data, getattr(self, '_dispatch', None)
)
except: # This should only happen if the module is buggy
# internal error, report as HTTP server error
self.send_response(500)
self.end_headers()
self.wfile.flush()
else:
# got a valid XML RPC response
self.send_response(200)
self.send_header("Content-type", "text/xml")
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
self.wfile.flush()
pass
return
def log_request(self, code='-', size='-'):
"""Selectively log an accepted request."""
if self.server.logRequests:
BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
#
# A simple server based on the forking version SSLServer. We fork cause
# we want to change our uid/gid to that of the person on the other end.
......@@ -62,12 +151,17 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 16)
ctx.set_allow_unknown_ca(0)
#ctx.set_info_callback()
SimpleXMLRPCDispatcher.__init__(self)
SSL.SSLServer.__init__(self, (ADDR, PORT),
SimpleXMLRPCRequestHandler, ctx)
MyXMLRPCRequestHandler, ctx)
pass
##
# Log a message to stdout, if in debug mode, otherwise write to syslog.
#
# @param msg The message to log.
#
def logit(self, msg):
if debug:
print msg
......@@ -76,6 +170,36 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
syslog.syslog(syslog.LOG_INFO, msg);
pass
return
##
# Updates PYTHONPATH and imports the 'emulabserver' module on its first
# invocation. The specified path must be in the ALLOWED_PATHS list and
# readable by the user, otherwise the request will fail.
#
# @param path The path from the POST request, should not include "lib" on
# the end (e.g. "/usr/testbed")
#
def set_path(self, path):
if not self.emulabserver:
if path not in ALLOWED_PATHS:
self.logit("Disallowed path: %s" % path)
raise Exception("Path not allowed: %s" % path)
path = os.path.join(path, "lib")
if not os.access(path, os.X_OK):
self.logit("Path not accessible by user: %s" % path)
raise Exception("Permission denied: %s" % path)
print `path`
print `sys.path`
if path not in sys.path:
sys.path.append(path)
pass
from emulabserver import EmulabServer
self.emulabserver = EmulabServer(readonly=0)
pass
return
#
# There might be a better arrangement, but the problem is that we
......@@ -221,7 +345,10 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
# This must never return, hence os._exit()!
try:
self.fliptouser(request, client_address);
self.emulabserver = EmulabServer(readonly=0)
# Remove the old path since the user can request a different
# one.
sys.path.remove(TBPATH)
self.finish_request(request, client_address)
self.close_request(request)
self.logit("request finished");
......@@ -249,10 +376,10 @@ if len(sys.argv) > 1 and sys.argv[1] == "-d":
#
if not debug:
#
# Connect to syslog.
# Connect to syslog.
#
syslog.openlog("sslxmlrpc", syslog.LOG_PID,
eval("syslog.LOG_" + string.upper(LOGFACIL)))
getattr(syslog, "LOG_" + string.upper(LOGFACIL)))
syslog.syslog(syslog.LOG_INFO, "SSL XMLRPC server starting up");
#
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment