undo last commit, some files are not ready
[sfa.git] / sfa / plc / sfaImport.py
1 #
2 # The import tool assumes that the existing PLC hierarchy should all be part
3 # of "planetlab.us" (see the root_auth and level1_auth variables below).
4 #
5 # Public keys are extracted from the users' SSH keys automatically and used to
6 # create GIDs. This is relatively experimental as a custom tool had to be
7 # written to perform conversion from SSH to OpenSSL format. It only supports
8 # RSA keys at this time, not DSA keys.
9 ##
10
11 import getopt
12 import sys
13 import tempfile
14
15 from sfa.util.record import *
16 from sfa.util.genitable import GeniTable
17 from sfa.util.misc import *
18 from sfa.util.config import Config
19 from sfa.util.report import trace, error
20
21 from sfa.trust.certificate import convert_public_key, Keypair
22 from sfa.trust.trustedroot import *
23 from sfa.trust.hierarchy import *
24 from sfa.trust.gid import create_uuid
25
26
27 def un_unicode(str):
28    if isinstance(str, unicode):
29        return str.encode("ascii", "ignore")
30    else:
31        return str
32
33 def cleanup_string(str):
34     # pgsql has a fit with strings that have high ascii in them, so filter it
35     # out when generating the hrns.
36     tmp = ""
37     for c in str:
38         if ord(c) < 128:
39             tmp = tmp + c
40     str = tmp
41
42     str = un_unicode(str)
43     str = str.replace(" ", "_")
44     str = str.replace(".", "_")
45     str = str.replace("(", "_")
46     str = str.replace("'", "_")
47     str = str.replace(")", "_")
48     str = str.replace('"', "_")
49     return str
50
51 def person_to_hrn(parent_hrn, person):
52     # the old way - Lastname_Firstname
53     #personname = person['last_name'] + "_" + person['first_name']
54
55     # the new way - use email address up to the "@"
56     personname = person['email'].split("@")[0]
57
58     personname = cleanup_string(personname)
59
60     hrn = parent_hrn + "." + personname
61     return hrn
62
63
64 class sfaImport:
65
66     def __init__(self):
67         self.AuthHierarchy = Hierarchy()
68         self.TrustedRoots = TrustedRootList()
69
70         self.config = Config()
71         self.plc_auth = self.config.get_plc_auth()
72         self.root_auth = self.config.SFA_REGISTRY_ROOT_AUTH
73         self.level1_auth = self.config.SFA_REGISTRY_LEVEL1_AUTH
74         if not self.level1_auth or self.level1_auth in ['']:
75             self.level1_auth = None
76         
77         # connect to planetlab
78         self.shell = None
79         if "Url" in self.plc_auth:
80             from sfa.plc.remoteshell import RemoteShell
81             self.shell = RemoteShell()
82         else:
83             import PLC.Shell
84             self.shell = PLC.Shell.Shell(globals = globals())        
85
86     def get_auth_table(self, auth_name):
87         AuthHierarchy = self.AuthHierarchy
88         auth_info = AuthHierarchy.get_auth_info(auth_name)
89
90         table = GeniTable(hrn=auth_name, cninfo=auth_info.get_dbinfo())
91
92         # if the table doesn't exist, then it means we haven't put any records
93         # into this authority yet.
94
95         if not table.exists():
96             trace("Import: creating table for authority " + auth_name)
97             table.create()
98
99         return table
100
101
102     def create_top_level_auth_records(self, hrn):
103         AuthHierarchy = self.AuthHierarchy
104         
105         # if root doesnt exist, create it
106         if not AuthHierarchy.auth_exists(hrn):
107             AuthHierarchy.create_auth(hrn)
108         
109         # get the parent hrn
110         parent_hrn = get_authority(hrn)
111         if not parent_hrn:
112             parent_hrn = hrn
113
114         # get the auth info of the newly created root auth (parent)
115         # or level1_auth if it exists
116         auth_info = AuthHierarchy.get_auth_info(parent_hrn)
117         if self.level1_auth:
118             auth_info = AuthHierarchy.get_auth_info(hrn)
119         table = self.get_auth_table(parent_hrn)
120
121         auth_record = table.resolve("authority", hrn)
122         if not auth_record:
123             auth_record = GeniRecord(hrn=hrn, gid=auth_info.get_gid_object(), type="authority", pointer=-1)
124             trace("  inserting authority record for " + hrn)
125             table.insert(auth_record)
126
127
128     def import_person(self, parent_hrn, person):
129         AuthHierarchy = self.AuthHierarchy
130         hrn = person_to_hrn(parent_hrn, person)
131
132         # ASN.1 will have problems with hrn's longer than 64 characters
133         if len(hrn) > 64:
134             hrn = hrn[:64]
135
136         trace("Import: importing person " + hrn)
137
138         table = self.get_auth_table(parent_hrn)
139
140         key_ids = []
141         if 'key_ids' in person and person['key_ids']:
142             key_ids = person["key_ids"]
143
144             # get the user's private key from the SSH keys they have uploaded
145             # to planetlab
146             keys = self.shell.GetKeys(self.plc_auth, key_ids)
147             key = keys[0]['key']
148             pkey = convert_public_key(key)
149         else:
150             # the user has no keys
151             trace("   person " + hrn + " does not have a PL public key")
152
153             # if a key is unavailable, then we still need to put something in the
154             # user's GID. So make one up.
155             pkey = Keypair(create=True)
156
157         # create the gid
158         person_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
159         person_record = table.resolve("user", hrn)
160         if not person_record:
161             trace("  inserting user record for " + hrn)
162             person_record = GeniRecord(hrn=hrn, gid=person_gid, type="user", pointer=person['person_id'])
163             table.insert(person_record)
164         else:
165             trace("  updating user record for " + hrn)
166             person_record = GeniRecord(hrn=hrn, gid=person_gid, type="user", pointer=person['person_id'])
167             table.update(person_record)
168
169     def import_slice(self, parent_hrn, slice):
170         AuthHierarchy = self.AuthHierarchy
171         slicename = slice['name'].split("_",1)[-1]
172         slicename = cleanup_string(slicename)
173
174         if not slicename:
175             error("Import_Slice: failed to parse slice name " + slice['name'])
176             return
177
178         hrn = parent_hrn + "." + slicename
179         trace("Import: importing slice " + hrn)
180
181         table = self.get_auth_table(parent_hrn)
182
183         slice_record = table.resolve("slice", hrn)
184         if not slice_record:
185             pkey = Keypair(create=True)
186             slice_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
187             slice_record = GeniRecord(hrn=hrn, gid=slice_gid, type="slice", pointer=slice['slice_id'])
188             trace("  inserting slice record for " + hrn)
189             table.insert(slice_record)
190
191     def import_node(self, parent_hrn, node):
192         AuthHierarchy = self.AuthHierarchy
193         nodename = node['hostname'].replace(".", "_")
194         nodename = cleanup_string(nodename)
195
196         if not nodename:
197             error("Import_node: failed to parse node name " + node['hostname'])
198             return
199
200         hrn = parent_hrn + "." + nodename
201
202         # ASN.1 will have problems with hrn's longer than 64 characters
203         if len(hrn) > 64:
204             hrn = hrn[:64]
205
206         trace("Import: importing node " + hrn)
207
208         table = self.get_auth_table(parent_hrn)
209
210         node_record = table.resolve("node", hrn)
211         if not node_record:
212             pkey = Keypair(create=True)
213             node_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
214             node_record = GeniRecord(hrn=hrn, gid=node_gid, type="node", pointer=node['node_id'])
215             trace("  inserting node record for " + hrn)
216             table.insert(node_record)
217
218
219     
220     def import_site(self, parent_hrn, site):
221         AuthHierarchy = self.AuthHierarchy
222         shell = self.shell
223         plc_auth = self.plc_auth
224         sitename = site['login_base']
225         sitename = cleanup_string(sitename)
226
227         hrn = parent_hrn + "." + sitename
228
229         # Hardcode 'internet2' into the hrn for sites hosting
230         # internet2 nodes. This is a special operation for some vini
231         # sites only
232         if ".vini" in parent_hrn and parent_hrn.endswith('vini'):
233             if sitename.startswith("ii"):
234                 sitename = sitename.replace("ii", "")
235                 hrn = ".".join([parent_hrn, "internet2", sitename])
236             elif sitename.startswith("nlr"):
237                 hrn = ".".join([parent_hrn, "internet2", sitename])
238                 sitename = sitename.replace("nlr", "")
239
240         trace("Import_Site: importing site " + hrn)
241
242         # create the authority
243         if not AuthHierarchy.auth_exists(hrn):
244             AuthHierarchy.create_auth(hrn)
245
246         auth_info = AuthHierarchy.get_auth_info(hrn)
247
248         table = self.get_auth_table(parent_hrn)
249
250         auth_record = table.resolve("authority", hrn)
251         if not auth_record:
252             auth_record = GeniRecord(hrn=hrn, gid=auth_info.get_gid_object(), type="authority", pointer=site['site_id'])
253             trace("  inserting authority record for " + hrn)
254             table.insert(auth_record)
255
256         if 'person_ids' in site:
257             for person_id in site['person_ids']:
258                 persons = shell.GetPersons(plc_auth, [person_id])
259                 if persons:
260                     try:
261                         self.import_person(hrn, persons[0])
262                     except Exception, e:
263                         trace("Failed to import: %s (%s)" % (persons[0], e))
264         if 'slice_ids' in site:
265             for slice_id in site['slice_ids']:
266                 slices = shell.GetSlices(plc_auth, [slice_id])
267                 if slices:
268                     try:
269                         self.import_slice(hrn, slices[0])
270                     except Exception, e:
271                         trace("Failed to import: %s (%s)" % (slices[0], e))
272         if 'node_ids' in site:
273             for node_id in site['node_ids']:
274                 nodes = shell.GetNodes(plc_auth, [node_id])
275                 if nodes:
276                     try:
277                         self.import_node(hrn, nodes[0])
278                     except Exception, e:
279                         trace("Failed to import: %s (%s)" % (nodes[0], e))     
280
281     def delete_record(self, parent_hrn, object, type):
282         # get the hrn
283         hrn = None
284         if type in ['slice'] and 'name' in object and object['name']:
285             slice_name = object['name'].split("_")[0]
286             hrn = parent_hrn + "." + slice_name
287         elif type in ['user', 'person'] and 'email' in object and object['email']:
288             person_name = object['email'].split('@')[0]
289             hrn = parent_hrn + "." + person_name
290         elif type in ['node'] and 'hostname' in object and object['hostname']:
291             node_name =  object['hostname'].replace('.','_')  
292             hrn = parent_hrn + "." + node_name
293         elif type in ['site'] and 'login_base' in object and object['login_base']:
294             site_name = object['login_base']
295             hrn = parent_hrn + "." + site_name         
296         else:
297             return
298
299         table = self.get_auth_table(parent_hrn)
300         record_list = table.resolve(type, hrn)
301         if not record_list:
302             return
303         record = record_list[0]
304         table.remove(record)