3 # PlanetLab SFA implementation
5 # This 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 servers.
11 # NOTE: Many configuration settings, including the PLC maintenance account
12 # credentials, URI of the PLCAPI, and PLC DB URI and admin credentials are initialized
13 # from your MyPLC configuration (/etc/planetlab/plc_config*). Please make sure this information
14 # is up to date and accurate.
16 # 1) Import the existing planetlab database, creating the
17 # appropriate SFA records. This is done by running the "sfa-import-plc.py" tool.
19 # 2) Create a "trusted_roots" directory and place the certificate of the root
20 # authority in that directory. Given the defaults in sfa-import-plc.py, this
21 # certificate would be named "planetlab.gid". For example,
23 # mkdir trusted_roots; cp authorities/planetlab.gid trusted_roots/
25 # TODO: Can all three servers use the same "registry" certificate?
28 # TCP ports for the three servers
32 ### xxx todo not in the config yet
37 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
38 from optparse import OptionParser
40 from sfa.util.sfalogging import logger
41 from sfa.trust.certificate import Keypair, Certificate
42 from sfa.trust.hierarchy import Hierarchy
43 from sfa.trust.gid import GID
44 from sfa.util.config import Config
45 from sfa.plc.api import SfaAPI
46 from sfa.server.registry import Registries
47 from sfa.server.aggregate import Aggregates
48 from sfa.util.xrn import get_authority, hrn_to_urn
49 from sfa.util.sfalogging import logger
51 from sfa.managers.import_manager import import_manager
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 Locate the manager based on config.*TYPE
142 Execute the init_server method (well in fact function, sigh) if defined in that module
143 In order to migrate to a more generic approach:
144 * search for <>_manager_<type>.py
145 * if not found, try <>_manager.py (and issue a warning if <type>!='pl')
148 manager=import_manager ("registry", config.SFA_REGISTRY_TYPE)
149 if manager and hasattr(manager, 'init_server'): manager.init_server()
151 manager=import_manager ("aggregate", config.SFA_AGGREGATE_TYPE)
152 if manager and hasattr(manager, 'init_server'): manager.init_server()
154 manager=import_manager ("slice", config.SFA_SM_TYPE)
155 if manager and hasattr(manager, 'init_server'): manager.init_server()
157 manager=import_manager ("component", config.SFA_CM_TYPE)
158 if manager and hasattr(manager, 'init_server'): manager.init_server()
161 def install_peer_certs(server_key_file, server_cert_file):
163 Attempt to install missing trusted gids and db records for
164 our federated interfaces
166 # Attempt to get any missing peer gids
167 # There should be a gid file in /etc/sfa/trusted_roots for every
168 # peer registry found in in the registries.xml config file. If there
169 # are any missing gids, request a new one from the peer registry.
170 api = SfaAPI(key_file = server_key_file, cert_file = server_cert_file)
171 registries = Registries()
172 aggregates = Aggregates()
173 interfaces = dict(registries.items() + aggregates.items())
174 gids_current = api.auth.trusted_cert_list
175 hrns_current = [gid.get_hrn() for gid in gids_current]
176 hrns_expected = set([hrn for hrn in interfaces])
177 new_hrns = set(hrns_expected).difference(hrns_current)
178 #gids = self.get_peer_gids(new_hrns) + gids_current
183 trusted_certs_dir = api.config.get_trustedroots_dir()
184 for new_hrn in new_hrns:
185 if not new_hrn: continue
186 # the gid for this interface should already be installed
187 if new_hrn == api.config.SFA_INTERFACE_HRN: continue
189 # get gid from the registry
190 url = interfaces[new_hrn].get_url()
191 interface = interfaces[new_hrn].get_server(server_key_file, server_cert_file, timeout=30)
192 # skip non sfa aggregates
193 server_version = api.get_cached_server_version(interface)
194 if 'sfa' not in server_version:
195 logger.info("get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
198 trusted_gids = interface.get_trusted_certs()
200 # the gid we want should be the first one in the list,
202 for trusted_gid in trusted_gids:
204 message = "interface: %s\t" % (api.interface)
205 message += "unable to install trusted gid for %s" % \
207 gid = GID(string=trusted_gids[0])
208 peer_gids.append(gid)
209 if gid.get_hrn() == new_hrn:
210 gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
211 gid.save_to_file(gid_filename, save_parents=True)
212 message = "installed trusted cert for %s" % new_hrn
214 api.logger.info(message)
216 message = "interface: %s\tunable to install trusted gid for %s" % \
217 (api.interface, new_hrn)
218 api.logger.log_exc(message)
219 # doesnt matter witch one
220 update_cert_records(peer_gids)
222 def update_cert_records(gids):
224 Make sure there is a record in the registry for the specified gids.
225 Removes old records from the db.
227 # import SfaTable here so this module can be loaded by ComponentAPI
228 from sfa.util.table import SfaTable
229 from sfa.util.record import SfaRecord
233 # get records that actually exist in the db
234 gid_urns = [gid.get_urn() for gid in gids]
235 hrns_expected = [gid.get_hrn() for gid in gids]
236 records_found = table.find({'hrn': hrns_expected, 'pointer': -1})
239 for record in records_found:
240 if record['hrn'] not in hrns_expected and \
241 record['hrn'] != self.api.config.SFA_INTERFACE_HRN:
244 # TODO: store urn in the db so we do this in 1 query
246 hrn, type = gid.get_hrn(), gid.get_type()
247 record = table.find({'hrn': hrn, 'type': type, 'pointer': -1})
250 'hrn': hrn, 'type': type, 'pointer': -1,
251 'authority': get_authority(hrn),
252 'gid': gid.save_to_string(save_parents=True),
254 record = SfaRecord(dict=record)
258 # Generate command line parser
259 parser = OptionParser(usage="sfa-server [options]")
260 parser.add_option("-r", "--registry", dest="registry", action="store_true",
261 help="run registry server", default=False)
262 parser.add_option("-s", "--slicemgr", dest="sm", action="store_true",
263 help="run slice manager", default=False)
264 parser.add_option("-a", "--aggregate", dest="am", action="store_true",
265 help="run aggregate manager", default=False)
266 parser.add_option("-c", "--component", dest="cm", action="store_true",
267 help="run component server", default=False)
268 parser.add_option("-t", "--trusted-certs", dest="trusted_certs", action="store_true",
269 help="refresh trusted certs", default=False)
270 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
271 help="verbose mode - cumulative")
272 parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
273 help="Run as daemon.", default=False)
274 (options, args) = parser.parse_args()
277 if config.SFA_API_DEBUG: pass
278 hierarchy = Hierarchy()
279 server_key_file = os.path.join(hierarchy.basedir, "server.key")
280 server_cert_file = os.path.join(hierarchy.basedir, "server.cert")
282 init_server_key(server_key_file, server_cert_file, config, hierarchy)
283 init_server(options, config)
285 if (options.daemon): daemon()
287 if options.trusted_certs:
288 install_peer_certs(server_key_file, server_cert_file)
290 # start registry server
291 if (options.registry):
292 from sfa.server.registry import Registry
293 r = Registry("", config.SFA_REGISTRY_PORT, server_key_file, server_cert_file)
297 from sfa.server.aggregate import Aggregate
298 a = Aggregate("", config.SFA_AGGREGATE_PORT, server_key_file, server_cert_file)
301 # start slice manager
303 from sfa.server.slicemgr import SliceMgr
304 s = SliceMgr("", config.SFA_SM_PORT, server_key_file, server_cert_file)
308 from sfa.server.component import Component
309 c = Component("", config.component_port, server_key_file, server_cert_file)
310 # c = Component("", config.SFA_COMPONENT_PORT, server_key_file, server_cert_file)
313 if __name__ == "__main__":
317 logger.log_exc_critical("SFA server is exiting")