#!/usr/bin/python
#
-### $Id$
-### $URL$
+# SFA PLC Wrapper
#
-# GENI PLC Wrapper
-#
-# This wrapper implements the Geni Registry and Slice Interfaces on PLC.
+# This wrapper implements the SFA Registry and Slice Interfaces on PLC.
# Depending on command line options, it starts some combination of a
# Registry, an Aggregate Manager, and a Slice Manager.
#
# is up to date and accurate.
#
# 1) Import the existing planetlab database, creating the
-# appropriate geni records. This is done by running the "sfa-import-plc.py" tool.
+# appropriate SFA records. This is done by running the "sfa-import-plc.py" tool.
#
# 2) Create a "trusted_roots" directory and place the certificate of the root
# authority in that directory. Given the defaults in sfa-import-plc.py, this
##
# TCP ports for the three servers
-registry_port=12345
-aggregate_port=12346
-slicemgr_port=12347
-
+#registry_port=12345
+#aggregate_port=12346
+#slicemgr_port=12347
+### xxx todo not in the config yet
+component_port=12346
import os, os.path
+import traceback
+import sys
+import sfa.util.xmlrpcprotocol as xmlrpcprotocol
from optparse import OptionParser
+from sfa.util.sfalogging import logger
from sfa.trust.trustedroot import TrustedRootList
from sfa.trust.certificate import Keypair, Certificate
-
-from sfa.server.registry import Registry
-from sfa.server.aggregate import Aggregate
-from sfa.server.slicemgr import SliceMgr
-
from sfa.trust.hierarchy import Hierarchy
-
+from sfa.trust.gid import GID
from sfa.util.config import Config
+from sfa.plc.api import SfaAPI
+from sfa.server.registry import Registries
+from sfa.server.aggregate import Aggregates
+from sfa.util.xrn import get_authority, hrn_to_urn
+from sfa.util.sfalogging import logger
# after http://www.erlenstar.demon.co.uk/unix/faq_2.html
def daemon():
devnull = os.open(os.devnull, os.O_RDWR)
os.dup2(devnull, 0)
# xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
- crashlog = os.open('/var/log/sfa.daemon', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
+ crashlog = os.open('/var/log/httpd/sfa_access_log', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
os.dup2(crashlog, 1)
os.dup2(crashlog, 2)
-def main():
- # xxx get rid of globals - name consistently CamelCase or under_score
- global AuthHierarchy
- global TrustedRoots
- global registry_port
- global aggregate_port
- global slicemgr_port
+def init_server_key(server_key_file, server_cert_file, config, hierarchy):
+
+ hrn = config.SFA_INTERFACE_HRN.lower()
+ # check if the server's private key exists. If it doesnt,
+ # get the right one from the authorities directory. If it cant be
+ # found in the authorities directory, generate a random one
+ if not os.path.exists(server_key_file):
+ hrn = config.SFA_INTERFACE_HRN.lower()
+ hrn_parts = hrn.split(".")
+ rel_key_path = hrn
+ pkey_filename = hrn+".pkey"
+
+ # sub authority's have "." in their hrn. This must
+ # be converted to os.path separator
+ if len(hrn_parts) > 0:
+ rel_key_path = hrn.replace(".", os.sep)
+ pkey_filename= hrn_parts[-1]+".pkey"
+
+ key_file = os.sep.join([hierarchy.basedir, rel_key_path, pkey_filename])
+ if not os.path.exists(key_file):
+ # if it doesnt exist then this is probably a fresh interface
+ # with no records. Generate a random keypair for now
+ logger.debug("server's public key not found in %s" % key_file)
+
+ logger.debug("generating a random server key pair")
+ key = Keypair(create=True)
+ key.save_to_file(server_key_file)
+ init_server_cert(hrn, key, server_cert_file, self_signed=True)
+
+ else:
+ # the pkey was found in the authorites directory. lets
+ # copy it to where the server key should be and generate
+ # the cert
+ key = Keypair(filename=key_file)
+ key.save_to_file(server_key_file)
+ init_server_cert(hrn, key, server_cert_file)
+
+ # If private key exists and cert doesnt, recreate cert
+ if (os.path.exists(server_key_file)) and (not os.path.exists(server_cert_file)):
+ key = Keypair(filename=server_key_file)
+ init_server_cert(hrn, key, server_cert_file)
+
+
+def init_server_cert(hrn, key, server_cert_file, self_signed=False):
+ """
+ Setup the certificate for this server. Attempt to use gid before
+ creating a self signed cert
+ """
+ if self_signed:
+ init_self_signed_cert(hrn, key, server_cert_file)
+ else:
+ try:
+ # look for gid file
+ logger.debug("generating server cert from gid: %s"% hrn)
+ hierarchy = Hierarchy()
+ auth_info = hierarchy.get_auth_info(hrn)
+ gid = GID(filename=auth_info.gid_filename)
+ gid.save_to_file(filename=server_cert_file)
+ except:
+ # fall back to self signed cert
+ logger.debug("gid for %s not found" % hrn)
+ init_self_signed_cert(hrn, key, server_cert_file)
+
+def init_self_signed_cert(hrn, key, server_cert_file):
+ logger.debug("generating self signed cert")
+ # generate self signed certificate
+ cert = Certificate(subject=hrn)
+ cert.set_issuer(key=key, subject=hrn)
+ cert.set_pubkey(key)
+ cert.sign()
+ cert.save_to_file(server_cert_file)
+
+def init_server(options, config):
+ """
+ Execute the init method defined in the manager file
+ """
+ def init_manager(manager_module, manager_base):
+ try: manager = __import__(manager_module, fromlist=[manager_base])
+ except: manager = None
+ if manager and hasattr(manager, 'init_server'):
+ manager.init_server()
+
+ manager_base = 'sfa.managers'
+ if options.registry:
+ mgr_type = config.SFA_REGISTRY_TYPE
+ manager_module = manager_base + ".registry_manager_%s" % mgr_type
+ init_manager(manager_module, manager_base)
+ if options.am:
+ mgr_type = config.SFA_AGGREGATE_TYPE
+ manager_module = manager_base + ".aggregate_manager_%s" % mgr_type
+ init_manager(manager_module, manager_base)
+ if options.sm:
+ mgr_type = config.SFA_SM_TYPE
+ manager_module = manager_base + ".slice_manager_%s" % mgr_type
+ init_manager(manager_module, manager_base)
+ if options.cm:
+ mgr_type = config.SFA_CM_TYPE
+ manager_module = manager_base + ".component_manager_%s" % mgr_type
+ init_manager(manager_module, manager_base)
+
+def install_peer_certs(server_key_file, server_cert_file):
+ """
+ Attempt to install missing trusted gids and db records for
+ our federated interfaces
+ """
+ # Attempt to get any missing peer gids
+ # There should be a gid file in /etc/sfa/trusted_roots for every
+ # peer registry found in in the registries.xml config file. If there
+ # are any missing gids, request a new one from the peer registry.
+ api = SfaAPI(key_file = server_key_file, cert_file = server_cert_file)
+ registries = Registries(api)
+ aggregates = Aggregates(api)
+ interfaces = dict(registries.interfaces.items() + aggregates.interfaces.items())
+ gids_current = api.auth.trusted_cert_list
+ hrns_current = [gid.get_hrn() for gid in gids_current]
+ hrns_expected = interfaces.keys()
+ new_hrns = set(hrns_expected).difference(hrns_current)
+ #gids = self.get_peer_gids(new_hrns) + gids_current
+ peer_gids = []
+ if not new_hrns:
+ return
+
+ trusted_certs_dir = api.config.get_trustedroots_dir()
+ for new_hrn in new_hrns:
+ if not new_hrn: continue
+ # the gid for this interface should already be installed
+ if new_hrn == api.config.SFA_INTERFACE_HRN: continue
+ try:
+ # get gid from the registry
+ url = interfaces[new_hrn]['url']
+ interface = xmlrpcprotocol.get_server(url, server_key_file, server_cert_file)
+ # skip non sfa aggregates
+ server_version = api.get_cached_server_version(interface)
+ if 'sfa' not in server_version:
+ logger.info("get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
+ continue
+
+ trusted_gids = interface.get_trusted_certs()
+ if trusted_gids:
+ # the gid we want should be the first one in the list,
+ # but lets make sure
+ for trusted_gid in trusted_gids:
+ # default message
+ message = "interface: %s\t" % (api.interface)
+ message += "unable to install trusted gid for %s" % \
+ (new_hrn)
+ gid = GID(string=trusted_gids[0])
+ peer_gids.append(gid)
+ if gid.get_hrn() == new_hrn:
+ gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
+ gid.save_to_file(gid_filename, save_parents=True)
+ message = "installed trusted cert for %s" % new_hrn
+ # log the message
+ api.logger.info(message)
+ except:
+ message = "interface: %s\tunable to install trusted gid for %s" % \
+ (api.interface, new_hrn)
+ api.logger.log_exc(message)
+ # doesnt matter witch one
+ update_cert_records(peer_gids)
+
+def update_cert_records(gids):
+ """
+ Make sure there is a record in the registry for the specified gids.
+ Removes old records from the db.
+ """
+ # import SfaTable here so this module can be loaded by ComponentAPI
+ from sfa.util.table import SfaTable
+ if not gids:
+ return
+ table = SfaTable()
+ # get records that actually exist in the db
+ gid_urns = [gid.get_urn() for gid in gids]
+ hrns_expected = [gid.get_hrn() for gid in gids]
+ records_found = table.find({'hrn': hrns_expected, 'pointer': -1})
+ # remove old records
+ for record in records_found:
+ if record['hrn'] not in hrns_expected and \
+ record['hrn'] != self.api.config.SFA_INTERFACE_HRN:
+ table.remove(record)
+
+ # TODO: store urn in the db so we do this in 1 query
+ for gid in gids:
+ hrn, type = gid.get_hrn(), gid.get_type()
+ record = table.find({'hrn': hrn, 'type': type, 'pointer': -1})
+ if not record:
+ record = {
+ 'hrn': hrn, 'type': type, 'pointer': -1,
+ 'authority': get_authority(hrn),
+ 'gid': gid.save_to_string(save_parents=True),
+ }
+ record = SfaRecord(dict=record)
+ table.insert(record)
+
+def main():
# Generate command line parser
parser = OptionParser(usage="sfa-server [options]")
parser.add_option("-r", "--registry", dest="registry", action="store_true",
help="run slice manager", default=False)
parser.add_option("-a", "--aggregate", dest="am", action="store_true",
help="run aggregate manager", default=False)
- parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
- help="verbose mode", default=False)
+ parser.add_option("-c", "--component", dest="cm", action="store_true",
+ help="run component server", default=False)
+ parser.add_option("-t", "--trusted-certs", dest="trusted_certs", action="store_true",
+ help="refresh trusted certs", default=False)
+ parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
+ help="verbose mode - cumulative")
parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
help="Run as daemon.", default=False)
(options, args) = parser.parse_args()
-
- hierarchy = Hierarchy()
- path = hierarchy.basedir
- key_file = os.path.join(path, "server.key")
- cert_file = os.path.join(path, "server.cert")
- # XX TODO: Subject should be the interfaces's hrn
- subject = "registry"
- if (options.daemon): daemon()
-
- if (os.path.exists(key_file)) and (not os.path.exists(cert_file)):
- # If private key exists and cert doesnt, recreate cert
- key = Keypair(filename=key_file)
- cert = Certificate(subject=subject)
- cert.set_issuer(key=key, subject=subject)
- cert.set_pubkey(key)
- cert.sign()
- cert.save_to_file(cert_file)
-
- elif (not os.path.exists(key_file)) or (not os.path.exists(cert_file)):
- # if no key is specified, then make one up
- key = Keypair(create=True)
- key.save_to_file(key_file)
- cert = Certificate(subject=subject)
- cert.set_issuer(key=key, subject=subject)
- cert.set_pubkey(key)
- cert.sign()
- cert.save_to_file(cert_file)
-
- AuthHierarchy = Hierarchy()
-
- TrustedRoots = TrustedRootList(Config().get_trustedroots_dir())
+ config = Config()
+ if config.SFA_API_DEBUG: pass
+ hierarchy = Hierarchy()
+ server_key_file = os.path.join(hierarchy.basedir, "server.key")
+ server_cert_file = os.path.join(hierarchy.basedir, "server.cert")
+ init_server_key(server_key_file, server_cert_file, config, hierarchy)
+ init_server(options, config)
+
+ if (options.daemon): daemon()
+
+ if options.trusted_certs:
+ install_peer_certs(server_key_file, server_cert_file)
+
# start registry server
if (options.registry):
- r = Registry("", registry_port, key_file, cert_file)
- #r.trusted_cert_list = TrustedRoots.get_list()
- #r.hierarchy = AuthHierarchy
+ from sfa.server.registry import Registry
+ r = Registry("", config.SFA_REGISTRY_PORT, server_key_file, server_cert_file)
r.start()
- # start aggregate manager
if (options.am):
- a = Aggregate("", aggregate_port, key_file, cert_file)
- #a.trusted_cert_list = TrustedRoots.get_list()
+ from sfa.server.aggregate import Aggregate
+ a = Aggregate("", config.SFA_AGGREGATE_PORT, server_key_file, server_cert_file)
a.start()
# start slice manager
if (options.sm):
- s = SliceMgr("", slicemgr_port, key_file, cert_file)
- #s.trusted_cert_list = TrustedRoots.get_list()
+ from sfa.server.slicemgr import SliceMgr
+ s = SliceMgr("", config.SFA_SM_PORT, server_key_file, server_cert_file)
s.start()
+ if (options.cm):
+ from sfa.server.component import Component
+ c = Component("", config.component_port, server_key_file, server_cert_file)
+# c = Component("", config.SFA_COMPONENT_PORT, server_key_file, server_cert_file)
+ c.start()
+
if __name__ == "__main__":
- main()
+ try:
+ main()
+ except:
+ logger.log_exc_critical("SFA server is exiting")