shebangs need to point at python2
[sfa.git] / sfa / server / sfa-start.py
1 #!/usr/bin/env python2
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.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 import os
29 import os.path
30 import traceback
31 import sys
32 from optparse import OptionParser
33
34 from sfa.util.sfalogging import init_logger, logger
35 from sfa.util.xrn import get_authority, hrn_to_urn
36 from sfa.util.config import Config
37
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 from sfa.client.return_value import ReturnValue
49
50
51 def install_peer_certs(server_key_file, server_cert_file):
52     """
53     Attempt to install missing trusted gids and db records for
54     our federated interfaces
55     """
56     # Attempt to get any missing peer gids
57     # There should be a gid file in /etc/sfa/trusted_roots for every
58     # peer registry found in in the registries.xml config file. If there
59     # are any missing gids, request a new one from the peer registry.
60     api = SfaApi(key_file=server_key_file, cert_file=server_cert_file)
61     registries = Registries()
62     aggregates = Aggregates()
63     interfaces = dict(registries.items() + aggregates.items())
64     gids_current = api.auth.trusted_cert_list
65     hrns_current = [gid.get_hrn() for gid in gids_current]
66     hrns_expected = set([hrn for hrn in interfaces])
67     new_hrns = set(hrns_expected).difference(hrns_current)
68     #gids = self.get_peer_gids(new_hrns) + gids_current
69     peer_gids = []
70     if not new_hrns:
71         return
72
73     trusted_certs_dir = api.config.get_trustedroots_dir()
74     for new_hrn in new_hrns:
75         if not new_hrn:
76             continue
77         # the gid for this interface should already be installed
78         if new_hrn == api.config.SFA_INTERFACE_HRN:
79             continue
80         try:
81             # get gid from the registry
82             url = interfaces[new_hrn].get_url()
83             interface = interfaces[new_hrn].server_proxy(
84                 server_key_file, server_cert_file, timeout=30)
85             # skip non sfa aggregates
86             server_version = api.get_cached_server_version(interface)
87             if 'sfa' not in server_version:
88                 logger.info(
89                     "get_trusted_certs: skipping non sfa aggregate: %s" % new_hrn)
90                 continue
91
92             trusted_gids = ReturnValue.get_value(interface.get_trusted_certs())
93             if trusted_gids:
94                 # the gid we want should be the first one in the list,
95                 # but lets make sure
96                 for trusted_gid in trusted_gids:
97                     # default message
98                     message = "interface: %s\t" % (api.interface)
99                     message += "unable to install trusted gid for %s" % \
100                                (new_hrn)
101                     gid = GID(string=trusted_gid)
102                     peer_gids.append(gid)
103                     if gid.get_hrn() == new_hrn:
104                         gid_filename = os.path.join(
105                             trusted_certs_dir, '%s.gid' % new_hrn)
106                         gid.save_to_file(gid_filename, save_parents=True)
107                         message = "installed trusted cert for %s" % new_hrn
108                     # log the message
109                     logger.info(message)
110         except Exception:
111             message = "interface: %s\tunable to install trusted gid for %s" % \
112                 (api.interface, new_hrn)
113             logger.log_exc(message)
114     # doesnt matter witch one
115     update_cert_records(peer_gids)
116
117
118 def update_cert_records(gids):
119     """
120     Make sure there is a record in the registry for the specified gids.
121     Removes old records from the db.
122     """
123     # import db stuff here here so this module can be loaded by PlcComponentApi
124     from sfa.storage.alchemy import global_dbsession
125     from sfa.storage.model import RegRecord
126     dbsession = global_dbsession
127     if not gids:
128         return
129     # get records that actually exist in the db
130     gid_urns = [gid.get_urn() for gid in gids]
131     hrns_expected = [gid.get_hrn() for gid in gids]
132     records_found = dbsession.query(RegRecord).\
133         filter_by(pointer=-1).filter(RegRecord.hrn.in_(hrns_expected)).all()
134
135     # remove old records
136     for record in records_found:
137         if record.hrn not in hrns_expected and \
138                 record.hrn != self.api.config.SFA_INTERFACE_HRN:
139             dbsession.delete(record)
140
141     # TODO: store urn in the db so we do this in 1 query
142     for gid in gids:
143         hrn, type = gid.get_hrn(), gid.get_type()
144         record = dbsession.query(RegRecord).filter_by(
145             hrn=hrn, type=type, pointer=-1).first()
146         if not record:
147             record = RegRecord(
148                 dict={'type': type,
149                       'hrn': hrn,
150                       'authority': get_authority(hrn),
151                       'gid': gid.save_to_string(save_parents=True),
152                       })
153             dbsession.add(record)
154     dbsession.commit()
155
156
157 def main():
158     # Generate command line parser
159     parser = OptionParser(usage="sfa-start.py [options]")
160     parser.add_option("-r", "--registry", dest="registry", action="store_true",
161                       help="run registry server", default=False)
162     parser.add_option("-a", "--aggregate", dest="am", action="store_true",
163                       help="run aggregate manager", default=False)
164     parser.add_option("-t", "--trusted-certs",
165                       dest="trusted_certs", action="store_true",
166                       help="refresh trusted certs", default=False)
167     (options, args) = parser.parse_args()
168
169     config = Config()
170     init_logger('server')
171     logger.setLevelFromOptVerbose(config.SFA_API_LOGLEVEL)
172
173     # ge the server's key and cert
174     hierarchy = Hierarchy()
175     auth_info = hierarchy.get_interface_auth_info()
176     server_key_file = auth_info.get_privkey_filename()
177     server_cert_file = auth_info.get_gid_filename()
178
179     # ensure interface cert is present in trusted roots dir
180     trusted_roots = TrustedRoots(config.get_trustedroots_dir())
181     trusted_roots.add_gid(GID(filename=server_cert_file))
182
183     if options.trusted_certs:
184         install_peer_certs(server_key_file, server_cert_file)
185
186     # start registry server
187     if (options.registry):
188         from sfa.server.registry import Registry
189         r = Registry("", config.SFA_REGISTRY_PORT,
190                      server_key_file, server_cert_file)
191         r.start()
192
193     if (options.am):
194         from sfa.server.aggregate import Aggregate
195         a = Aggregate("", config.SFA_AGGREGATE_PORT,
196                       server_key_file, server_cert_file)
197         a.start()
198
199 if __name__ == "__main__":
200     try:
201         main()
202     except Exception:
203         logger.log_exc("SFA server is exiting")
204         exit(1)