4 from sfa.util.config import Config
5 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
7 from sfa.trust.gid import create_uuid
8 from sfa.trust.certificate import convert_public_key, Keypair
10 # using global alchemy.session() here is fine
11 # as importer is on standalone one-shot process
12 from sfa.storage.alchemy import global_dbsession
13 from sfa.storage.model import RegRecord, RegAuthority, RegSlice, RegNode, RegUser, RegKey
15 from sfa.nitos.nitosshell import NitosShell
16 from sfa.nitos.nitosxrn import hostname_to_hrn, slicename_to_hrn, email_to_hrn, hrn_to_nitos_slicename, username_to_hrn
19 def _get_site_hrn(interface_hrn, site):
20 hrn = ".".join([interface_hrn, site['name']])
26 def __init__(self, auth_hierarchy, logger):
27 self.auth_hierarchy = auth_hierarchy
30 def add_options(self, parser):
31 # we don't have any options for now
34 # hrn hash is initialized from current db
35 # remember just-created records as we go
36 # xxx might make sense to add a UNIQUE constraint in the db itself
37 def remember_record_by_hrn(self, record):
38 tuple = (record.type, record.hrn)
39 if tuple in self.records_by_type_hrn:
41 "NitosImporter.remember_record_by_hrn: duplicate (%s,%s)" % tuple)
43 self.records_by_type_hrn[tuple] = record
45 # ditto for pointer hash
46 def remember_record_by_pointer(self, record):
47 if record.pointer == -1:
49 "NitosImporter.remember_record_by_pointer: pointer is void")
51 tuple = (record.type, record.pointer)
52 if tuple in self.records_by_type_pointer:
54 "NitosImporter.remember_record_by_pointer: duplicate (%s,%s)" % tuple)
56 self.records_by_type_pointer[(record.type, record.pointer,)] = record
58 def remember_record(self, record):
59 self.remember_record_by_hrn(record)
60 self.remember_record_by_pointer(record)
62 def locate_by_type_hrn(self, type, hrn):
63 return self.records_by_type_hrn.get((type, hrn), None)
65 def locate_by_type_pointer(self, type, pointer):
66 return self.records_by_type_pointer.get((type, pointer), None)
68 # a convenience/helper function to see if a record is already known
69 # a former, broken, attempt (in 2.1-9) had been made
70 # to try and use 'pointer' as a first, most significant attempt
71 # the idea being to preserve stuff as much as possible, and thus
72 # to avoid creating a new gid in the case of a simple hrn rename
73 # however this of course doesn't work as the gid depends on the hrn...
74 # def locate (self, type, hrn=None, pointer=-1):
76 # attempt = self.locate_by_type_pointer (type, pointer)
77 # if attempt : return attempt
79 # attempt = self.locate_by_type_hrn (type, hrn,)
80 # if attempt : return attempt
83 # this makes the run method a bit abtruse - out of the way
85 def run(self, options):
87 interface_hrn = config.SFA_INTERFACE_HRN
88 root_auth = config.SFA_REGISTRY_ROOT_AUTH
89 shell = NitosShell(config)
91 # retrieve all existing SFA objects
92 all_records = global_dbsession.query(RegRecord).all()
94 # create hash by (type,hrn)
95 # we essentially use this to know if a given record is already known to
97 self.records_by_type_hrn = \
98 dict([((record.type, record.hrn), record)
99 for record in all_records])
100 # create hash by (type,pointer)
101 self.records_by_type_pointer = \
102 dict([((record.type, record.pointer), record) for record in all_records
103 if record.pointer != -1])
105 # initialize record.stale to True by default, then mark stale=False on
106 # the ones that are in use
107 for record in all_records:
110 # retrieve NITOS data
112 # retrieve only required stuf
113 site = shell.getTestbedInfo()
115 # create a hash of sites by login_base
116 # # sites_by_login_base = dict ( [ ( site['login_base'], site ) for site in sites ] )
117 # Get all NITOS users
118 users = shell.getUsers()
119 # create a hash of users by user_id
120 users_by_id = dict([(user['user_id'], user) for user in users])
121 # Get all NITOS public keys
122 # accumulate key ids for keys retrieval
124 # for person in persons:
125 # key_ids.extend(person['key_ids'])
126 # keys = shell.GetKeys( {'peer_id': None, 'key_id': key_ids,
127 # 'key_type': 'ssh'} )
128 # # create a hash of keys by key_id
129 # keys_by_id = dict ( [ ( key['key_id'], key ) for key in keys ] )
130 # create a dict user_id -> [ (nitos)keys ]
131 keys_by_user_id = dict(
132 [(user['user_id'], user['keys']) for user in users])
133 # Get all nitos nodes
134 nodes = shell.getNodes({}, [])
135 # create hash by node_id
136 nodes_by_id = dict([(node['node_id'], node) for node in nodes])
137 # Get all nitos slices
138 slices = shell.getSlices({}, [])
139 # create hash by slice_id
140 slices_by_id = dict([(slice['slice_id'], slice) for slice in slices])
145 site_hrn = _get_site_hrn(interface_hrn, site)
146 # import if hrn is not in list of existing hrns or if the hrn exists
147 # but its not a site record
148 site_record = self.locate_by_type_hrn('authority', site_hrn)
151 urn = hrn_to_urn(site_hrn, 'authority')
152 if not self.auth_hierarchy.auth_exists(urn):
153 self.auth_hierarchy.create_auth(urn)
154 auth_info = self.auth_hierarchy.get_auth_info(urn)
155 site_record = RegAuthority(hrn=site_hrn, gid=auth_info.get_gid_object(),
157 authority=get_authority(site_hrn))
158 site_record.just_created()
159 global_dbsession.add(site_record)
160 global_dbsession.commit()
162 "NitosImporter: imported authority (site) : %s" % site_record)
163 self.remember_record(site_record)
165 # if the site import fails then there is no point in trying to import the
166 # site's child records (node, slices, persons), so skip
169 "NitosImporter: failed to import site. Skipping child records")
172 # xxx update the record ...
174 site_record.stale = False
176 # import node records
178 site_auth = get_authority(site_hrn)
179 site_name = site['name']
180 node_hrn = hostname_to_hrn(
181 site_auth, site_name, node['hostname'])
182 # xxx this sounds suspicious
183 if len(node_hrn) > 64:
184 node_hrn = node_hrn[:64]
185 node_record = self.locate_by_type_hrn('node', node_hrn)
188 pkey = Keypair(create=True)
189 urn = hrn_to_urn(node_hrn, 'node')
190 node_gid = self.auth_hierarchy.create_gid(
191 urn, create_uuid(), pkey)
192 node_record = RegNode(hrn=node_hrn, gid=node_gid,
193 pointer=node['node_id'],
194 authority=get_authority(node_hrn))
195 node_record.just_created()
196 global_dbsession.add(node_record)
197 global_dbsession.commit()
199 "NitosImporter: imported node: %s" % node_record)
200 self.remember_record(node_record)
203 "NitosImporter: failed to import node")
205 # xxx update the record ...
208 node_record.stale = False
212 user_hrn = username_to_hrn(
213 interface_hrn, site['name'], user['username'])
214 # xxx suspicious again
215 if len(user_hrn) > 64:
216 user_hrn = user_hrn[:64]
217 user_urn = hrn_to_urn(user_hrn, 'user')
219 user_record = self.locate_by_type_hrn('user', user_hrn)
221 # return a tuple pubkey (a nitos key object) and pkey (a
223 def init_user_key(user):
227 # randomly pick first key in set
228 for key in user['keys']:
231 pkey = convert_public_key(pubkey)
237 'NitosImporter: unable to convert public key for %s' % user_hrn)
238 pkey = Keypair(create=True)
240 # the user has no keys. Creating a random keypair for
243 "NitosImporter: user %s does not have a NITOS public key" % user_hrn)
244 pkey = Keypair(create=True)
245 return (pubkey, pkey)
250 (pubkey, pkey) = init_user_key(user)
251 user_gid = self.auth_hierarchy.create_gid(
252 user_urn, create_uuid(), pkey)
253 user_gid.set_email(user['email'])
254 user_record = RegUser(hrn=user_hrn, gid=user_gid,
255 pointer=user['user_id'],
256 authority=get_authority(
260 user_record.reg_keys = [RegKey(pubkey)]
263 "No key found for user %s" % user_record)
264 user_record.just_created()
265 global_dbsession.add(user_record)
266 global_dbsession.commit()
268 "NitosImporter: imported user: %s" % user_record)
269 self.remember_record(user_record)
271 # update the record ?
272 # if user's primary key has changed then we need to update the
273 # users gid by forcing an update here
274 sfa_keys = user_record.reg_keys
276 def sfa_key_in_list(sfa_key, nitos_user_keys):
277 for nitos_key in nitos_user_keys:
278 if nitos_key == sfa_key:
281 # are all the SFA keys known to nitos ?
283 if not sfa_keys and user['keys']:
286 for sfa_key in sfa_keys:
287 if not sfa_key_in_list(sfa_key.key, user['keys']):
291 (pubkey, pkey) = init_user_key(user)
292 user_gid = self.auth_hierarchy.create_gid(
293 user_urn, create_uuid(), pkey)
295 user_record.reg_keys = []
297 user_record.reg_keys = [RegKey(pubkey)]
298 user_record.gid = user_gid
299 user_record.just_updated()
301 "NitosImporter: updated user: %s" % user_record)
302 user_record.email = user['email']
303 global_dbsession.commit()
304 user_record.stale = False
306 self.logger.log_exc("NitosImporter: failed to import user %s %s" % (
307 user['user_id'], user['email']))
311 slice_hrn = slicename_to_hrn(
312 interface_hrn, site['name'], slice['slice_name'])
313 slice_record = self.locate_by_type_hrn('slice', slice_hrn)
316 pkey = Keypair(create=True)
317 urn = hrn_to_urn(slice_hrn, 'slice')
318 slice_gid = self.auth_hierarchy.create_gid(
319 urn, create_uuid(), pkey)
320 slice_record = RegSlice(hrn=slice_hrn, gid=slice_gid,
321 pointer=slice['slice_id'],
322 authority=get_authority(slice_hrn))
323 slice_record.just_created()
324 global_dbsession.add(slice_record)
325 global_dbsession.commit()
327 "NitosImporter: imported slice: %s" % slice_record)
328 self.remember_record(slice_record)
331 "NitosImporter: failed to import slice")
333 # xxx update the record ...
334 self.logger.warning("Slice update not yet implemented")
336 # record current users affiliated with the slice
337 slice_record.reg_researchers = \
338 [self.locate_by_type_pointer('user', int(
339 user_id)) for user_id in slice['user_ids']]
340 global_dbsession.commit()
341 slice_record.stale = False
343 # remove stale records
344 # special records must be preserved
345 system_hrns = [interface_hrn, root_auth,
346 interface_hrn + '.slicemanager']
347 for record in all_records:
348 if record.hrn in system_hrns:
350 if record.peer_authority:
353 for record in all_records:
358 self.logger.warning("stale not found with %s" % record)
361 "NitosImporter: deleting stale record: %s" % record)
362 global_dbsession.delete(record)
363 global_dbsession.commit()