sfa-import-plc.py is not longer responsible for creating the top level authority...
[sfa.git] / sfa / server / sfa-start.py
1 #!/usr/bin/python
2 #
3 # PlanetLab SFA implementation
4 #
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.
8 #
9 # There are several items that need to be done before starting the servers.
10 #
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.
15 #
16 # 1) Import the existing planetlab database, creating the
17 #    appropriate SFA records. This is done by running the "sfa-import-plc.py" tool.
18 #
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,
22 #
23 #    mkdir trusted_roots; cp authorities/planetlab.gid trusted_roots/
24 #
25 # TODO: Can all three servers use the same "registry" certificate?
26 ##
27
28 # TCP ports for the three servers
29 #registry_port=12345
30 #aggregate_port=12346
31 #slicemgr_port=12347
32 ### xxx todo not in the config yet
33 component_port=12346
34 import os, os.path
35 import traceback
36 import sys
37 from optparse import OptionParser
38
39 from sfa.util.sfalogging import logger
40 from sfa.util.xrn import get_authority, hrn_to_urn
41 from sfa.util.config import Config
42 import sfa.client.xmlrpcprotocol as xmlrpcprotocol
43
44 from sfa.trust.certificate import Keypair, Certificate
45 from sfa.trust.hierarchy import Hierarchy
46 from sfa.trust.gid import GID
47
48 from sfa.server.sfaapi import SfaApi
49
50 from sfa.server.registry import Registries
51 from sfa.server.aggregate import Aggregates
52
53 # after http://www.erlenstar.demon.co.uk/unix/faq_2.html
54 def daemon():
55     """Daemonize the current process."""
56     if os.fork() != 0: os._exit(0)
57     os.setsid()
58     if os.fork() != 0: os._exit(0)
59     os.umask(0)
60     devnull = os.open(os.devnull, os.O_RDWR)
61     os.dup2(devnull, 0)
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)
64     os.dup2(crashlog, 1)
65     os.dup2(crashlog, 2)
66
67
68 def install_peer_certs(server_key_file, server_cert_file):
69     """
70     Attempt to install missing trusted gids and db records for 
71     our federated interfaces
72     """
73     # Attempt to get any missing peer gids
74     # There should be a gid file in /etc/sfa/trusted_roots for every
75     # peer registry found in in the registries.xml config file. If there
76     # are any missing gids, request a new one from the peer registry.
77     api = SfaApi(key_file = server_key_file, cert_file = server_cert_file)
78     registries = Registries()
79     aggregates = Aggregates()
80     interfaces = dict(registries.items() + aggregates.items())
81     gids_current = api.auth.trusted_cert_list
82     hrns_current = [gid.get_hrn() for gid in gids_current]
83     hrns_expected = set([hrn for hrn in interfaces])
84     new_hrns = set(hrns_expected).difference(hrns_current)
85     #gids = self.get_peer_gids(new_hrns) + gids_current
86     peer_gids = []
87     if not new_hrns:
88         return 
89
90     trusted_certs_dir = api.config.get_trustedroots_dir()
91     for new_hrn in new_hrns:
92         if not new_hrn: continue
93         # the gid for this interface should already be installed
94         if new_hrn == api.config.SFA_INTERFACE_HRN: continue
95         try:
96             # get gid from the registry
97             url = interfaces[new_hrn].get_url()
98             interface = interfaces[new_hrn].server_proxy(server_key_file, server_cert_file, timeout=30)
99             # skip non sfa aggregates
100             server_version = api.get_cached_server_version(interface)
101             if 'sfa' not in server_version:
102                 logger.info("get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
103                 continue
104       
105             trusted_gids = interface.get_trusted_certs()
106             if trusted_gids:
107                 # the gid we want should be the first one in the list,
108                 # but lets make sure
109                 for trusted_gid in trusted_gids:
110                     # default message
111                     message = "interface: %s\t" % (api.interface)
112                     message += "unable to install trusted gid for %s" % \
113                                (new_hrn)
114                     gid = GID(string=trusted_gids[0])
115                     peer_gids.append(gid)
116                     if gid.get_hrn() == new_hrn:
117                         gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
118                         gid.save_to_file(gid_filename, save_parents=True)
119                         message = "installed trusted cert for %s" % new_hrn
120                     # log the message
121                     api.logger.info(message)
122         except:
123             message = "interface: %s\tunable to install trusted gid for %s" % \
124                         (api.interface, new_hrn)
125             api.logger.log_exc(message)
126     # doesnt matter witch one
127     update_cert_records(peer_gids)
128
129 def update_cert_records(gids):
130     """
131     Make sure there is a record in the registry for the specified gids. 
132     Removes old records from the db.
133     """
134     # import SfaTable here so this module can be loaded by PlcComponentApi
135     from sfa.util.table import SfaTable
136     from sfa.util.record import SfaRecord
137     if not gids:
138         return
139     table = SfaTable()
140     # get records that actually exist in the db
141     gid_urns = [gid.get_urn() for gid in gids]
142     hrns_expected = [gid.get_hrn() for gid in gids]
143     records_found = table.find({'hrn': hrns_expected, 'pointer': -1}) 
144
145     # remove old records
146     for record in records_found:
147         if record['hrn'] not in hrns_expected and \
148             record['hrn'] != self.api.config.SFA_INTERFACE_HRN:
149             table.remove(record)
150
151     # TODO: store urn in the db so we do this in 1 query 
152     for gid in gids:
153         hrn, type = gid.get_hrn(), gid.get_type()
154         record = table.find({'hrn': hrn, 'type': type, 'pointer': -1})
155         if not record:
156             record = {
157                 'hrn': hrn, 'type': type, 'pointer': -1,
158                 'authority': get_authority(hrn),
159                 'gid': gid.save_to_string(save_parents=True),
160             }
161             record = SfaRecord(dict=record)
162             table.insert(record)
163         
164 def main():
165     # Generate command line parser
166     parser = OptionParser(usage="sfa-start.py [options]")
167     parser.add_option("-r", "--registry", dest="registry", action="store_true",
168          help="run registry server", default=False)
169     parser.add_option("-s", "--slicemgr", dest="sm", action="store_true",
170          help="run slice manager", default=False)
171     parser.add_option("-a", "--aggregate", dest="am", action="store_true",
172          help="run aggregate manager", default=False)
173     parser.add_option("-c", "--component", dest="cm", action="store_true",
174          help="run component server", default=False)
175     parser.add_option("-t", "--trusted-certs", dest="trusted_certs", action="store_true",
176          help="refresh trusted certs", default=False)
177     parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
178          help="verbose mode - cumulative")
179     parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
180          help="Run as daemon.", default=False)
181     (options, args) = parser.parse_args()
182     
183     config = Config()
184     if config.SFA_API_DEBUG: pass
185
186     # ge the server's key and cert
187     hierarchy = Hierarchy()
188     auth_info = hierarchy.get_interface_auth_info() 
189     server_key_file = auth_info.get_privkey_filename()
190     server_cert_file = auth_info.get_gid_filename()
191
192     if (options.daemon):  daemon()
193     
194     if options.trusted_certs:
195         install_peer_certs(server_key_file, server_cert_file)   
196     
197     # start registry server
198     if (options.registry):
199         from sfa.server.registry import Registry
200         r = Registry("", config.SFA_REGISTRY_PORT, server_key_file, server_cert_file)
201         r.start()
202
203     if (options.am):
204         from sfa.server.aggregate import Aggregate
205         a = Aggregate("", config.SFA_AGGREGATE_PORT, server_key_file, server_cert_file)
206         a.start()
207
208     # start slice manager
209     if (options.sm):
210         from sfa.server.slicemgr import SliceMgr
211         s = SliceMgr("", config.SFA_SM_PORT, server_key_file, server_cert_file)
212         s.start()
213
214     if (options.cm):
215         from sfa.server.component import Component
216         c = Component("", config.component_port, server_key_file, server_cert_file)
217 #        c = Component("", config.SFA_COMPONENT_PORT, server_key_file, server_cert_file)
218         c.start()
219
220 if __name__ == "__main__":
221     try:
222         main()
223     except:
224         logger.log_exc_critical("SFA server is exiting")