modified delete_record
[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,
91                           cninfo=auth_info.get_dbinfo())
92
93         # if the table doesn't exist, then it means we haven't put any records
94         # into this authority yet.
95
96         if not table.exists():
97             trace("Import: creating table for authority " + auth_name)
98             table.create()
99
100         return table
101
102
103     def create_top_level_auth_records(self, hrn):
104         AuthHierarchy = self.AuthHierarchy
105         
106         # if root doesnt exist, create it
107         if not AuthHierarchy.auth_exists(hrn):
108             AuthHierarchy.create_auth(hrn)
109         
110         # get the parent hrn
111         parent_hrn = get_authority(hrn)
112         if not parent_hrn:
113             parent_hrn = hrn
114
115         # get the auth info of the newly created root auth (parent)
116         # or level1_auth if it exists
117         auth_info = AuthHierarchy.get_auth_info(parent_hrn)
118         if self.level1_auth:
119             auth_info = AuthHierarchy.get_auth_info(hrn)
120         table = self.get_auth_table(parent_hrn)
121
122         auth_record = table.resolve("authority", hrn)
123         if not auth_record:
124             auth_record = GeniRecord(hrn=hrn, gid=auth_info.get_gid_object(), type="authority", pointer=-1)
125             trace("  inserting authority record for " + hrn)
126             table.insert(auth_record)
127
128
129     def import_person(self, parent_hrn, person):
130         AuthHierarchy = self.AuthHierarchy
131         hrn = person_to_hrn(parent_hrn, person)
132
133         # ASN.1 will have problems with hrn's longer than 64 characters
134         if len(hrn) > 64:
135             hrn = hrn[:64]
136
137         trace("Import: importing person " + hrn)
138
139         table = self.get_auth_table(parent_hrn)
140
141         key_ids = []
142         if 'key_ids' in person and person['key_ids']:
143             key_ids = person["key_ids"]
144
145             # get the user's private key from the SSH keys they have uploaded
146             # to planetlab
147             keys = shell.GetKeys(plc_auth, key_ids)
148             key = keys[0]['key']
149             pkey = convert_public_key(key)
150         else:
151             # the user has no keys
152             trace("   person " + hrn + " does not have a PL public key")
153
154             # if a key is unavailable, then we still need to put something in the
155             # user's GID. So make one up.
156             pkey = Keypair(create=True)
157
158         # create the gid
159         person_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
160         person_record = table.resolve("user", hrn)
161         if not person_record:
162             trace("  inserting user record for " + hrn)
163             person_record = GeniRecord(hrn=hrn, gid=person_gid, type="user", pointer=person['person_id'])
164             table.insert(person_record)
165         else:
166             trace("  updating user record for " + hrn)
167             person_record = GeniRecord(hrn=hrn, gid=person_gid, type="user", pointer=person['person_id'])
168             table.update(person_record)
169
170     def import_slice(self, parent_hrn, slice):
171         AuthHierarchy = self.AuthHierarchy
172         slicename = slice['name'].split("_",1)[-1]
173         slicename = cleanup_string(slicename)
174
175         if not slicename:
176             error("Import_Slice: failed to parse slice name " + slice['name'])
177             return
178
179         hrn = parent_hrn + "." + slicename
180         trace("Import: importing slice " + hrn)
181
182         table = self.get_auth_table(parent_hrn)
183
184         slice_record = table.resolve("slice", hrn)
185         if not slice_record:
186             pkey = Keypair(create=True)
187             slice_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
188             slice_record = GeniRecord(hrn=hrn, gid=slice_gid, type="slice", pointer=slice['slice_id'])
189             trace("  inserting slice record for " + hrn)
190             table.insert(slice_record)
191
192     def import_node(self, parent_hrn, node):
193         AuthHierarchy = self.AuthHierarchy
194         nodename = node['hostname'].split(".")[0]
195         nodename = cleanup_string(nodename)
196
197         if not nodename:
198             error("Import_node: failed to parse node name " + node['hostname'])
199             return
200
201         hrn = parent_hrn + "." + nodename
202
203         # ASN.1 will have problems with hrn's longer than 64 characters
204         if len(hrn) > 64:
205             hrn = hrn[:64]
206
207         trace("Import: importing node " + hrn)
208
209         table = self.get_auth_table(parent_hrn)
210
211         node_record = table.resolve("node", hrn)
212         if not node_record:
213             pkey = Keypair(create=True)
214             node_gid = AuthHierarchy.create_gid(hrn, create_uuid(), pkey)
215             node_record = GeniRecord(hrn=hrn, gid=node_gid, type="node", pointer=node['node_id'])
216             trace("  inserting node record for " + hrn)
217             table.insert(node_record)
218
219
220     
221     def import_site(self, parent_hrn, site):
222         AuthHierarchy = self.AuthHierarchy
223         shell = self.shell
224         plc_auth = self.plc_auth
225         sitename = site['login_base']
226         sitename = cleanup_string(sitename)
227
228         hrn = parent_hrn + "." + sitename
229
230         # Hardcode 'internet2' into the hrn for sites hosting
231         # internet2 nodes. This is a special operation for some vini
232         # sites only
233         if ".vini" in parent_hrn and parent_hrn.endswith('vini'):
234             if sitename.startswith("ii"):
235                 sitename = sitename.replace("ii", "")
236                 hrn = ".".join([parent_hrn, "internet2", sitename])
237             elif sitename.startswith("nlr"):
238                 hrn = ".".join([parent_hrn, "internet2", sitename])
239                 sitename = sitename.replace("nlr", "")
240
241         trace("Import_Site: importing site " + hrn)
242
243         # create the authority
244         if not AuthHierarchy.auth_exists(hrn):
245             AuthHierarchy.create_auth(hrn)
246
247         auth_info = AuthHierarchy.get_auth_info(hrn)
248
249         table = self.get_auth_table(parent_hrn)
250
251         auth_record = table.resolve("authority", hrn)
252         if not auth_record:
253             auth_record = GeniRecord(hrn=hrn, gid=auth_info.get_gid_object(), type="authority", pointer=site['site_id'])
254             trace("  inserting authority record for " + hrn)
255             table.insert(auth_record)
256
257         if 'person_ids' in site:
258             for person_id in site['person_ids']:
259                 persons = shell.GetPersons(plc_auth, [person_id])
260                 if persons:
261                     try:
262                         self.import_person(hrn, persons[0])
263                     except Exception, e:
264                         trace("Failed to import: %s (%s)" % (persons[0], e))
265         if 'slice_ids' in site:
266             for slice_id in site['slice_ids']:
267                 slices = shell.GetSlices(plc_auth, [slice_id])
268                 if slices:
269                     try:
270                         self.import_slice(hrn, slices[0])
271                     except Exception, e:
272                         trace("Failed to import: %s (%s)" % (slices[0], e))
273         if 'node_ids' in site:
274             for node_id in site['node_ids']:
275                 nodes = shell.GetNodes(plc_auth, [node_id])
276                 if nodes:
277                     try:
278                         self.import_node(hrn, nodes[0])
279                     except Exception, e:
280                         trace("Failed to import: %s (%s)" % (nodes[0], e))     
281
282     def delete_record(self, parent_hrn, object, type):
283         # get the hrn
284         hrn = None
285         if type in ['slice'] and 'name' in object and object['name']:
286             slice_name = object['name'].split("_")[0]
287             hrn = parent_hrn + "." + slice_name
288         elif type in ['user', 'person'] and 'email' in object and object['email']:
289             person_name = object['email'].split('@')[0]
290             hrn = parent_hrn + "." + person_name
291         elif type in ['node'] and 'hostname' in object and object['hostname']:
292             node_name =  object['hostname'].replace('.','_')  
293             hrn = parent_hrn + "." + node_name
294         elif type in ['site'] and 'login_base' in object and object['login_base']:
295             site_name = object['login_base']
296             hrn = parent_hrn + "." + site_name         
297         else:
298             return
299
300         auth_name = self.get_auth_table(hrn)
301         table = self.AuthHierarchy.get_auth_table(auth_name)
302         record_list = table.resolve(type, hrn)
303         if not record_list:
304             return
305         record = record_list[0]
306         table.remove(record)