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
17 from sfa.util.xml import XML
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 = XML('<record/>')
308 record.root.attrib.update(filteredDict)
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]
324 self.load_from_dict(record.root.attrib)
327 # Dump the record to stdout
329 # @param dump_parents if true, then the parents of the GID will be dumped
331 def dump(self, dump_parents=False):
333 Walk tree and dump records.
335 #print "RECORD", self.name
336 #print " hrn:", self.name
337 #print " type:", self.type
342 # self.get_gid_object().dump(8, dump_parents)
343 #print " pointer:", self.pointer
345 order = SfaRecord.fields.keys()
346 for key in self.keys():
350 if key in self and key in self.fields:
351 if key in 'gid' and self[key]:
352 gid = GID(string=self[key])
354 gid.dump(8, dump_parents)
356 print " %s: %s" % (key, self[key])
362 class UserRecord(SfaRecord):
365 'email': Parameter(str, 'email'),
366 'first_name': Parameter(str, 'First name'),
367 'last_name': Parameter(str, 'Last name'),
368 'phone': Parameter(str, 'Phone Number'),
369 'keys': Parameter(str, 'Public key'),
370 'slices': Parameter([str], 'List of slices this user belongs to'),
372 fields.update(SfaRecord.fields)
374 class SliceRecord(SfaRecord):
376 'name': Parameter(str, 'Slice name'),
377 'url': Parameter(str, 'Slice url'),
378 'expires': Parameter(int, 'Date and time this slice exipres'),
379 'researcher': Parameter([str], 'List of users for this slice'),
380 'PI': Parameter([str], 'List of PIs responsible for this slice'),
381 'description': Parameter([str], 'Description of this slice'),
383 fields.update(SfaRecord.fields)
386 class NodeRecord(SfaRecord):
388 'hostname': Parameter(str, 'This nodes dns name'),
389 'node_type': Parameter(str, 'Type of node this is'),
390 'node_type': Parameter(str, 'Type of node this is'),
391 'latitude': Parameter(str, 'latitude'),
392 'longitude': Parameter(str, 'longitude'),
394 fields.update(SfaRecord.fields)
397 class AuthorityRecord(SfaRecord):
399 'name': Parameter(str, 'Name'),
400 'login_base': Parameter(str, 'login base'),
401 'enabled': Parameter(bool, 'Is this site enabled'),
402 'url': Parameter(str, 'URL'),
403 'nodes': Parameter([str], 'List of nodes at this site'),
404 'operator': Parameter([str], 'List of operators'),
405 'researcher': Parameter([str], 'List of researchers'),
406 'PI': Parameter([str], 'List of Principal Investigators'),
408 fields.update(SfaRecord.fields)