2 # Implements support for SFA records
4 # TODO: Use existing PLC database methods? or keep this separate?
10 from types import StringTypes
12 from sfa.trust.gid import *
14 from sfa.util.parameter import *
15 from sfa.util.xrn import get_authority
16 from sfa.util.row import Row
20 The SfaRecord class implements an SFA Record. A SfaRecord is a tuple
21 (Hrn, GID, Type, Info).
23 Hrn specifies the Human Readable Name of the object
24 GID is the GID of the object
25 Type is user | authority | slice | component
27 Info is comprised of the following sub-fields
28 pointer = a pointer to the record in the PL database
30 The pointer is interpreted depending on the type of the record. For example,
31 if the type=="user", then pointer is assumed to be a person_id that indexes
32 into the persons table.
34 A given HRN may have more than one record, provided that the records are
40 primary_key = 'record_id'
42 ### the wsdl generator assumes this is named 'fields'
44 'record_id': Parameter(int, 'An id that uniquely identifies this record', ro=True),
45 'pointer': Parameter(int, 'An id that uniquely identifies this record in an external database ')
49 'authority': Parameter(str, "The authority for this record"),
50 'peer_authority': Parameter(str, "The peer authority for this record"),
51 'hrn': Parameter(str, "Human readable name of object"),
52 'gid': Parameter(str, "GID of the object"),
53 'type': Parameter(str, "Record type"),
54 'last_updated': Parameter(int, 'Date and time of last update', ro=True),
55 'date_created': Parameter(int, 'Date and time this record was created', ro=True),
57 all_fields = dict(fields.items() + internal_fields.items())
59 # Create an SFA Record
61 # @param name if !=None, assign the name of the record
62 # @param gid if !=None, assign the gid of the record
63 # @param type one of user | authority | slice | component
64 # @param pointer is a pointer to a PLC record
65 # @param dict if !=None, then fill in this record from the dictionary
67 def __init__(self, hrn=None, gid=None, type=None, pointer=None, peer_authority=None, dict=None, string=None):
73 self.set_peer_auth(peer_authority)
81 self.set_pointer(pointer)
83 self.load_from_dict(dict)
85 self.load_from_string(string)
88 def validate_last_updated(self, last_updated):
89 return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
91 def update(self, new_dict):
92 if isinstance(new_dict, list):
93 new_dict = new_dict[0]
95 # Convert any boolean strings to real bools
97 if isinstance(new_dict[key], StringTypes):
98 if new_dict[key].lower() in ["true"]:
100 elif new_dict[key].lower() in ["false"]:
101 new_dict[key] = False
102 dict.update(self, new_dict)
105 # Set the name of the record
107 # @param hrn is a string containing the HRN
109 def set_name(self, hrn):
111 Set the name of the record
118 # Set the GID of the record
120 # @param gid is a GID object or the string representation of a GID object
122 def set_gid(self, gid):
124 Set the GID of the record
127 if isinstance(gid, StringTypes):
131 self.gid = gid.save_to_string(save_parents=True)
132 self['gid'] = gid.save_to_string(save_parents=True)
136 # Set the type of the record
138 # @param type is a string: user | authority | slice | component
140 def set_type(self, type):
142 Set the type of the record
149 # Set the pointer of the record
151 # @param pointer is an integer containing the ID of a PLC record
153 def set_pointer(self, pointer):
155 Set the pointer of the record
157 self.pointer = pointer
158 self['pointer'] = pointer
162 def set_peer_auth(self, peer_authority):
163 self.peer_authority = peer_authority
164 self['peer_authority'] = peer_authority
168 # Return the name (HRN) of the record
172 Return the name (HRN) of the record
177 # Return the type of the record
181 Return the type of the record
186 # Return the pointer of the record. The pointer is an integer that may be
187 # used to look up the record in the PLC database. The evaluation of pointer
188 # depends on the type of the record
190 def get_pointer(self):
192 Return the pointer of the record. The pointer is an integer that may be
193 used to look up the record in the PLC database. The evaluation of pointer
194 depends on the type of the record
199 # Return the GID of the record, in the form of a GID object
200 # TODO: not the best name for the function, because we have things called
201 # gidObjects in the Cred
203 def get_gid_object(self):
205 Return the GID of the record, in the form of a GID object
207 return GID(string=self.gid)
210 # Returns the value of a field
212 def get_field(self, fieldname, default=None):
213 # sometimes records act like classes, and sometimes they act like dicts
215 return getattr(self, fieldname)
216 except AttributeError:
218 return self[fieldname]
226 # Returns a list of field names in this record.
228 def get_field_names(self):
230 Returns a list of field names in this record.
232 return self.fields.keys()
235 # Given a field name ("hrn", "gid", ...) return the value of that field.
237 # @param fieldname is the name of field to be returned
239 def get_field_value_string(self, fieldname):
241 Given a field name ("hrn", "gid", ...) return the value of that field.
243 if fieldname == "authority":
244 val = get_authority(self['hrn'])
247 val = getattr(self, fieldname)
249 val = self[fieldname]
250 if isinstance(val, str):
251 return "'" + str(val) + "'"
256 # Given a list of field names, return a list of values for those public.
258 # @param fieldnames is a list of field names
260 def get_field_value_strings(self, fieldnames):
262 Given a list of field names, return a list of values for those public.
264 return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
267 # Return the record in the form of a dictionary
271 Return the record in the form of a dictionary
276 # Load the record from a dictionary
278 # @param dict dictionary to load record public from
280 def load_from_dict(self, dict):
282 Load the record from a dictionary
284 self.set_name(dict['hrn'])
285 gidstr = dict.get("gid", None)
287 self.set_gid(dict['gid'])
289 if "pointer" in dict:
290 self.set_pointer(dict['pointer'])
292 self.set_type(dict['type'])
296 # Save the record to a string. The string contains an XML representation of
299 def save_to_string(self):
301 Save the record to a string. The string contains an XML representation of
304 recorddict = self.as_dict()
305 filteredDict = dict([(key, val) for (key, val) in recorddict.iteritems() if key in self.fields.keys()])
306 record = RecordSpec()
307 record.parseDict(filteredDict)
309 #str = xmlrpclib.dumps((dict,), allow_none=True)
313 # Load the record from a string. The string is assumed to contain an XML
314 # representation of the record.
316 def load_from_string(self, str):
318 Load the record from a string. The string is assumed to contain an XML
319 representation of the record.
321 #dict = xmlrpclib.loads(str)[0][0]
323 record = RecordSpec()
324 record.parseString(str)
325 record_dict = record.toDict()
326 sfa_dict = record_dict['record']
327 self.load_from_dict(sfa_dict)
330 # Dump the record to stdout
332 # @param dump_parents if true, then the parents of the GID will be dumped
334 def dump(self, dump_parents=False):
336 Walk tree and dump records.
338 #print "RECORD", self.name
339 #print " hrn:", self.name
340 #print " type:", self.type
345 # self.get_gid_object().dump(8, dump_parents)
346 #print " pointer:", self.pointer
348 order = SfaRecord.fields.keys()
349 for key in self.keys():
353 if key in self and key in self.fields:
354 if key in 'gid' and self[key]:
355 gid = GID(string=self[key])
357 gid.dump(8, dump_parents)
359 print " %s: %s" % (key, self[key])
365 class UserRecord(SfaRecord):
368 'email': Parameter(str, 'email'),
369 'first_name': Parameter(str, 'First name'),
370 'last_name': Parameter(str, 'Last name'),
371 'phone': Parameter(str, 'Phone Number'),
372 'keys': Parameter(str, 'Public key'),
373 'slices': Parameter([str], 'List of slices this user belongs to'),
375 fields.update(SfaRecord.fields)
377 class SliceRecord(SfaRecord):
379 'name': Parameter(str, 'Slice name'),
380 'url': Parameter(str, 'Slice url'),
381 'expires': Parameter(int, 'Date and time this slice exipres'),
382 'researcher': Parameter([str], 'List of users for this slice'),
383 'PI': Parameter([str], 'List of PIs responsible for this slice'),
384 'description': Parameter([str], 'Description of this slice'),
386 fields.update(SfaRecord.fields)
389 class NodeRecord(SfaRecord):
391 'hostname': Parameter(str, 'This nodes dns name'),
392 'node_type': Parameter(str, 'Type of node this is'),
393 'node_type': Parameter(str, 'Type of node this is'),
394 'latitude': Parameter(str, 'latitude'),
395 'longitude': Parameter(str, 'longitude'),
397 fields.update(SfaRecord.fields)
400 class AuthorityRecord(SfaRecord):
402 'name': Parameter(str, 'Name'),
403 'login_base': Parameter(str, 'login base'),
404 'enabled': Parameter(bool, 'Is this site enabled'),
405 'url': Parameter(str, 'URL'),
406 'nodes': Parameter([str], 'List of nodes at this site'),
407 'operator': Parameter([str], 'List of operators'),
408 'researcher': Parameter([str], 'List of researchers'),
409 'PI': Parameter([str], 'List of Principal Investigators'),
411 fields.update(SfaRecord.fields)