2 # Implements support for SFA records
4 # TODO: Use existing PLC database methods? or keep this separate?
7 from types import StringTypes
8 from sfa.trust.gid import GID
9 from sfa.storage.parameter import Parameter
10 from sfa.util.xrn import get_authority
11 from sfa.storage.row import Row
12 from sfa.util.xml import XML
13 from sfa.util.sfalogging import logger
17 The SfaRecord class implements an SFA Record. A SfaRecord is a tuple
18 (Hrn, GID, Type, Info).
20 Hrn specifies the Human Readable Name of the object
21 GID is the GID of the object
22 Type is user | authority | slice | component
24 Info is comprised of the following sub-fields
25 pointer = a pointer to the record in the PL database
27 The pointer is interpreted depending on the type of the record. For example,
28 if the type=="user", then pointer is assumed to be a person_id that indexes
29 into the persons table.
31 A given HRN may have more than one record, provided that the records are
36 # primary_key = 'record_id'
38 ### the wsdl generator assumes this is named 'fields'
40 'record_id': Parameter(int, "An id that uniquely identifies this record", ro=True),
41 'pointer': Parameter(int, "An id that uniquely identifies this record in an external database")
45 'authority': Parameter(str, "The authority for this record"),
46 'peer_authority': Parameter(str, "The peer authority for this record"),
47 'hrn': Parameter(str, "Human readable name of object"),
48 'gid': Parameter(str, "GID of the object"),
49 'type': Parameter(str, "Record type"),
50 'last_updated': Parameter(int, "Date and time of last update", ro=True),
51 'date_created': Parameter(int, "Date and time this record was created", ro=True),
53 all_fields = dict(fields.items() + internal_fields.items())
55 # Create an SFA Record
57 # @param name if !=None, assign the name of the record
58 # @param gid if !=None, assign the gid of the record
59 # @param type one of user | authority | slice | component
60 # @param pointer is a pointer to a PLC record
61 # @param dict if !=None, then fill in this record from the dictionary
63 def __init__(self, hrn=None, gid=None, type=None, pointer=None, authority=None,
64 peer_authority=None, dict=None, string=None):
70 self.set_peer_auth(peer_authority)
71 self.set_authority(authority)
79 self.set_pointer(pointer)
81 self.load_from_dict(dict)
83 self.load_from_string(string)
86 def validate_last_updated(self, last_updated):
87 return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
89 def update(self, new_dict):
90 if isinstance(new_dict, list):
91 new_dict = new_dict[0]
93 # Convert any boolean strings to real bools
95 if isinstance(new_dict[key], StringTypes):
96 if new_dict[key].lower() in ["true"]:
98 elif new_dict[key].lower() in ["false"]:
100 dict.update(self, new_dict)
103 # Set the name of the record
105 # @param hrn is a string containing the HRN
107 def set_name(self, hrn):
109 Set the name of the record
115 def set_authority(self, authority):
121 self.authority = authority
122 self['authority'] = authority
127 # Set the GID of the record
129 # @param gid is a GID object or the string representation of a GID object
131 def set_gid(self, gid):
133 Set the GID of the record
136 if isinstance(gid, StringTypes):
140 self.gid = gid.save_to_string(save_parents=True)
141 self['gid'] = gid.save_to_string(save_parents=True)
145 # Set the type of the record
147 # @param type is a string: user | authority | slice | component
149 def set_type(self, type):
151 Set the type of the record
158 # Set the pointer of the record
160 # @param pointer is an integer containing the ID of a PLC record
162 def set_pointer(self, pointer):
164 Set the pointer of the record
166 self.pointer = pointer
167 self['pointer'] = pointer
171 def set_peer_auth(self, peer_authority):
172 self.peer_authority = peer_authority
173 self['peer_authority'] = peer_authority
177 # Return the name (HRN) of the record
181 Return the name (HRN) of the record
186 # Return the type of the record
190 Return the type of the record
195 # Return the pointer of the record. The pointer is an integer that may be
196 # used to look up the record in the PLC database. The evaluation of pointer
197 # depends on the type of the record
199 def get_pointer(self):
201 Return the pointer of the record. The pointer is an integer that may be
202 used to look up the record in the PLC database. The evaluation of pointer
203 depends on the type of the record
208 # Return the GID of the record, in the form of a GID object
209 # TODO: not the best name for the function, because we have things called
210 # gidObjects in the Cred
212 def get_gid_object(self):
214 Return the GID of the record, in the form of a GID object
216 return GID(string=self.gid)
219 # Returns the value of a field
221 def get_field(self, fieldname, default=None):
222 # sometimes records act like classes, and sometimes they act like dicts
224 return getattr(self, fieldname)
225 except AttributeError:
227 return self[fieldname]
235 # Returns a list of field names in this record.
237 def get_field_names(self):
239 Returns a list of field names in this record.
241 return self.fields.keys()
244 # Given a field name ("hrn", "gid", ...) return the value of that field.
246 # @param fieldname is the name of field to be returned
248 def get_field_value_string(self, fieldname):
250 Given a field name ("hrn", "gid", ...) return the value of that field.
252 if fieldname == "authority":
253 val = get_authority(self['hrn'])
256 val = getattr(self, fieldname)
258 val = self[fieldname]
259 if isinstance(val, str):
260 return "'" + str(val) + "'"
265 # Given a list of field names, return a list of values for those public.
267 # @param fieldnames is a list of field names
269 def get_field_value_strings(self, fieldnames):
271 Given a list of field names, return a list of values for those public.
273 return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
276 # Return the record in the form of a dictionary
280 Return the record in the form of a dictionary
285 # Load the record from a dictionary
287 # @param dict dictionary to load record public from
289 def load_from_dict(self, dict):
291 Load the record from a dictionary
294 self.set_name(dict['hrn'])
295 gidstr = dict.get("gid", None)
297 self.set_gid(dict['gid'])
299 if "pointer" in dict:
300 self.set_pointer(dict['pointer'])
302 self.set_type(dict['type'])
306 # Save the record to a string. The string contains an XML representation of
309 def save_to_string(self):
311 Save the record to a string. The string contains an XML representation of
314 recorddict = self.as_dict()
315 filteredDict = dict([(key, val) for (key, val) in recorddict.iteritems() if key in self.fields.keys()])
316 xml_record = XML('<record/>')
317 xml_record.parse_dict(filteredDict)
318 str = xml_record.toxml()
322 # Load the record from a string. The string is assumed to contain an XML
323 # representation of the record.
325 def load_from_string(self, str):
327 Load the record from a string. The string is assumed to contain an XML
328 representation of the record.
330 #dict = xmlrpclib.loads(str)[0][0]
332 xml_record = XML(str)
333 self.load_from_dict(xml_record.todict())
336 # Dump the record to stdout
338 # @param dump_parents if true, then the parents of the GID will be dumped
340 def dump(self, dump_parents=False):
342 Walk tree and dump records.
344 #print "RECORD", self.name
345 #print " hrn:", self.name
346 #print " type:", self.type
351 # self.get_gid_object().dump(8, dump_parents)
352 #print " pointer:", self.pointer
354 order = SfaRecord.fields.keys()
355 for key in self.keys():
359 if key in self and key in self.fields:
360 if key in 'gid' and self[key]:
361 gid = GID(string=self[key])
363 gid.dump(8, dump_parents)
365 print " %s: %s" % (key, self[key])
367 def summary_string(self):
368 return "Record(record_id=%s, hrn=%s, type=%s, authority=%s, pointer=%s)" % \
369 (self.get('record_id'), self.get('hrn'), self.get('type'), self.get('authority'), \
377 Sync this record with the database.
379 from sfa.storage.table import SfaTable
382 if self.get('record_id'):
383 filter['record_id'] = self.get('record_id')
384 if self.get('hrn') and self.get('type'):
385 filter['hrn'] = self.get('hrn')
386 filter['type'] = self.get('type')
387 if self.get('pointer'):
388 filter['pointer'] = self.get('pointer')
389 existing_records = table.find(filter)
390 if not existing_records:
393 existing_record = existing_records[0]
394 self['record_id'] = existing_record['record_id']
399 Remove record from the database.
401 from sfa.storage.table import SfaTable
404 if self.get('record_id'):
405 filter['record_id'] = self.get('record_id')
406 if self.get('hrn') and self.get('type'):
407 filter['hrn'] = self.get('hrn')
408 filter['type'] = self.get('type')
409 if self.get('pointer'):
410 filter['pointer'] = self.get('pointer')
412 existing_records = table.find(filter)
413 for record in existing_records:
416 class UserRecord(SfaRecord):
419 'email': Parameter(str, 'email'),
420 'first_name': Parameter(str, 'First name'),
421 'last_name': Parameter(str, 'Last name'),
422 'phone': Parameter(str, 'Phone Number'),
423 'keys': Parameter(str, 'Public key'),
424 'slices': Parameter([str], 'List of slices this user belongs to'),
426 fields.update(SfaRecord.fields)
428 class SliceRecord(SfaRecord):
430 'name': Parameter(str, 'Slice name'),
431 'url': Parameter(str, 'Slice url'),
432 'expires': Parameter(int, 'Date and time this slice exipres'),
433 'researcher': Parameter([str], 'List of users for this slice'),
434 'PI': Parameter([str], 'List of PIs responsible for this slice'),
435 'description': Parameter([str], 'Description of this slice'),
437 fields.update(SfaRecord.fields)
440 class NodeRecord(SfaRecord):
442 'hostname': Parameter(str, 'This nodes dns name'),
443 'node_type': Parameter(str, 'Type of node this is'),
444 'latitude': Parameter(str, 'latitude'),
445 'longitude': Parameter(str, 'longitude'),
447 fields.update(SfaRecord.fields)
450 class AuthorityRecord(SfaRecord):
452 'name': Parameter(str, 'Name'),
453 'login_base': Parameter(str, 'login base'),
454 'enabled': Parameter(bool, 'Is this site enabled'),
455 'url': Parameter(str, 'URL'),
456 'nodes': Parameter([str], 'List of nodes at this site'),
457 'operator': Parameter([str], 'List of operators'),
458 'researcher': Parameter([str], 'List of researchers'),
459 'PI': Parameter([str], 'List of Principal Investigators'),
461 fields.update(SfaRecord.fields)