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