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