else
+$(RSYNC) ./sfa/ $(SSHURL)/usr/lib\*/python2.\*/site-packages/sfa/
+$(RSYNC) ./tests/ $(SSHURL)/root/tests-sfa
- +$(RSYNC) $(BINS) $(SSHURL)/usr/bin
- +$(RSYNC) ./sfa/init.d/sfa $(SSHURL)/etc/init.d
+ +$(RSYNC) $(BINS) $(SSHURL)/usr/bin/
+ +$(RSYNC) ./sfa/init.d/sfa $(SSHURL)/etc/init.d/
+ +$(RSYNC) ./config/default_config.xml $(SSHURL)/etc/sfa/
$(SSHCOMMAND) exec service sfa restart
endif
<description>Basic system variables.</description>
<variablelist>
+ <variable id="generic_flavour" type="string">
+ <name>Generic Flavour</name>
+ <value>pl</value>
+ <description>This string refers to a class located in sfa.generic that describes
+ which specific implementation needs to be used for api, manager and driver objects.
+ PlanetLab users do not need to change this setting.
+ </description>
+ </variable>
+
<variable id="interface_hrn" type="string">
<name>Human readable name</name>
<value>plc</value>
it look like the user is the one performing the operation. Doing this requires a
valid key pair and credential for the user. This option defines the path where
key pairs and credentials are generated and stored.
- This functionality is used by the SFA web gui
+ This functionality is used by the SFA web GUI.
</description>
</variable>
+
</variablelist>
</category>
package_dirs = [
'sfa',
- 'sfa/client',
- 'sfa/methods',
- 'sfa/plc',
- 'sfa/server',
'sfa/trust',
'sfa/util',
+ 'sfa/client',
+ 'sfa/server',
+ 'sfa/methods',
+ 'sfa/generic',
'sfa/managers',
'sfa/managers/vini',
+ 'sfa/plc',
'sfa/rspecs',
'sfa/rspecs/elements',
'sfa/rspecs/elements/versions',
--- /dev/null
+from sfa.util.sfalogging import logger
+from sfa.util.config import Config
+import traceback
+
+# a bundle is the combination of
+# (*) an api that reacts on the incoming requests to trigger the API methods
+# (*) a manager that implements the function of the service,
+# either aggregate, registry, or slicemgr
+# (*) a driver that controls the underlying testbed
+#
+#
+# The Generic class is a utility that uses the configuration to figure out
+# which combination of these pieces need to be put together
+# from config.
+# this extra indirection is needed to adapt to the current naming scheme
+# where we have 'pl' and 'plc' and components and the like, that does not
+# yet follow a sensible scheme
+
+# needs refinements to cache more efficiently, esp. wrt the config
+
+class Generic:
+
+ def __init__ (self, config):
+ self.config=config
+
+ # proof of concept
+ # example flavour='pl' -> sfa.generic.pl.pl()
+ @staticmethod
+ def the_flavour (flavour=None, config=None):
+ if config is None: config=Config()
+ if flavour is None: flavour=config.SFA_GENERIC_FLAVOUR
+ flavour = flavour.lower()
+ #mixed = flavour.capitalize()
+ module_path="sfa.generic.%s"%flavour
+ classname="%s"%flavour
+ logger.info("Generic.the_flavour with flavour=%s"%flavour)
+ try:
+ module = __import__ (module_path, globals(), locals(), [classname])
+ return getattr(module, classname)(config)
+ except:
+ logger.log_exc("Cannot locate generic instance with flavour=%s"%flavour)
+
+
+ # how to build an API object
+ # default is to use api_class but can be redefined
+ def make_api (self, *args, **kwds):
+ return self.api_class()(*args, **kwds)
--- /dev/null
+from sfa.generic import Generic
+import sfa.plc.plcsfaapi
+
+class pl (Generic):
+
+ def api_class (self):
+ return sfa.plc.plcsfaapi.PlcSfaApi
+
+
--- /dev/null
+from sfa.generic.pl import pl
+import sfa.plc.plccomponentapi
+
+class plcm (pl):
+
+ def api_class (self):
+ return sfa.plc.plccomponentapi.PlcComponentApi
+
import time
import sys
-from sfa.server.componentserver import ComponentServer
+from sfa.server.sfaserver import SfaServer
# GeniLight client support is optional
try:
##
# Component is a SfaServer that serves component operations.
-class Component(ComponentServer):
+# set SFA_GENERIC_FLAVOUR=plcm to get a PlcComponentApi instance in the request handler
+class Component(SfaServer):
##
# Create a new registry object.
#
# @param cert_file certificate filename containing public key (could be a GID file)
def __init__(self, ip, port, key_file, cert_file):
- ComponentServer.__init__(self, ip, port, key_file, cert_file)
+ SfaServer.__init__(self, ip, port, key_file, cert_file)
self.server.interface = 'component'
+++ /dev/null
-##
-# This module implements a general-purpose server layer for sfa.
-# The same basic server should be usable on the registry, component, or
-# other interfaces.
-#
-# TODO: investigate ways to combine this with existing PLC server?
-##
-
-import threading
-import socket
-import SimpleXMLRPCServer
-
-from sfa.util.sfalogging import logger
-from sfa.trust.certificate import Keypair, Certificate
-from sfa.plc.api import PlcComponentApi
-from sfa.server.threadedserver import ThreadedServer
-
-
-##
-# taken from the web (XXX find reference). Implents HTTPS xmlrpc request handler
-
-class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """Secure XML-RPC request handler class.
-
- It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
- """
- def setup(self):
- self.connection = self.request
- self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
- self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
-
- def do_POST(self):
- """Handles the HTTPS POST request.
-
- It was copied out from SimpleXMLRPCServer.py and modified to shutdown the socket cleanly.
- """
- try:
- peer_cert = Certificate()
- peer_cert.load_from_pyopenssl_x509(self.connection.get_peer_certificate())
- self.api = PlcComponentApi(peer_cert = peer_cert,
- interface = self.server.interface,
- key_file = self.server.key_file,
- cert_file = self.server.cert_file)
- # get arguments
- request = 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(request, getattr(self, '_dispatch', None))
- # XX TODO: Need to get the real remote address
- remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
- self.api.remote_addr = remote_addr
- #remote_addr = (self.rfile.connection.remote_ip, remote_port)
- #self.api.remote_addr = remote_addr
- response = self.api.handle(remote_addr, request)
-
-
- except Exception, fault:
- raise
- # This should only happen if the module is buggy
- # internal error, report as HTTP server error
- self.send_response(500)
- self.end_headers()
- logger.log_exc("componentserver.SecureXMLRpcRequestHandler.do_POST")
- 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)
-
- # shut down the connection
- self.wfile.flush()
- self.connection.shutdown() # Modified here!
-
-##
-# Implements an HTTPS XML-RPC server. Generally it is expected that SFA
-# functions will take a credential string, which is passed to
-# decode_authentication. Decode_authentication() will verify the validity of
-# the credential, and verify that the user is using the key that matches the
-# GID supplied in the credential.
-
-class ComponentServer(threading.Thread):
-
- ##
- # Create a new SfaServer object.
- #
- # @param ip the ip address to listen on
- # @param port the port to listen on
- # @param key_file private key filename of registry
- # @param cert_file certificate filename containing public key
- # (could be a GID file)
-
- def __init__(self, ip, port, key_file, cert_file, api=None):
- threading.Thread.__init__(self)
- self.key = Keypair(filename = key_file)
- self.cert = Certificate(filename = cert_file)
- self.server = ThreadedServer((ip, port), SecureXMLRpcRequestHandler, key_file, cert_file)
- self.trusted_cert_list = None
- self.register_functions()
-
-
- ##
- # Register functions that will be served by the XMLRPC server. This
- # function should be overrided by each descendant class.
-
- def register_functions(self):
- self.server.register_function(self.noop)
-
- ##
- # Sample no-op server function. The no-op function decodes the credential
- # that was passed to it.
-
- def noop(self, cred, anything):
- return anything
-
- ##
- # Execute the server, serving requests forever.
-
- def run(self):
- self.server.serve_forever()
-
-
+import os.path
+import datetime
+
from sfa.util.faults import SfaAPIError
from sfa.util.config import Config
from sfa.util.cache import Cache
from sfa.trust.auth import Auth
from sfa.trust.certificate import Keypair, Certificate
+from sfa.trust.credential import Credential
# this is wrong all right, but temporary
from sfa.managers.managerwrapper import ManagerWrapper, import_manager
augmented with the local cryptographic material and hrn
It also has the notion of neighbour sfa services
as defined in /etc/sfa/{aggregates,registries}.xml
+ Finally it contains a cache instance
It has no a priori knowledge of the underlying testbed
"""
return
# Load configuration
self.config = Config(config)
+ self.credential = None
self.auth = Auth(peer_cert)
self.interface = interface
self.hrn = self.config.SFA_INTERFACE_HRN
self.cache = cache
if self.cache is None:
self.cache = Cache()
- self.credential = None
# load registries
from sfa.server.registry import Registries
type = 'authority'
path = self.config.SFA_DATA_DIR
filename = ".".join([self.interface, self.hrn, type, "cred"])
- cred_filename = path + os.sep + filename
+ cred_filename = os.path.join(path,filename)
cred = None
if os.path.isfile(cred_filename):
cred = Credential(filename = cred_filename)
# see if this file exists
# XX This is really the aggregate's credential. Using this is easier than getting
- # the registry's credential from iteslf (ssl errors).
- ma_cred_filename = self.config.SFA_DATA_DIR + os.sep + self.interface + self.hrn + ".ma.cred"
+ # the registry's credential from iteslf (ssl errors).
+ filename = self.interface + self.hrn + ".ma.cred"
+ ma_cred_path = os.path.join(self.config.SFA_DATA_DIR,filename)
try:
- self.credential = Credential(filename = ma_cred_filename)
+ self.credential = Credential(filename = ma_cred_path)
except IOError:
self.credential = self.getCredentialFromRegistry()
from sfa.util.cache import Cache
from sfa.trust.certificate import Certificate
from sfa.trust.trustedroots import TrustedRoots
-#can we get rid of that ?
-from sfa.plc.api import PlcSfaApi
+# don't hard code an api class anymore here
+from sfa.generic import Generic
##
# Verification callback for pyOpenSSL. We do our own checking of keys because
try:
peer_cert = Certificate()
peer_cert.load_from_pyopenssl_x509(self.connection.get_peer_certificate())
- self.api = PlcSfaApi(peer_cert = peer_cert,
- interface = self.server.interface,
- key_file = self.server.key_file,
- cert_file = self.server.cert_file,
- cache = self.cache)
+ generic=Generic.the_flavour()
+ self.api = generic.make_api (peer_cert = peer_cert,
+ interface = self.server.interface,
+ key_file = self.server.key_file,
+ cert_file = self.server.cert_file,
+ cache = self.cache)
+ #logger.info("SecureXMLRpcRequestHandler.do_POST:")
+ #logger.info("interface=%s"%self.server.interface)
+ #logger.info("key_file=%s"%self.server.key_file)
+ #logger.info("api=%s"%self.api)
+ #logger.info("server=%s"%self.server)
+ #logger.info("handler=%s"%self)
# get arguments
request = self.rfile.read(int(self.headers["content-length"]))
remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
##
# Taken from the web (XXX find reference). Implements an HTTPS xmlrpc server
class SecureXMLRPCServer(BaseHTTPServer.HTTPServer,SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
+
def __init__(self, server_address, HandlerClass, key_file, cert_file, logRequests=True):
"""Secure XML-RPC server.