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.certificate import Keypair, Certificate
43 from sfa.trust.hierarchy import Hierarchy
44 from sfa.trust.gid import GID
45 from sfa.util.config import Config
46 from sfa.plc.api import SfaAPI
47 from sfa.server.registry import Registries
48 from sfa.server.aggregate import Aggregates
49 from sfa.util.xrn import get_authority, hrn_to_urn
50 from sfa.util.sfalogging import logger
52 from sfa.managers.import_manager import import_manager
54 # after http://www.erlenstar.demon.co.uk/unix/faq_2.html
56 """Daemonize the current process."""
57 if os.fork() != 0: os._exit(0)
59 if os.fork() != 0: os._exit(0)
61 devnull = os.open(os.devnull, os.O_RDWR)
63 # xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
64 crashlog = os.open('/var/log/httpd/sfa_access_log', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
68 def init_server_key(server_key_file, server_cert_file, config, hierarchy):
70 hrn = config.SFA_INTERFACE_HRN.lower()
71 # check if the server's private key exists. If it doesnt,
72 # get the right one from the authorities directory. If it cant be
73 # found in the authorities directory, generate a random one
74 if not os.path.exists(server_key_file):
75 hrn = config.SFA_INTERFACE_HRN.lower()
76 hrn_parts = hrn.split(".")
78 pkey_filename = hrn+".pkey"
80 # sub authority's have "." in their hrn. This must
81 # be converted to os.path separator
82 if len(hrn_parts) > 0:
83 rel_key_path = hrn.replace(".", os.sep)
84 pkey_filename= hrn_parts[-1]+".pkey"
86 key_file = os.sep.join([hierarchy.basedir, rel_key_path, pkey_filename])
87 if not os.path.exists(key_file):
88 # if it doesnt exist then this is probably a fresh interface
89 # with no records. Generate a random keypair for now
90 logger.debug("server's public key not found in %s" % key_file)
92 logger.debug("generating a random server key pair")
93 key = Keypair(create=True)
94 key.save_to_file(server_key_file)
95 init_server_cert(hrn, key, server_cert_file, self_signed=True)
98 # the pkey was found in the authorites directory. lets
99 # copy it to where the server key should be and generate
101 key = Keypair(filename=key_file)
102 key.save_to_file(server_key_file)
103 init_server_cert(hrn, key, server_cert_file)
105 # If private key exists and cert doesnt, recreate cert
106 if (os.path.exists(server_key_file)) and (not os.path.exists(server_cert_file)):
107 key = Keypair(filename=server_key_file)
108 init_server_cert(hrn, key, server_cert_file)
111 def init_server_cert(hrn, key, server_cert_file, self_signed=False):
113 Setup the certificate for this server. Attempt to use gid before
114 creating a self signed cert
117 init_self_signed_cert(hrn, key, server_cert_file)
121 logger.debug("generating server cert from gid: %s"% hrn)
122 hierarchy = Hierarchy()
123 auth_info = hierarchy.get_auth_info(hrn)
124 gid = GID(filename=auth_info.gid_filename)
125 gid.save_to_file(filename=server_cert_file)
127 # fall back to self signed cert
128 logger.debug("gid for %s not found" % hrn)
129 init_self_signed_cert(hrn, key, server_cert_file)
131 def init_self_signed_cert(hrn, key, server_cert_file):
132 logger.debug("generating self signed cert")
133 # generate self signed certificate
134 cert = Certificate(subject=hrn)
135 cert.set_issuer(key=key, subject=hrn)
138 cert.save_to_file(server_cert_file)
140 def init_server(options, config):
142 Locate the manager based on config.*TYPE
143 Execute the init_server method (well in fact function, sigh) if defined in that module
144 In order to migrate to a more generic approach:
145 * search for <>_manager_<type>.py
146 * if not found, try <>_manager.py (and issue a warning if <type>!='pl')
149 manager=import_manager ("registry", config.SFA_REGISTRY_TYPE)
150 if manager and hasattr(manager, 'init_server'): manager.init_server()
152 manager=import_manager ("aggregate", config.SFA_AGGREGATE_TYPE)
153 if manager and hasattr(manager, 'init_server'): manager.init_server()
155 manager=import_manager ("slice", config.SFA_SM_TYPE)
156 if manager and hasattr(manager, 'init_server'): manager.init_server()
158 manager=import_manager ("component", config.SFA_CM_TYPE)
159 if manager and hasattr(manager, 'init_server'): manager.init_server()
162 def install_peer_certs(server_key_file, server_cert_file):
164 Attempt to install missing trusted gids and db records for
165 our federated interfaces
167 # Attempt to get any missing peer gids
168 # There should be a gid file in /etc/sfa/trusted_roots for every
169 # peer registry found in in the registries.xml config file. If there
170 # are any missing gids, request a new one from the peer registry.
171 api = SfaAPI(key_file = server_key_file, cert_file = server_cert_file)
172 registries = Registries()
173 aggregates = Aggregates()
174 interfaces = dict(registries.items() + aggregates.items())
175 gids_current = api.auth.trusted_cert_list
176 hrns_current = [gid.get_hrn() for gid in gids_current]
177 hrns_expected = set([hrn for hrn in interfaces])
178 new_hrns = set(hrns_expected).difference(hrns_current)
179 #gids = self.get_peer_gids(new_hrns) + gids_current
184 trusted_certs_dir = api.config.get_trustedroots_dir()
185 for new_hrn in new_hrns:
186 if not new_hrn: continue
187 # the gid for this interface should already be installed
188 if new_hrn == api.config.SFA_INTERFACE_HRN: continue
190 # get gid from the registry
191 url = interfaces[new_hrn].get_url()
192 interface = interfaces[new_hrn].get_server(server_key_file, server_cert_file, timeout=30)
193 # skip non sfa aggregates
194 server_version = api.get_cached_server_version(interface)
195 if 'sfa' not in server_version:
196 logger.info("get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
199 trusted_gids = interface.get_trusted_certs()
201 # the gid we want should be the first one in the list,
203 for trusted_gid in trusted_gids:
205 message = "interface: %s\t" % (api.interface)
206 message += "unable to install trusted gid for %s" % \
208 gid = GID(string=trusted_gids[0])
209 peer_gids.append(gid)
210 if gid.get_hrn() == new_hrn:
211 gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
212 gid.save_to_file(gid_filename, save_parents=True)
213 message = "installed trusted cert for %s" % new_hrn
215 api.logger.info(message)
217 message = "interface: %s\tunable to install trusted gid for %s" % \
218 (api.interface, new_hrn)
219 api.logger.log_exc(message)
220 # doesnt matter witch one
221 update_cert_records(peer_gids)
223 def update_cert_records(gids):
225 Make sure there is a record in the registry for the specified gids.
226 Removes old records from the db.
228 # import SfaTable here so this module can be loaded by ComponentAPI
229 from sfa.util.table import SfaTable
230 from sfa.util.record import SfaRecord
234 # get records that actually exist in the db
235 gid_urns = [gid.get_urn() for gid in gids]
236 hrns_expected = [gid.get_hrn() for gid in gids]
237 records_found = table.find({'hrn': hrns_expected, 'pointer': -1})
240 for record in records_found:
241 if record['hrn'] not in hrns_expected and \
242 record['hrn'] != self.api.config.SFA_INTERFACE_HRN:
245 # TODO: store urn in the db so we do this in 1 query
247 hrn, type = gid.get_hrn(), gid.get_type()
248 record = table.find({'hrn': hrn, 'type': type, 'pointer': -1})
251 'hrn': hrn, 'type': type, 'pointer': -1,
252 'authority': get_authority(hrn),
253 'gid': gid.save_to_string(save_parents=True),
255 record = SfaRecord(dict=record)
259 # Generate command line parser
260 parser = OptionParser(usage="sfa-server [options]")
261 parser.add_option("-r", "--registry", dest="registry", action="store_true",
262 help="run registry server", default=False)
263 parser.add_option("-s", "--slicemgr", dest="sm", action="store_true",
264 help="run slice manager", default=False)
265 parser.add_option("-a", "--aggregate", dest="am", action="store_true",
266 help="run aggregate manager", default=False)
267 parser.add_option("-c", "--component", dest="cm", action="store_true",
268 help="run component server", default=False)
269 parser.add_option("-t", "--trusted-certs", dest="trusted_certs", action="store_true",
270 help="refresh trusted certs", default=False)
271 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
272 help="verbose mode - cumulative")
273 parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
274 help="Run as daemon.", default=False)
275 (options, args) = parser.parse_args()
278 if config.SFA_API_DEBUG: pass
279 hierarchy = Hierarchy()
280 server_key_file = os.path.join(hierarchy.basedir, "server.key")
281 server_cert_file = os.path.join(hierarchy.basedir, "server.cert")
283 init_server_key(server_key_file, server_cert_file, config, hierarchy)
284 init_server(options, config)
286 if (options.daemon): daemon()
288 if options.trusted_certs:
289 install_peer_certs(server_key_file, server_cert_file)
291 # start registry server
292 if (options.registry):
293 from sfa.server.registry import Registry
294 r = Registry("", config.SFA_REGISTRY_PORT, server_key_file, server_cert_file)
298 from sfa.server.aggregate import Aggregate
299 a = Aggregate("", config.SFA_AGGREGATE_PORT, server_key_file, server_cert_file)
302 # start slice manager
304 from sfa.server.slicemgr import SliceMgr
305 s = SliceMgr("", config.SFA_SM_PORT, server_key_file, server_cert_file)
309 from sfa.server.component import Component
310 c = Component("", config.component_port, server_key_file, server_cert_file)
311 # c = Component("", config.SFA_COMPONENT_PORT, server_key_file, server_cert_file)
314 if __name__ == "__main__":
318 logger.log_exc_critical("SFA server is exiting")