5 # This wrapper implements the SFA Registry and Slice Interfaces on PLC.
6 # Depending on command line options, it starts some combination of a
7 # Registry, an Aggregate Manager, and a Slice Manager.
9 # There are several items that need to be done before starting the wrapper
12 # NOTE: Many configuration settings, including the PLC maintenance account
13 # credentials, URI of the PLCAPI, and PLC DB URI and admin credentials are initialized
14 # from your MyPLC configuration (/etc/planetlab/plc_config*). Please make sure this information
15 # is up to date and accurate.
17 # 1) Import the existing planetlab database, creating the
18 # appropriate SFA records. This is done by running the "sfa-import-plc.py" tool.
20 # 2) Create a "trusted_roots" directory and place the certificate of the root
21 # authority in that directory. Given the defaults in sfa-import-plc.py, this
22 # certificate would be named "planetlab.gid". For example,
24 # mkdir trusted_roots; cp authorities/planetlab.gid trusted_roots/
26 # TODO: Can all three servers use the same "registry" certificate?
29 # TCP ports for the three servers
33 ### xxx todo not in the config yet
38 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
39 from optparse import OptionParser
41 from sfa.util.sfalogging import logger
42 from sfa.trust.trustedroot import TrustedRootList
43 from sfa.trust.certificate import Keypair, Certificate
44 from sfa.trust.hierarchy import Hierarchy
45 from sfa.trust.gid import GID
46 from sfa.util.config import Config
47 from sfa.plc.api import SfaAPI
48 from sfa.server.registry import Registries
49 from sfa.server.aggregate import Aggregates
50 from sfa.util.xrn import get_authority, hrn_to_urn
51 from sfa.util.sfalogging import logger
53 # after http://www.erlenstar.demon.co.uk/unix/faq_2.html
55 """Daemonize the current process."""
56 if os.fork() != 0: os._exit(0)
58 if os.fork() != 0: os._exit(0)
60 devnull = os.open(os.devnull, os.O_RDWR)
62 # xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
63 crashlog = os.open('/var/log/httpd/sfa_access_log', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
67 def init_server_key(server_key_file, server_cert_file, config, hierarchy):
69 hrn = config.SFA_INTERFACE_HRN.lower()
70 # check if the server's private key exists. If it doesnt,
71 # get the right one from the authorities directory. If it cant be
72 # found in the authorities directory, generate a random one
73 if not os.path.exists(server_key_file):
74 hrn = config.SFA_INTERFACE_HRN.lower()
75 hrn_parts = hrn.split(".")
77 pkey_filename = hrn+".pkey"
79 # sub authority's have "." in their hrn. This must
80 # be converted to os.path separator
81 if len(hrn_parts) > 0:
82 rel_key_path = hrn.replace(".", os.sep)
83 pkey_filename= hrn_parts[-1]+".pkey"
85 key_file = os.sep.join([hierarchy.basedir, rel_key_path, pkey_filename])
86 if not os.path.exists(key_file):
87 # if it doesnt exist then this is probably a fresh interface
88 # with no records. Generate a random keypair for now
89 logger.debug("server's public key not found in %s" % key_file)
91 logger.debug("generating a random server key pair")
92 key = Keypair(create=True)
93 key.save_to_file(server_key_file)
94 init_server_cert(hrn, key, server_cert_file, self_signed=True)
97 # the pkey was found in the authorites directory. lets
98 # copy it to where the server key should be and generate
100 key = Keypair(filename=key_file)
101 key.save_to_file(server_key_file)
102 init_server_cert(hrn, key, server_cert_file)
104 # If private key exists and cert doesnt, recreate cert
105 if (os.path.exists(server_key_file)) and (not os.path.exists(server_cert_file)):
106 key = Keypair(filename=server_key_file)
107 init_server_cert(hrn, key, server_cert_file)
110 def init_server_cert(hrn, key, server_cert_file, self_signed=False):
112 Setup the certificate for this server. Attempt to use gid before
113 creating a self signed cert
116 init_self_signed_cert(hrn, key, server_cert_file)
120 logger.debug("generating server cert from gid: %s"% hrn)
121 hierarchy = Hierarchy()
122 auth_info = hierarchy.get_auth_info(hrn)
123 gid = GID(filename=auth_info.gid_filename)
124 gid.save_to_file(filename=server_cert_file)
126 # fall back to self signed cert
127 logger.debug("gid for %s not found" % hrn)
128 init_self_signed_cert(hrn, key, server_cert_file)
130 def init_self_signed_cert(hrn, key, server_cert_file):
131 logger.debug("generating self signed cert")
132 # generate self signed certificate
133 cert = Certificate(subject=hrn)
134 cert.set_issuer(key=key, subject=hrn)
137 cert.save_to_file(server_cert_file)
139 def init_server(options, config):
141 Execute the init method defined in the manager file
143 def init_manager(manager_module, manager_base):
144 try: manager = __import__(manager_module, fromlist=[manager_base])
145 except: manager = None
146 if manager and hasattr(manager, 'init_server'):
147 manager.init_server()
149 manager_base = 'sfa.managers'
151 mgr_type = config.SFA_REGISTRY_TYPE
152 manager_module = manager_base + ".registry_manager_%s" % mgr_type
153 init_manager(manager_module, manager_base)
155 mgr_type = config.SFA_AGGREGATE_TYPE
156 manager_module = manager_base + ".aggregate_manager_%s" % mgr_type
157 init_manager(manager_module, manager_base)
159 mgr_type = config.SFA_SM_TYPE
160 manager_module = manager_base + ".slice_manager_%s" % mgr_type
161 init_manager(manager_module, manager_base)
163 mgr_type = config.SFA_CM_TYPE
164 manager_module = manager_base + ".component_manager_%s" % mgr_type
165 init_manager(manager_module, manager_base)
167 def install_peer_certs(server_key_file, server_cert_file):
169 Attempt to install missing trusted gids and db records for
170 our federated interfaces
172 # Attempt to get any missing peer gids
173 # There should be a gid file in /etc/sfa/trusted_roots for every
174 # peer registry found in in the registries.xml config file. If there
175 # are any missing gids, request a new one from the peer registry.
176 api = SfaAPI(key_file = server_key_file, cert_file = server_cert_file)
177 registries = Registries(api)
178 aggregates = Aggregates(api)
179 interfaces = dict(registries.interfaces.items() + aggregates.interfaces.items())
180 gids_current = api.auth.trusted_cert_list
181 hrns_current = [gid.get_hrn() for gid in gids_current]
182 hrns_expected = interfaces.keys()
183 new_hrns = set(hrns_expected).difference(hrns_current)
184 #gids = self.get_peer_gids(new_hrns) + gids_current
189 trusted_certs_dir = api.config.get_trustedroots_dir()
190 for new_hrn in new_hrns:
191 if not new_hrn: continue
192 # the gid for this interface should already be installed
193 if new_hrn == api.config.SFA_INTERFACE_HRN: continue
195 # get gid from the registry
196 url = interfaces[new_hrn]['url']
197 interface = xmlrpcprotocol.get_server(url, server_key_file, server_cert_file)
198 # skip non sfa aggregates
199 server_version = api.get_cached_server_version(interface)
200 if 'sfa' not in server_version:
201 logger.info("get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
204 trusted_gids = interface.get_trusted_certs()
206 # the gid we want should be the first one in the list,
208 for trusted_gid in trusted_gids:
210 message = "interface: %s\t" % (api.interface)
211 message += "unable to install trusted gid for %s" % \
213 gid = GID(string=trusted_gids[0])
214 peer_gids.append(gid)
215 if gid.get_hrn() == new_hrn:
216 gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
217 gid.save_to_file(gid_filename, save_parents=True)
218 message = "installed trusted cert for %s" % new_hrn
220 api.logger.info(message)
222 message = "interface: %s\tunable to install trusted gid for %s" % \
223 (api.interface, new_hrn)
224 api.logger.log_exc(message)
225 # doesnt matter witch one
226 update_cert_records(peer_gids)
228 def update_cert_records(gids):
230 Make sure there is a record in the registry for the specified gids.
231 Removes old records from the db.
233 # import SfaTable here so this module can be loaded by ComponentAPI
234 from sfa.util.table import SfaTable
238 # get records that actually exist in the db
239 gid_urns = [gid.get_urn() for gid in gids]
240 hrns_expected = [gid.get_hrn() for gid in gids]
241 records_found = table.find({'hrn': hrns_expected, 'pointer': -1})
244 for record in records_found:
245 if record['hrn'] not in hrns_expected and \
246 record['hrn'] != self.api.config.SFA_INTERFACE_HRN:
249 # TODO: store urn in the db so we do this in 1 query
251 hrn, type = gid.get_hrn(), gid.get_type()
252 record = table.find({'hrn': hrn, 'type': type, 'pointer': -1})
255 'hrn': hrn, 'type': type, 'pointer': -1,
256 'authority': get_authority(hrn),
257 'gid': gid.save_to_string(save_parents=True),
259 record = SfaRecord(dict=record)
263 # Generate command line parser
264 parser = OptionParser(usage="sfa-server [options]")
265 parser.add_option("-r", "--registry", dest="registry", action="store_true",
266 help="run registry server", default=False)
267 parser.add_option("-s", "--slicemgr", dest="sm", action="store_true",
268 help="run slice manager", default=False)
269 parser.add_option("-a", "--aggregate", dest="am", action="store_true",
270 help="run aggregate manager", default=False)
271 parser.add_option("-c", "--component", dest="cm", action="store_true",
272 help="run component server", default=False)
273 parser.add_option("-t", "--trusted-certs", dest="trusted_certs", action="store_true",
274 help="refresh trusted certs", default=False)
275 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
276 help="verbose mode - cumulative")
277 parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
278 help="Run as daemon.", default=False)
279 (options, args) = parser.parse_args()
282 if config.SFA_API_DEBUG: pass
283 hierarchy = Hierarchy()
284 server_key_file = os.path.join(hierarchy.basedir, "server.key")
285 server_cert_file = os.path.join(hierarchy.basedir, "server.cert")
287 init_server_key(server_key_file, server_cert_file, config, hierarchy)
288 init_server(options, config)
290 if (options.daemon): daemon()
292 if options.trusted_certs:
293 install_peer_certs(server_key_file, server_cert_file)
295 # start registry server
296 if (options.registry):
297 from sfa.server.registry import Registry
298 r = Registry("", config.SFA_REGISTRY_PORT, server_key_file, server_cert_file)
302 from sfa.server.aggregate import Aggregate
303 a = Aggregate("", config.SFA_AGGREGATE_PORT, server_key_file, server_cert_file)
306 # start slice manager
308 from sfa.server.slicemgr import SliceMgr
309 s = SliceMgr("", config.SFA_SM_PORT, server_key_file, server_cert_file)
313 from sfa.server.component import Component
314 c = Component("", config.component_port, server_key_file, server_cert_file)
315 # c = Component("", config.SFA_COMPONENT_PORT, server_key_file, server_cert_file)
318 if __name__ == "__main__":
322 logger.log_exc_critical("SFA server is exiting")