1 from sfa.util.config import Config
2 from sfa.util.xrn import Xrn, get_authority, hrn_to_urn
4 from sfa.iotlab.iotlabdriver import IotlabDriver
6 from sfa.trust.certificate import Keypair, convert_public_key
7 from sfa.trust.gid import create_uuid
9 from sfa.storage.alchemy import dbsession
10 from sfa.storage.model import RegRecord, RegAuthority, RegSlice, RegNode, \
14 from sqlalchemy.exc import SQLAlchemyError
18 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
21 IotlabImporter class, generic importer_class. Used to populate the SFA DB
22 with iotlab resources' records.
26 SlabImporter class, generic importer_class. Used to populate the SFA DB
27 with senslab resources' records.
28 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
29 Used to update records when new resources, users or nodes, are added
33 def __init__ (self, auth_hierarchy, loc_logger):
35 Sets and defines import logger and the authority name. Gathers all the
36 records already registerd in the SFA DB, broke them into 3 dicts,
37 by type and hrn, by email and by type and pointer.
39 :param auth_hierarchy: authority name
40 :type auth_hierarchy: string
41 :param loc_logger: local logger
42 :type loc_logger: _SfaLogger
45 self.auth_hierarchy = auth_hierarchy
46 self.logger = loc_logger
47 self.logger.setLevelDebug()
48 #retrieve all existing SFA objects
49 self.all_records = dbsession.query(RegRecord).all()
51 # initialize record.stale to True by default,
52 # then mark stale=False on the ones that are in use
53 for record in self.all_records:
55 #create hash by (type,hrn)
56 #used to know if a given record is already known to SFA
57 self.records_by_type_hrn = \
58 dict([( (record.type,record.hrn), record) \
59 for record in self.all_records])
61 self.users_rec_by_email = \
62 dict([ (record.email, record) \
63 for record in self.all_records if record.type == 'user'])
65 # create hash by (type,pointer)
66 self.records_by_type_pointer = \
67 dict([ ( (str(record.type), record.pointer) , record) \
68 for record in self.all_records if record.pointer != -1])
73 def hostname_to_hrn_escaped(root_auth, hostname):
76 Returns a node's hrn based on its hostname and the root
77 authority and by removing special caracters from the hostname.
79 :param root_auth: root authority name
80 :param hostname: nodes's hostname
81 :type root_auth: string
82 :type hostname: string
85 return '.'.join( [root_auth, Xrn.escape(hostname)] )
89 def slicename_to_hrn(person_hrn):
92 Returns the slicename associated to a given person's hrn.
94 :param person_hrn: user's hrn
95 :type person_hrn: string
98 return (person_hrn +'_slice')
100 def add_options (self, parser):
101 # we don't have any options for now
104 def find_record_by_type_hrn(self, record_type, hrn):
107 Returns the record associated with a given hrn and hrn type.
108 Returns None if the key tuple is not in dictionary.
110 :param record_type: the record's type (slice, node, authority...)
111 :type record_type: string
112 :param hrn: Human readable name of the object's record
114 :rtype: RegUser if user, RegSlice if slice, RegNode if node...
115 or None if record does not exist.
118 return self.records_by_type_hrn.get ( (record_type, hrn), None)
120 def locate_by_type_pointer (self, record_type, pointer):
123 Returns the record corresponding to the key pointer and record
124 type. Returns None if the record does not exist and is not in the
125 records_by_type_pointer dictionnary.
127 :param record_type: the record's type (slice, node, authority...)
128 :type record_type: string
129 :param pointer:Pointer to where the record is in the origin db,
130 used in case the record comes from a trusted authority.
131 :type pointer: integer
132 :rtype: RegUser if user, RegSlice if slice, RegNode if node...
133 or None if record does not exist.
135 return self.records_by_type_pointer.get ( (record_type, pointer), None)
138 def update_just_added_records_dict (self, record):
141 Updates the records_by_type_hrn dictionnary if the record has
144 :param record: Record to add in the records_by_type_hrn dict.
145 :type record: dictionary
147 rec_tuple = (record.type, record.hrn)
148 if rec_tuple in self.records_by_type_hrn:
149 self.logger.warning ("IotlabImporter.update_just_added_records_dict:\
150 duplicate (%s,%s)"%rec_tuple)
152 self.records_by_type_hrn [ rec_tuple ] = record
154 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
155 def import_sites_and_nodes(self, iotlabdriver):
157 def import_sites_and_nodes(self, slabdriver):
158 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
161 Gets all the sites and nodes from OAR, process the information,
162 creates hrns and RegAuthority for sites, and feed them to the database.
163 For each site, import the site's nodes to the DB by calling
166 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
167 :param iotlabdriver: IotlabDriver object, used to have access to iotlabdriver
168 methods and fetching info on sites and nodes.
169 :type iotlabdriver: IotlabDriver
172 sites_listdict = iotlabdriver.iotlab_api.GetSites()
173 nodes_listdict = iotlabdriver.iotlab_api.GetNodes()
175 :param slabdriver: SlabDriver object, used to have access to slabdriver
176 methods and fetching info on sites and nodes.
177 :type slabdriver: SlabDriver
180 sites_listdict = slabdriver.slab_api.GetSites()
181 nodes_listdict = slabdriver.slab_api.GetNodes()
182 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
183 nodes_by_id = dict([(node['node_id'], node) for node in nodes_listdict])
184 for site in sites_listdict:
185 site_hrn = site['name']
186 site_record = self.find_record_by_type_hrn ('authority', site_hrn)
189 urn = hrn_to_urn(site_hrn, 'authority')
190 if not self.auth_hierarchy.auth_exists(urn):
191 self.auth_hierarchy.create_auth(urn)
193 auth_info = self.auth_hierarchy.get_auth_info(urn)
194 site_record = RegAuthority(hrn=site_hrn, \
195 gid=auth_info.get_gid_object(),
197 authority=get_authority(site_hrn))
198 site_record.just_created()
199 dbsession.add(site_record)
201 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
202 self.logger.info("IotlabImporter: imported authority (site) \
204 self.logger.info("SlabImporter: imported authority (site) \
205 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
207 self.update_just_added_records_dict(site_record)
208 except SQLAlchemyError:
209 # if the site import fails then there is no point in
210 # trying to import the
211 # site's child records(node, slices, persons), so skip them.
212 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
213 self.logger.log_exc("IotlabImporter: failed to import site. \
215 self.logger.log_exc("SlabImporter: failed to import site. \
216 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
217 Skipping child records")
220 # xxx update the record ...
224 site_record.stale = False
225 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
226 self.import_nodes(site['node_ids'], nodes_by_id, iotlabdriver)
230 def import_nodes(self, site_node_ids, nodes_by_id, iotlabdriver):
232 self.import_nodes(site['node_ids'], nodes_by_id, slabdriver)
236 def import_nodes(self, site_node_ids, nodes_by_id, slabdriver):
237 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
240 Creates appropriate hostnames and RegNode records for
241 each node in site_node_ids, based on the information given by the
242 dict nodes_by_id that was made from data from OAR.
243 Saves the records to the DB.
245 :param site_node_ids: site's node ids
246 :type site_node_ids: list of integers
247 :param nodes_by_id: dictionary , key is the node id, value is the a dict
248 with node information.
249 :type nodes_by_id: dictionary
250 :param iotlabdriver:IotlabDriver object, used to have access to iotlabdriver
252 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
253 :type iotlabdriver:IotlabDriver
255 :type slabdriver:SlabDriver
256 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
260 for node_id in site_node_ids:
262 node = nodes_by_id[node_id]
264 self.logger.warning ("IotlabImporter: cannot find node_id %s \
265 - ignored" %(node_id))
268 self.hostname_to_hrn_escaped(iotlabdriver.iotlab_api.root_auth, \
270 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
271 self.logger.info("IOTLABIMPORTER node %s " %(node))
273 self.logger.info("SLABIMPORTER node %s " %(node))
274 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
278 # xxx this sounds suspicious
281 node_record = self.find_record_by_type_hrn( 'node', hrn )
283 pkey = Keypair(create=True)
284 urn = hrn_to_urn(escaped_hrn, 'node')
286 self.auth_hierarchy.create_gid(urn, \
289 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
290 def iotlab_get_authority(hrn):
292 def slab_get_authority(hrn):
293 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
294 return hrn.split(".")[0]
296 node_record = RegNode(hrn=hrn, gid=node_gid,
298 authority=iotlab_get_authority(hrn))
301 node_record.just_created()
302 dbsession.add(node_record)
304 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
305 self.logger.info("IotlabImporter: imported node: %s" \
307 self.update_just_added_records_dict(node_record)
308 except SQLAlchemyError:
309 self.logger.log_exc("IotlabImporter: \
311 self.logger.info("SlabImporter: imported node: %s" \
313 self.update_just_added_records_dict(node_record)
314 except SQLAlchemyError:
315 self.logger.log_exc("SlabImporter: \
316 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
317 failed to import node")
319 #TODO: xxx update the record ...
321 node_record.stale = False
322 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
325 def init_person_key (self, person, iotlab_key):
329 def init_person_key (self, person, slab_key):
330 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
333 Returns a tuple pubkey and pkey.
335 :param person Person's data.
337 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
338 :param iotlab_key: SSH public key, from LDAP user's data.
340 :param slab_key: SSH public key, from LDAP user's data.
341 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
343 :type iotlab_key: string
344 :rtype (string, Keypair)
348 # randomly pick first key in set
349 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
353 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
356 pkey = convert_public_key(pubkey)
358 #key not good. create another pkey
359 self.logger.warn('IotlabImporter: \
360 unable to convert public \
361 key for %s' %person['hrn'])
362 pkey = Keypair(create=True)
365 # the user has no keys.
366 #Creating a random keypair for the user's gid
367 self.logger.warn("IotlabImporter: person %s does not have a \
368 public key" %(person['hrn']))
369 pkey = Keypair(create=True)
370 return (pubkey, pkey)
373 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
374 def import_persons_and_slices(self, iotlabdriver):
376 def import_persons_and_slices(self, slabdriver):
377 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
380 Gets user data from LDAP, process the information.
381 Creates hrn for the user's slice, the user's gid, creates
382 the RegUser record associated with user. Creates the RegKey record
383 associated nwith the user's key.
384 Saves those records into the SFA DB.
385 import the user's slice onto the database as well by calling
388 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
389 :param iotlabdriver:IotlabDriver object, used to have access to iotlabdriver
391 :param slabdriver:SlabDriver object, used to have access to slabdriver
392 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
394 :type iotlabdriver:IotlabDriver
396 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
397 ldap_person_listdict = iotlabdriver.iotlab_api.GetPersons()
398 self.logger.info("IOTLABIMPORT \t ldap_person_listdict %s \r\n" \
400 ldap_person_listdict = slabdriver.slab_api.GetPersons()
401 self.logger.info("SLABIMPORT \t ldap_person_listdict %s \r\n" \
402 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
403 %(ldap_person_listdict))
406 for person in ldap_person_listdict :
408 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
409 self.logger.info("IotlabImporter: person :" %(person))
411 self.logger.info("SlabImporter: person :" %(person))
412 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
413 if 'ssh-rsa' not in person['pkey']:
414 #people with invalid ssh key (ssh-dss, empty, bullshit keys...)
417 person_hrn = person['hrn']
418 slice_hrn = self.slicename_to_hrn(person['hrn'])
420 # xxx suspicious again
421 if len(person_hrn) > 64:
422 person_hrn = person_hrn[:64]
423 person_urn = hrn_to_urn(person_hrn, 'user')
426 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
427 self.logger.info("IotlabImporter: users_rec_by_email %s " \
429 self.logger.info("SlabImporter: users_rec_by_email %s " \
430 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
431 %(self.users_rec_by_email))
433 #Check if user using person['email'] from LDAP is already registered
434 #in SFA. One email = one person. In this case, do not create another
435 #record for this person
436 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
437 #person_hrn returned by GetPerson based on iotlab root auth +
439 #person_hrn returned by GetPerson based on senslab root auth +
440 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
442 user_record = self.find_record_by_type_hrn('user', person_hrn)
444 if not user_record and person['email'] in self.users_rec_by_email:
445 user_record = self.users_rec_by_email[person['email']]
446 person_hrn = user_record.hrn
447 person_urn = hrn_to_urn(person_hrn, 'user')
450 slice_record = self.find_record_by_type_hrn ('slice', slice_hrn)
452 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
453 iotlab_key = person['pkey']
455 slab_key = person['pkey']
456 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
459 (pubkey, pkey) = self.init_person_key(person, iotlab_key)
460 if pubkey is not None and pkey is not None :
462 self.auth_hierarchy.create_gid(person_urn, \
465 self.logger.debug( "SLAB IMPORTER \
466 PERSON EMAIL OK email %s " %(person['email']))
467 person_gid.set_email(person['email'])
468 user_record = RegUser(hrn=person_hrn, \
471 authority=get_authority(person_hrn),
472 email=person['email'])
474 user_record = RegUser(hrn=person_hrn, \
477 authority=get_authority(person_hrn))
480 user_record.reg_keys = [RegKey(pubkey)]
482 self.logger.warning("No key found for user %s" \
486 user_record.just_created()
487 dbsession.add (user_record)
489 self.logger.info("IotlabImporter: imported person %s"\
491 self.update_just_added_records_dict( user_record )
493 except SQLAlchemyError:
494 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
495 self.logger.log_exc("IotlabImporter: \
497 self.logger.log_exc("SlabImporter: \
498 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
499 failed to import person %s"%(person))
501 # update the record ?
502 # if user's primary key has changed then we need to update
503 # the users gid by forcing an update here
504 sfa_keys = user_record.reg_keys
507 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
508 if iotlab_key is not sfa_keys :
510 if slab_key is not sfa_keys :
511 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
514 self.logger.info("IotlabImporter: \t \t USER UPDATE \
515 person: %s" %(person['hrn']))
516 (pubkey, pkey) = self.init_person_key (person, iotlab_key)
518 self.auth_hierarchy.create_gid(person_urn, \
521 user_record.reg_keys = []
523 user_record.reg_keys = [RegKey(pubkey)]
524 self.logger.info("IotlabImporter: updated person: %s" \
528 user_record.email = person['email']
532 user_record.stale = False
533 except SQLAlchemyError:
534 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
535 self.logger.log_exc("IotlabImporter: \
537 self.logger.log_exc("SlabImporter: \
538 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
539 failed to update person %s"%(person))
541 self.import_slice(slice_hrn, slice_record, user_record)
544 def import_slice(self, slice_hrn, slice_record, user_record):
547 Create RegSlice record according to the slice hrn if the slice
548 does not exist yet.Creates a relationship with the user record
549 associated with the slice.
550 Commit the record to the database.
553 :param slice_hrn: Human readable name of the slice.
554 :type slice_hrn: string
555 :param slice_record: record of the slice found in the DB, if any.
556 :type slice_record: RegSlice or None
557 :param user_record: user record found in the DB if any.
558 :type user_record: RegUser
560 .. todo::Update the record if a slice record already exists.
562 if not slice_record :
563 pkey = Keypair(create=True)
564 urn = hrn_to_urn(slice_hrn, 'slice')
566 self.auth_hierarchy.create_gid(urn, \
568 slice_record = RegSlice (hrn=slice_hrn, gid=slice_gid,
570 authority=get_authority(slice_hrn))
572 slice_record.just_created()
573 dbsession.add(slice_record)
577 self.update_just_added_records_dict ( slice_record )
579 except SQLAlchemyError:
580 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
581 self.logger.log_exc("IotlabImporter: failed to import slice")
583 #No slice update upon import in iotlab
585 self.logger.log_exc("SlabImporter: failed to import slice")
587 #No slice update upon import in senslab
588 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
590 # xxx update the record ...
591 self.logger.warning ("Slice update not yet implemented")
593 # record current users affiliated with the slice
596 slice_record.reg_researchers = [user_record]
599 slice_record.stale = False
600 except SQLAlchemyError:
601 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
602 self.logger.log_exc("IotlabImporter: failed to update slice")
604 self.logger.log_exc("SlabImporter: failed to update slice")
605 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
608 def run (self, options):
610 Create the special iotlab table, iotlab_xp, in the iotlab database.
611 Import everything (users, slices, nodes and sites from OAR
612 and LDAP) into the SFA database.
613 Delete stale records that are no longer in OAR or LDAP.
619 <<<<<<< HEAD:sfa/importer/iotlabimporter.py
620 iotlabdriver = IotlabDriver(config)
622 #Create special slice table for iotlab
624 if not iotlabdriver.db.exists('iotlab_xp'):
625 iotlabdriver.db.createtable()
626 self.logger.info ("IotlabImporter.run: iotlab_xp table created ")
629 # import site and node records in site into the SFA db.
630 self.import_sites_and_nodes(iotlabdriver)
631 #import users and slice into the SFA DB.
632 self.import_persons_and_slices(iotlabdriver)
634 ### remove stale records
635 # special records must be preserved
636 system_hrns = [iotlabdriver.hrn, iotlabdriver.iotlab_api.root_auth, \
637 iotlabdriver.hrn+ '.slicemanager']
639 slabdriver = SlabDriver(config)
641 #Create special slice table for senslab
643 if not slabdriver.db.exists('slab_xp'):
644 slabdriver.db.createtable()
645 self.logger.info ("SlabImporter.run: slab_xp table created ")
648 # import site and node records in site into the SFA db.
649 self.import_sites_and_nodes(slabdriver)
650 #import users and slice into the SFA DB.
651 self.import_persons_and_slices(slabdriver)
653 ### remove stale records
654 # special records must be preserved
655 system_hrns = [slabdriver.hrn, slabdriver.slab_api.root_auth, \
656 slabdriver.hrn+ '.slicemanager']
657 >>>>>>> 3fe7429... SA:sfa/importer/slabimporter.py
658 for record in self.all_records:
659 if record.hrn in system_hrns:
661 if record.peer_authority:
665 for record in self.all_records:
666 if record.type == 'user':
667 self.logger.info("IotlabImporter: stale records: hrn %s %s" \
668 %(record.hrn,record.stale) )
673 self.logger.warning("stale not found with %s"%record)
675 self.logger.info("IotlabImporter: deleting stale record: %s" \
679 dbsession.delete(record)
681 except SQLAlchemyError:
682 self.logger.log_exc("IotlabImporter: failed to delete stale \
683 record %s" %(record) )