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
14 from sfa.util.sfatime import utcparse, datetime_to_string
18 The SfaRecord class implements an SFA Record. A SfaRecord is a tuple
19 (Hrn, GID, Type, Info).
21 Hrn specifies the Human Readable Name of the object
22 GID is the GID of the object
23 Type is user | authority | slice | component
25 Info is comprised of the following sub-fields
26 pointer = a pointer to the record in the PL database
28 The pointer is interpreted depending on the type of the record. For example,
29 if the type=="user", then pointer is assumed to be a person_id that indexes
30 into the persons table.
32 A given HRN may have more than one record, provided that the records are
37 # primary_key = 'record_id'
39 ### the wsdl generator assumes this is named 'fields'
41 'record_id': Parameter(int, "An id that uniquely identifies this record", ro=True),
42 'pointer': Parameter(int, "An id that uniquely identifies this record in an external database")
46 'authority': Parameter(str, "The authority for this record"),
47 'peer_authority': Parameter(str, "The peer authority for this record"),
48 'hrn': Parameter(str, "Human readable name of object"),
49 'gid': Parameter(str, "GID of the object"),
50 'type': Parameter(str, "Record type"),
51 'last_updated': Parameter(int, "Date and time of last update", ro=True),
52 'date_created': Parameter(int, "Date and time this record was created", ro=True),
54 all_fields = dict(fields.items() + internal_fields.items())
56 # Create an SFA Record
58 # @param name if !=None, assign the name of the record
59 # @param gid if !=None, assign the gid of the record
60 # @param type one of user | authority | slice | component
61 # @param pointer is a pointer to a PLC record
62 # @param dict if !=None, then fill in this record from the dictionary
64 def __init__(self, hrn=None, gid=None, type=None, pointer=None, authority=None,
65 peer_authority=None, dict=None, string=None):
71 self.set_peer_auth(peer_authority)
72 self.set_authority(authority)
80 self.set_pointer(pointer)
82 self.load_from_dict(dict)
84 self.load_from_string(string)
87 def validate_last_updated(self, last_updated):
88 return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
90 def update(self, new_dict):
91 if isinstance(new_dict, list):
92 new_dict = new_dict[0]
94 # Convert any boolean strings to real bools
96 if isinstance(new_dict[key], StringTypes):
97 if new_dict[key].lower() in ["true"]:
99 elif new_dict[key].lower() in ["false"]:
100 new_dict[key] = False
101 dict.update(self, new_dict)
104 # Set the name of the record
106 # @param hrn is a string containing the HRN
108 def set_name(self, hrn):
110 Set the name of the record
116 def set_authority(self, authority):
122 self.authority = authority
123 self['authority'] = authority
128 # Set the GID of the record
130 # @param gid is a GID object or the string representation of a GID object
132 def set_gid(self, gid):
134 Set the GID of the record
137 if isinstance(gid, StringTypes):
141 self.gid = gid.save_to_string(save_parents=True)
142 self['gid'] = gid.save_to_string(save_parents=True)
146 # Set the type of the record
148 # @param type is a string: user | authority | slice | component
150 def set_type(self, type):
152 Set the type of the record
159 # Set the pointer of the record
161 # @param pointer is an integer containing the ID of a PLC record
163 def set_pointer(self, pointer):
165 Set the pointer of the record
167 self.pointer = pointer
168 self['pointer'] = pointer
172 def set_peer_auth(self, peer_authority):
173 self.peer_authority = peer_authority
174 self['peer_authority'] = peer_authority
178 # Return the name (HRN) of the record
182 Return the name (HRN) of the record
187 # Return the type of the record
191 Return the type of the record
196 # Return the pointer of the record. The pointer is an integer that may be
197 # used to look up the record in the PLC database. The evaluation of pointer
198 # depends on the type of the record
200 def get_pointer(self):
202 Return the pointer of the record. The pointer is an integer that may be
203 used to look up the record in the PLC database. The evaluation of pointer
204 depends on the type of the record
209 # Return the GID of the record, in the form of a GID object
210 # TODO: not the best name for the function, because we have things called
211 # gidObjects in the Cred
213 def get_gid_object(self):
215 Return the GID of the record, in the form of a GID object
217 return GID(string=self.gid)
220 # Returns the value of a field
222 def get_field(self, fieldname, default=None):
223 # sometimes records act like classes, and sometimes they act like dicts
225 return getattr(self, fieldname)
226 except AttributeError:
228 return self[fieldname]
236 # Returns a list of field names in this record.
238 def get_field_names(self):
240 Returns a list of field names in this record.
242 return self.fields.keys()
245 # Given a field name ("hrn", "gid", ...) return the value of that field.
247 # @param fieldname is the name of field to be returned
249 def get_field_value_string(self, fieldname):
251 Given a field name ("hrn", "gid", ...) return the value of that field.
253 if fieldname == "authority":
254 val = get_authority(self['hrn'])
257 val = getattr(self, fieldname)
259 val = self[fieldname]
260 if isinstance(val, str):
261 return "'" + str(val) + "'"
266 # Given a list of field names, return a list of values for those public.
268 # @param fieldnames is a list of field names
270 def get_field_value_strings(self, fieldnames):
272 Given a list of field names, return a list of values for those public.
274 return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
277 # Return the record in the form of a dictionary
281 Return the record in the form of a dictionary
286 # Load the record from a dictionary
288 # @param dict dictionary to load record public from
290 def load_from_dict(self, dict):
292 Load the record from a dictionary
295 self.set_name(dict['hrn'])
296 gidstr = dict.get("gid", None)
298 self.set_gid(dict['gid'])
300 if "pointer" in dict:
301 self.set_pointer(dict['pointer'])
303 self.set_type(dict['type'])
307 # Save the record to a string. The string contains an XML representation of
310 def save_to_string(self):
312 Save the record to a string. The string contains an XML representation of
315 recorddict = self.as_dict()
316 filteredDict = dict([(key, val) for (key, val) in recorddict.iteritems() if key in self.fields.keys()])
317 xml_record = XML('<record/>')
318 xml_record.parse_dict(filteredDict)
319 str = xml_record.toxml()
323 # Load the record from a string. The string is assumed to contain an XML
324 # representation of the record.
326 def load_from_string(self, str):
328 Load the record from a string. The string is assumed to contain an XML
329 representation of the record.
331 #dict = xmlrpclib.loads(str)[0][0]
333 xml_record = XML(str)
334 self.load_from_dict(xml_record.todict())
337 # Dump the record to stdout
339 # @param dump_parents if true, then the parents of the GID will be dumped
341 def dump_text(self, dump_parents=False):
343 Walk tree and dump records.
345 # print core fields in this order
346 print "".join(['=' for i in range(40)])
348 print " hrn:", self.get('hrn')
349 print " type:", self.get('type')
350 print " authority:", self.get('authority')
351 date_created = utcparse(datetime_to_string(self.get('date_created')))
352 print " date created:", date_created
353 last_updated = utcparse(datetime_to_string(self.get('last_updated')))
354 print " last updated:", last_updated
356 print "\t\t", self.get_gid_object().dump_string(8, dump_parents)
358 # print remaining fields
359 all_fields = set(UserRecord.fields.keys() +
360 AuthorityRecord.fields.keys() +
361 SliceRecord.fields.keys() +
362 NodeRecord.fields.keys())
364 # dont print core fields
365 if field in all_fields and field not in SfaRecord.fields:
366 print " %s: %s" % (field, self[field])
368 def dump(self, format=None, dump_parents=False):
372 format = format.lower()
375 self.dump_text(dump_parents)
376 elif format == 'xml':
377 print self.save_to_string()
378 elif format == 'summary':
379 print self.summary_string()
381 raise Exception, "Invalid format %s" % format
383 def summary_string(self):
384 return "Record(record_id=%s, hrn=%s, type=%s, authority=%s, pointer=%s)" % \
385 (self.get('record_id'), self.get('hrn'), self.get('type'), self.get('authority'), \
393 Sync this record with the database.
395 from sfa.storage.table import SfaTable
398 if self.get('record_id'):
399 filter['record_id'] = self.get('record_id')
400 if self.get('hrn') and self.get('type'):
401 filter['hrn'] = self.get('hrn')
402 filter['type'] = self.get('type')
403 if self.get('pointer'):
404 filter['pointer'] = self.get('pointer')
405 existing_records = table.find(filter)
406 if not existing_records:
409 existing_record = existing_records[0]
410 self['record_id'] = existing_record['record_id']
415 Remove record from the database.
417 from sfa.storage.table import SfaTable
420 if self.get('record_id'):
421 filter['record_id'] = self.get('record_id')
422 if self.get('hrn') and self.get('type'):
423 filter['hrn'] = self.get('hrn')
424 filter['type'] = self.get('type')
425 if self.get('pointer'):
426 filter['pointer'] = self.get('pointer')
428 existing_records = table.find(filter)
429 for record in existing_records:
432 class UserRecord(SfaRecord):
435 'email': Parameter(str, 'email'),
436 'first_name': Parameter(str, 'First name'),
437 'last_name': Parameter(str, 'Last name'),
438 'phone': Parameter(str, 'Phone Number'),
439 'keys': Parameter(str, 'Public key'),
440 'slices': Parameter([str], 'List of slices this user belongs to'),
442 fields.update(SfaRecord.fields)
444 class SliceRecord(SfaRecord):
446 'name': Parameter(str, 'Slice name'),
447 'url': Parameter(str, 'Slice url'),
448 'expires': Parameter(int, 'Date and time this slice exipres'),
449 'researcher': Parameter([str], 'List of users for this slice'),
450 'PI': Parameter([str], 'List of PIs responsible for this slice'),
451 'description': Parameter([str], 'Description of this slice'),
453 fields.update(SfaRecord.fields)
456 class NodeRecord(SfaRecord):
458 'hostname': Parameter(str, 'This nodes dns name'),
459 'node_type': Parameter(str, 'Type of node this is'),
460 'latitude': Parameter(str, 'latitude'),
461 'longitude': Parameter(str, 'longitude'),
463 fields.update(SfaRecord.fields)
466 class AuthorityRecord(SfaRecord):
468 'name': Parameter(str, 'Name'),
469 'login_base': Parameter(str, 'login base'),
470 'enabled': Parameter(bool, 'Is this site enabled'),
471 'url': Parameter(str, 'URL'),
472 'nodes': Parameter([str], 'List of nodes at this site'),
473 'operator': Parameter([str], 'List of operators'),
474 'researcher': Parameter([str], 'List of researchers'),
475 'PI': Parameter([str], 'List of Principal Investigators'),
477 fields.update(SfaRecord.fields)