2 # Implements support for SFA records
4 # TODO: Use existing PLC database methods? or keep this separate?
7 from types import StringTypes
9 from sfa.trust.gid import GID
11 from sfa.util.parameter import Parameter
12 from sfa.util.xrn import get_authority
13 from sfa.util.row import Row
14 from sfa.util.xml import XML
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
38 primary_key = 'record_id'
40 ### the wsdl generator assumes this is named 'fields'
42 'record_id': Parameter(int, 'An id that uniquely identifies this record', ro=True),
43 'pointer': Parameter(int, 'An id that uniquely identifies this record in an external database ')
47 'authority': Parameter(str, "The authority for this record"),
48 'peer_authority': Parameter(str, "The peer authority for this record"),
49 'hrn': Parameter(str, "Human readable name of object"),
50 'gid': Parameter(str, "GID of the object"),
51 'type': Parameter(str, "Record type"),
52 'last_updated': Parameter(int, 'Date and time of last update', ro=True),
53 'date_created': Parameter(int, 'Date and time this record was created', ro=True),
55 all_fields = dict(fields.items() + internal_fields.items())
57 # Create an SFA Record
59 # @param name if !=None, assign the name of the record
60 # @param gid if !=None, assign the gid of the record
61 # @param type one of user | authority | slice | component
62 # @param pointer is a pointer to a PLC record
63 # @param dict if !=None, then fill in this record from the dictionary
65 def __init__(self, hrn=None, gid=None, type=None, pointer=None, peer_authority=None, dict=None, string=None):
71 self.set_peer_auth(peer_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
116 # Set the GID of the record
118 # @param gid is a GID object or the string representation of a GID object
120 def set_gid(self, gid):
122 Set the GID of the record
125 if isinstance(gid, StringTypes):
129 self.gid = gid.save_to_string(save_parents=True)
130 self['gid'] = gid.save_to_string(save_parents=True)
134 # Set the type of the record
136 # @param type is a string: user | authority | slice | component
138 def set_type(self, type):
140 Set the type of the record
147 # Set the pointer of the record
149 # @param pointer is an integer containing the ID of a PLC record
151 def set_pointer(self, pointer):
153 Set the pointer of the record
155 self.pointer = pointer
156 self['pointer'] = pointer
160 def set_peer_auth(self, peer_authority):
161 self.peer_authority = peer_authority
162 self['peer_authority'] = peer_authority
166 # Return the name (HRN) of the record
170 Return the name (HRN) of the record
175 # Return the type of the record
179 Return the type of the record
184 # Return the pointer of the record. The pointer is an integer that may be
185 # used to look up the record in the PLC database. The evaluation of pointer
186 # depends on the type of the record
188 def get_pointer(self):
190 Return the pointer of the record. The pointer is an integer that may be
191 used to look up the record in the PLC database. The evaluation of pointer
192 depends on the type of the record
197 # Return the GID of the record, in the form of a GID object
198 # TODO: not the best name for the function, because we have things called
199 # gidObjects in the Cred
201 def get_gid_object(self):
203 Return the GID of the record, in the form of a GID object
205 return GID(string=self.gid)
208 # Returns the value of a field
210 def get_field(self, fieldname, default=None):
211 # sometimes records act like classes, and sometimes they act like dicts
213 return getattr(self, fieldname)
214 except AttributeError:
216 return self[fieldname]
224 # Returns a list of field names in this record.
226 def get_field_names(self):
228 Returns a list of field names in this record.
230 return self.fields.keys()
233 # Given a field name ("hrn", "gid", ...) return the value of that field.
235 # @param fieldname is the name of field to be returned
237 def get_field_value_string(self, fieldname):
239 Given a field name ("hrn", "gid", ...) return the value of that field.
241 if fieldname == "authority":
242 val = get_authority(self['hrn'])
245 val = getattr(self, fieldname)
247 val = self[fieldname]
248 if isinstance(val, str):
249 return "'" + str(val) + "'"
254 # Given a list of field names, return a list of values for those public.
256 # @param fieldnames is a list of field names
258 def get_field_value_strings(self, fieldnames):
260 Given a list of field names, return a list of values for those public.
262 return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
265 # Return the record in the form of a dictionary
269 Return the record in the form of a dictionary
274 # Load the record from a dictionary
276 # @param dict dictionary to load record public from
278 def load_from_dict(self, dict):
280 Load the record from a dictionary
282 self.set_name(dict['hrn'])
283 gidstr = dict.get("gid", None)
285 self.set_gid(dict['gid'])
287 if "pointer" in dict:
288 self.set_pointer(dict['pointer'])
290 self.set_type(dict['type'])
294 # Save the record to a string. The string contains an XML representation of
297 def save_to_string(self):
299 Save the record to a string. The string contains an XML representation of
302 recorddict = self.as_dict()
303 filteredDict = dict([(key, val) for (key, val) in recorddict.iteritems() if key in self.fields.keys()])
304 record = XML('<record/>')
305 record.root.attrib.update(filteredDict)
310 # Load the record from a string. The string is assumed to contain an XML
311 # representation of the record.
313 def load_from_string(self, str):
315 Load the record from a string. The string is assumed to contain an XML
316 representation of the record.
318 #dict = xmlrpclib.loads(str)[0][0]
321 self.load_from_dict(record.todict())
324 # Dump the record to stdout
326 # @param dump_parents if true, then the parents of the GID will be dumped
328 def dump(self, dump_parents=False):
330 Walk tree and dump records.
332 #print "RECORD", self.name
333 #print " hrn:", self.name
334 #print " type:", self.type
339 # self.get_gid_object().dump(8, dump_parents)
340 #print " pointer:", self.pointer
342 order = SfaRecord.fields.keys()
343 for key in self.keys():
347 if key in self and key in self.fields:
348 if key in 'gid' and self[key]:
349 gid = GID(string=self[key])
351 gid.dump(8, dump_parents)
353 print " %s: %s" % (key, self[key])
359 class UserRecord(SfaRecord):
362 'email': Parameter(str, 'email'),
363 'first_name': Parameter(str, 'First name'),
364 'last_name': Parameter(str, 'Last name'),
365 'phone': Parameter(str, 'Phone Number'),
366 'keys': Parameter(str, 'Public key'),
367 'slices': Parameter([str], 'List of slices this user belongs to'),
369 fields.update(SfaRecord.fields)
371 class SliceRecord(SfaRecord):
373 'name': Parameter(str, 'Slice name'),
374 'url': Parameter(str, 'Slice url'),
375 'expires': Parameter(int, 'Date and time this slice exipres'),
376 'researcher': Parameter([str], 'List of users for this slice'),
377 'PI': Parameter([str], 'List of PIs responsible for this slice'),
378 'description': Parameter([str], 'Description of this slice'),
380 fields.update(SfaRecord.fields)
383 class NodeRecord(SfaRecord):
385 'hostname': Parameter(str, 'This nodes dns name'),
386 'node_type': Parameter(str, 'Type of node this is'),
387 'node_type': Parameter(str, 'Type of node this is'),
388 'latitude': Parameter(str, 'latitude'),
389 'longitude': Parameter(str, 'longitude'),
391 fields.update(SfaRecord.fields)
394 class AuthorityRecord(SfaRecord):
396 'name': Parameter(str, 'Name'),
397 'login_base': Parameter(str, 'login base'),
398 'enabled': Parameter(bool, 'Is this site enabled'),
399 'url': Parameter(str, 'URL'),
400 'nodes': Parameter([str], 'List of nodes at this site'),
401 'operator': Parameter([str], 'List of operators'),
402 'researcher': Parameter([str], 'List of researchers'),
403 'PI': Parameter([str], 'List of Principal Investigators'),
405 fields.update(SfaRecord.fields)