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.rspec import *
15 from sfa.util.parameter import *
16 from sfa.util.xrn import get_authority
17 from sfa.util.row import Row
21 The SfaRecord class implements an SFA Record. A SfaRecord is a tuple
22 (Hrn, GID, Type, Info).
24 Hrn specifies the Human Readable Name of the object
25 GID is the GID of the object
26 Type is user | authority | slice | component
28 Info is comprised of the following sub-fields
29 pointer = a pointer to the record in the PL database
31 The pointer is interpreted depending on the type of the record. For example,
32 if the type=="user", then pointer is assumed to be a person_id that indexes
33 into the persons table.
35 A given HRN may have more than one record, provided that the records are
41 primary_key = 'record_id'
43 ### the wsdl generator assumes this is named 'fields'
45 'record_id': Parameter(int, 'An id that uniquely identifies this record', ro=True),
46 'pointer': Parameter(int, 'An id that uniquely identifies this record in an external database ')
50 'authority': Parameter(str, "The authority for this record"),
51 'peer_authority': Parameter(str, "The peer authority for this record"),
52 'hrn': Parameter(str, "Human readable name of object"),
53 'gid': Parameter(str, "GID of the object"),
54 'type': Parameter(str, "Record type"),
55 'last_updated': Parameter(int, 'Date and time of last update', ro=True),
56 'date_created': Parameter(int, 'Date and time this record was created', ro=True),
58 all_fields = dict(fields.items() + internal_fields.items())
60 # Create an SFA Record
62 # @param name if !=None, assign the name of the record
63 # @param gid if !=None, assign the gid of the record
64 # @param type one of user | authority | slice | component
65 # @param pointer is a pointer to a PLC record
66 # @param dict if !=None, then fill in this record from the dictionary
68 def __init__(self, hrn=None, gid=None, type=None, pointer=None, peer_authority=None, dict=None, string=None):
74 self.set_peer_auth(peer_authority)
82 self.set_pointer(pointer)
84 self.load_from_dict(dict)
86 self.load_from_string(string)
89 def validate_last_updated(self, last_updated):
90 return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
92 def update(self, new_dict):
93 if isinstance(new_dict, list):
94 new_dict = new_dict[0]
96 # Convert any boolean strings to real bools
98 if isinstance(new_dict[key], StringTypes):
99 if new_dict[key].lower() in ["true"]:
101 elif new_dict[key].lower() in ["false"]:
102 new_dict[key] = False
103 dict.update(self, new_dict)
106 # Set the name of the record
108 # @param hrn is a string containing the HRN
110 def set_name(self, hrn):
112 Set the name of the record
119 # Set the GID of the record
121 # @param gid is a GID object or the string representation of a GID object
123 def set_gid(self, gid):
125 Set the GID of the record
128 if isinstance(gid, StringTypes):
132 self.gid = gid.save_to_string(save_parents=True)
133 self['gid'] = gid.save_to_string(save_parents=True)
137 # Set the type of the record
139 # @param type is a string: user | authority | slice | component
141 def set_type(self, type):
143 Set the type of the record
150 # Set the pointer of the record
152 # @param pointer is an integer containing the ID of a PLC record
154 def set_pointer(self, pointer):
156 Set the pointer of the record
158 self.pointer = pointer
159 self['pointer'] = pointer
163 def set_peer_auth(self, peer_authority):
164 self.peer_authority = peer_authority
165 self['peer_authority'] = peer_authority
169 # Return the name (HRN) of the record
173 Return the name (HRN) of the record
178 # Return the type of the record
182 Return the type of the record
187 # Return the pointer of the record. The pointer is an integer that may be
188 # used to look up the record in the PLC database. The evaluation of pointer
189 # depends on the type of the record
191 def get_pointer(self):
193 Return the pointer of the record. The pointer is an integer that may be
194 used to look up the record in the PLC database. The evaluation of pointer
195 depends on the type of the record
200 # Return the GID of the record, in the form of a GID object
201 # TODO: not the best name for the function, because we have things called
202 # gidObjects in the Cred
204 def get_gid_object(self):
206 Return the GID of the record, in the form of a GID object
208 return GID(string=self.gid)
211 # Returns the value of a field
213 def get_field(self, fieldname, default=None):
214 # sometimes records act like classes, and sometimes they act like dicts
216 return getattr(self, fieldname)
217 except AttributeError:
219 return self[fieldname]
227 # Returns a list of field names in this record.
229 def get_field_names(self):
231 Returns a list of field names in this record.
233 return self.fields.keys()
236 # Given a field name ("hrn", "gid", ...) return the value of that field.
238 # @param fieldname is the name of field to be returned
240 def get_field_value_string(self, fieldname):
242 Given a field name ("hrn", "gid", ...) return the value of that field.
244 if fieldname == "authority":
245 val = get_authority(self['hrn'])
248 val = getattr(self, fieldname)
250 val = self[fieldname]
251 if isinstance(val, str):
252 return "'" + str(val) + "'"
257 # Given a list of field names, return a list of values for those public.
259 # @param fieldnames is a list of field names
261 def get_field_value_strings(self, fieldnames):
263 Given a list of field names, return a list of values for those public.
265 return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
268 # Return the record in the form of a dictionary
272 Return the record in the form of a dictionary
277 # Load the record from a dictionary
279 # @param dict dictionary to load record public from
281 def load_from_dict(self, dict):
283 Load the record from a dictionary
285 self.set_name(dict['hrn'])
286 gidstr = dict.get("gid", None)
288 self.set_gid(dict['gid'])
290 if "pointer" in dict:
291 self.set_pointer(dict['pointer'])
293 self.set_type(dict['type'])
297 # Save the record to a string. The string contains an XML representation of
300 def save_to_string(self):
302 Save the record to a string. The string contains an XML representation of
305 recorddict = self.as_dict()
306 filteredDict = dict([(key, val) for (key, val) in recorddict.iteritems() if key in self.fields.keys()])
307 record = RecordSpec()
308 record.parseDict(filteredDict)
310 #str = xmlrpclib.dumps((dict,), allow_none=True)
314 # Load the record from a string. The string is assumed to contain an XML
315 # representation of the record.
317 def load_from_string(self, str):
319 Load the record from a string. The string is assumed to contain an XML
320 representation of the record.
322 #dict = xmlrpclib.loads(str)[0][0]
324 record = RecordSpec()
325 record.parseString(str)
326 record_dict = record.toDict()
327 sfa_dict = record_dict['record']
328 self.load_from_dict(sfa_dict)
331 # Dump the record to stdout
333 # @param dump_parents if true, then the parents of the GID will be dumped
335 def dump(self, dump_parents=False):
337 Walk tree and dump records.
339 #print "RECORD", self.name
340 #print " hrn:", self.name
341 #print " type:", self.type
346 # self.get_gid_object().dump(8, dump_parents)
347 #print " pointer:", self.pointer
349 order = SfaRecord.fields.keys()
350 for key in self.keys():
354 if key in self and key in self.fields:
355 if key in 'gid' and self[key]:
356 gid = GID(string=self[key])
358 gid.dump(8, dump_parents)
360 print " %s: %s" % (key, self[key])
366 class UserRecord(SfaRecord):
369 'email': Parameter(str, 'email'),
370 'first_name': Parameter(str, 'First name'),
371 'last_name': Parameter(str, 'Last name'),
372 'phone': Parameter(str, 'Phone Number'),
373 'keys': Parameter(str, 'Public key'),
374 'slices': Parameter([str], 'List of slices this user belongs to'),
376 fields.update(SfaRecord.fields)
378 class SliceRecord(SfaRecord):
380 'name': Parameter(str, 'Slice name'),
381 'url': Parameter(str, 'Slice url'),
382 'expires': Parameter(int, 'Date and time this slice exipres'),
383 'researcher': Parameter([str], 'List of users for this slice'),
384 'PI': Parameter([str], 'List of PIs responsible for this slice'),
385 'description': Parameter([str], 'Description of this slice'),
387 fields.update(SfaRecord.fields)
390 class NodeRecord(SfaRecord):
392 'hostname': Parameter(str, 'This nodes dns name'),
393 'node_type': Parameter(str, 'Type of node this is'),
394 'node_type': Parameter(str, 'Type of node this is'),
395 'latitude': Parameter(str, 'latitude'),
396 'longitude': Parameter(str, 'longitude'),
398 fields.update(SfaRecord.fields)
401 class AuthorityRecord(SfaRecord):
403 'name': Parameter(str, 'Name'),
404 'login_base': Parameter(str, 'login base'),
405 'enabled': Parameter(bool, 'Is this site enabled'),
406 'url': Parameter(str, 'URL'),
407 'nodes': Parameter([str], 'List of nodes at this site'),
408 'operator': Parameter([str], 'List of operators'),
409 'researcher': Parameter([str], 'List of researchers'),
410 'PI': Parameter([str], 'List of Principal Investigators'),
412 fields.update(SfaRecord.fields)