0fed06553757c1bf407cb4636548d4c5146b5054
[sfa.git] / sfa / plc / sfa-import-plc.py
1 #!/usr/bin/python
2 #
3 ##
4 # Import PLC records into the SFA database. It is indended that this tool be
5 # run once to create SFA records that reflect the current state of the
6 # planetlab database.
7 #
8 # The import tool assumes that the existing PLC hierarchy should all be part
9 # of "planetlab.us" (see the root_auth and level1_auth variables below).
10 #
11 # Public keys are extracted from the users' SSH keys automatically and used to
12 # create GIDs. This is relatively experimental as a custom tool had to be
13 # written to perform conversion from SSH to OpenSSL format. It only supports
14 # RSA keys at this time, not DSA keys.
15 ##
16
17 import getopt
18 import sys
19 import tempfile
20
21 from sfa.util.record import *
22 from sfa.util.table import SfaTable
23 from sfa.util.namespace import get_leaf, get_authority, hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_pl_slicename
24 from sfa.util.config import Config
25 from sfa.trust.certificate import convert_public_key, Keypair
26 from sfa.trust.trustedroot import *
27 from sfa.trust.hierarchy import *
28 from sfa.plc.api import *
29 from sfa.trust.gid import create_uuid
30 from sfa.plc.sfaImport import sfaImport
31
32 def process_options():
33
34    (options, args) = getopt.getopt(sys.argv[1:], '', [])
35    for opt in options:
36        name = opt[0]
37        val = opt[1]
38
39
40 def load_keys(filename):
41     keys = {}
42     tmp_dict = {}
43     try:
44         execfile(filename, tmp_dict)
45         if 'keys' in tmp_dict:
46             keys = tmp_dict['keys']
47         return keys
48     except:
49         return keys
50
51 def save_keys(filename, keys):
52     f = open(filename, 'w')
53     f.write("keys = %s" % str(keys))
54     f.close()
55
56 def main():
57
58     process_options()
59     config = Config()
60     if not config.SFA_REGISTRY_ENABLED:
61         sys.exit(0)
62     root_auth = config.SFA_REGISTRY_ROOT_AUTH
63     interface_hrn = config.SFA_INTERFACE_HRN
64     keys_filename = config.config_path + os.sep + 'person_keys.py' 
65     sfaImporter = sfaImport()
66     if config.SFA_API_DEBUG: sfaImporter.logger.setLevelDebug()
67     shell = sfaImporter.shell
68     plc_auth = sfaImporter.plc_auth 
69     table = SfaTable()
70
71     if not table.exists():
72        table.create()
73
74     # create root authority 
75     sfaImporter.create_top_level_auth_records(root_auth)
76     if not root_auth == interface_hrn:
77         sfaImporter.create_top_level_auth_records(interface_hrn)
78
79     sfaImporter.logger.info("Import: adding " + interface_hrn + " to trusted list")
80     authority = sfaImporter.AuthHierarchy.get_auth_info(interface_hrn)
81     sfaImporter.TrustedRoots.add_gid(authority.get_gid_object())
82
83     if ".vini" in interface_hrn and interface_hrn.endswith('vini'):
84         # create a fake internet2 site first
85         i2site = {'name': 'Internet2', 'abbreviated_name': 'I2',
86                     'login_base': 'internet2', 'site_id': -1}
87         sfaImporter.import_site(interface_hrn, i2site)
88    
89     # create dict of all existing sfa records
90     existing_records = {}
91     existing_hrns = []
92     key_ids = []
93     person_keys = {} 
94     results = table.find()
95     for result in results:
96         existing_records[(result['hrn'], result['type'])] = result
97         existing_hrns.append(result['hrn']) 
98             
99     # Get all plc sites
100     sites = shell.GetSites(plc_auth, {'peer_id': None})
101     sites_dict = {}
102     for site in sites:
103         sites_dict[site['login_base']] = site 
104     
105     # Get all plc users
106     persons = shell.GetPersons(plc_auth, {'peer_id': None, 'enabled': True}, ['person_id', 'email', 'key_ids', 'site_ids'])
107     persons_dict = {}
108     for person in persons:
109         persons_dict[person['person_id']] = person
110         key_ids.extend(person['key_ids'])
111
112     # Get all public keys
113     keys = shell.GetKeys(plc_auth, {'peer_id': None, 'key_id': key_ids})
114     keys_dict = {}
115     for key in keys:
116         keys_dict[key['key_id']] = key['key']
117
118     # create a dict of person keys keyed on key_id 
119     old_person_keys = load_keys(keys_filename)
120     for person in persons:
121         pubkeys = []
122         for key_id in person['key_ids']:
123             pubkeys.append(keys_dict[key_id])
124         person_keys[person['person_id']] = pubkeys
125
126     # Get all plc nodes  
127     nodes = shell.GetNodes(plc_auth, {'peer_id': None}, ['node_id', 'hostname', 'site_id'])
128     nodes_dict = {}
129     for node in nodes:
130         nodes_dict[node['node_id']] = node
131
132     # Get all plc slices
133     slices = shell.GetSlices(plc_auth, {'peer_id': None}, ['slice_id', 'name'])
134     slices_dict = {}
135     for slice in slices:
136         slices_dict[slice['slice_id']] = slice
137     # start importing 
138     for site in sites:
139         site_hrn = interface_hrn + "." + site['login_base']
140         sfa_logger().info("Importing site: %s" % site_hrn)
141
142         # import if hrn is not in list of existing hrns or if the hrn exists
143         # but its not a site record
144         if site_hrn not in existing_hrns or \
145            (site_hrn, 'authority') not in existing_records:
146             site_hrn = sfaImporter.import_site(interface_hrn, site)
147              
148         # import node records
149         for node_id in site['node_ids']:
150             if node_id not in nodes_dict:
151                 continue 
152             node = nodes_dict[node_id]
153             hrn =  hostname_to_hrn(interface_hrn, site['login_base'], node['hostname'])
154             if hrn not in existing_hrns or \
155                (hrn, 'node') not in existing_records:
156                 sfaImporter.import_node(site_hrn, node)
157
158         # import slices
159         for slice_id in site['slice_ids']:
160             if slice_id not in slices_dict:
161                 continue 
162             slice = slices_dict[slice_id]
163             hrn = slicename_to_hrn(interface_hrn, slice['name'])
164             if hrn not in existing_hrns or \
165                (hrn, 'slice') not in existing_records:
166                 sfaImporter.import_slice(site_hrn, slice)      
167
168         # import persons
169         for person_id in site['person_ids']:
170             if person_id not in persons_dict:
171                 continue 
172             person = persons_dict[person_id]
173             hrn = email_to_hrn(site_hrn, person['email'])
174             old_keys = []
175             new_keys = []
176             if person_id in old_person_keys:
177                 old_keys = old_person_keys[person_id]
178             if person_id in person_keys:
179                 new_keys = person_keys[person_id]
180             update_record = False
181             for key in new_keys:
182                 if key not in old_keys:
183                     update_record = True 
184
185             if hrn not in existing_hrns or \
186                (hrn, 'user') not in existing_records or update_record:
187                 sfaImporter.import_person(site_hrn, person)
188
189     # remove stale records    
190     for (record_hrn, type) in existing_records.keys():
191         record = existing_records[(record_hrn, type)]
192         # if this is the interface name dont do anything
193         if record_hrn == interface_hrn or \
194            record_hrn == root_auth or \
195            record['peer_authority']:
196             continue
197         # dont delete vini's internet2 placeholdder record
198         # normally this would be deleted becuase it does not have a plc record 
199         if ".vini" in interface_hrn and interface_hrn.endswith('vini') and \
200            record_hrn.endswith("internet2"):     
201             continue
202
203         found = False
204         
205         if type == 'authority':    
206             for site in sites:
207                 site_hrn = interface_hrn + "." + site['login_base']
208                 if site_hrn == record_hrn and site['site_id'] == record['pointer']:
209                     found = True
210                     break
211
212         elif type == 'user':
213             login_base = get_leaf(get_authority(record_hrn))
214             username = get_leaf(record_hrn)
215             if login_base in sites_dict:
216                 site = sites_dict[login_base]
217                 for person in persons:
218                     tmp_username = person['email'].split("@")[0]
219                     alt_username = person['email'].split("@")[0].replace(".", "_")
220                     if username in [tmp_username, alt_username] and \
221                        site['site_id'] in person['site_ids'] and \
222                        person['person_id'] == record['pointer']:
223                         found = True
224                         break
225         
226         elif type == 'slice':
227             slicename = hrn_to_pl_slicename(record_hrn)
228             for slice in slices:
229                 if slicename == slice['name'] and \
230                    slice['slice_id'] == record['pointer']:
231                     found = True
232                     break    
233  
234         elif type == 'node':
235             login_base = get_leaf(get_authority(record_hrn))
236             nodename = get_leaf(record_hrn)
237             if login_base in sites_dict:
238                 site = sites_dict[login_base]
239                 for node in nodes:
240                     tmp_nodename = node['hostname'].split(".")[0]
241                     if tmp_nodename == nodename and \
242                        node['site_id'] == site['site_id'] and \
243                        node['node_id'] == record['pointer']:
244                         found = True
245                         break  
246         else:
247             continue 
248         
249         if not found:
250             record_object = existing_records[(record_hrn, type)]
251             sfaImporter.delete_record(record_hrn, type) 
252                                    
253     # save pub keys
254     sfaImporter.logger.info('Import: saving current pub keys')
255     save_keys(keys_filename, person_keys)                
256         
257 if __name__ == "__main__":
258     main()