removed imports on sfa.util.rspec that is gone
[sfa.git] / sfa / util / record.py
1 ##
2 # Implements support for SFA records
3 #
4 # TODO: Use existing PLC database methods? or keep this separate?
5 ##
6
7 ### $Id$
8 ### $URL$
9
10 from types import StringTypes
11
12 from sfa.trust.gid import *
13
14 from sfa.util.parameter import *
15 from sfa.util.xrn import get_authority
16 from sfa.util.row import Row
17
18 class SfaRecord(Row):
19     """ 
20     The SfaRecord class implements an SFA Record. A SfaRecord is a tuple
21     (Hrn, GID, Type, Info).
22  
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
26  
27     Info is comprised of the following sub-fields
28            pointer = a pointer to the record in the PL database
29  
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.
33  
34     A given HRN may have more than one record, provided that the records are
35     of different types.
36     """
37
38     table_name = 'sfa'
39     
40     primary_key = 'record_id'
41
42     ### the wsdl generator assumes this is named 'fields'
43     internal_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 ')
46     }
47
48     fields = {
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),
56     }
57     all_fields = dict(fields.items() + internal_fields.items())
58     ##
59     # Create an SFA Record
60     #
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
66
67     def __init__(self, hrn=None, gid=None, type=None, pointer=None, peer_authority=None, dict=None, string=None):
68         self.dirty = True
69         self.hrn = None
70         self.gid = None
71         self.type = None
72         self.pointer = None
73         self.set_peer_auth(peer_authority)
74         if hrn:
75             self.set_name(hrn)
76         if gid:
77             self.set_gid(gid)
78         if type:
79             self.set_type(type)
80         if pointer:
81             self.set_pointer(pointer)
82         if dict:
83             self.load_from_dict(dict)
84         if string:
85             self.load_from_string(string)
86
87
88     def validate_last_updated(self, last_updated):
89         return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
90         
91     def update(self, new_dict):
92         if isinstance(new_dict, list):
93             new_dict = new_dict[0]
94
95         # Convert any boolean strings to real bools
96         for key in new_dict:
97             if isinstance(new_dict[key], StringTypes):
98                 if new_dict[key].lower() in ["true"]:
99                     new_dict[key] = True
100                 elif new_dict[key].lower() in ["false"]:
101                     new_dict[key] = False
102         dict.update(self, new_dict)
103
104     ##
105     # Set the name of the record
106     #
107     # @param hrn is a string containing the HRN
108
109     def set_name(self, hrn):
110         """
111         Set the name of the record
112         """
113         self.hrn = hrn
114         self['hrn'] = hrn
115         self.dirty = True
116
117     ##
118     # Set the GID of the record
119     #
120     # @param gid is a GID object or the string representation of a GID object
121
122     def set_gid(self, gid):
123         """
124         Set the GID of the record
125         """
126
127         if isinstance(gid, StringTypes):
128             self.gid = gid
129             self['gid'] = gid
130         else:
131             self.gid = gid.save_to_string(save_parents=True)
132             self['gid'] = gid.save_to_string(save_parents=True)
133         self.dirty = True
134
135     ##
136     # Set the type of the record
137     #
138     # @param type is a string: user | authority | slice | component
139
140     def set_type(self, type):
141         """
142         Set the type of the record
143         """
144         self.type = type
145         self['type'] = type
146         self.dirty = True
147
148     ##
149     # Set the pointer of the record
150     #
151     # @param pointer is an integer containing the ID of a PLC record
152
153     def set_pointer(self, pointer):
154         """
155         Set the pointer of the record
156         """
157         self.pointer = pointer
158         self['pointer'] = pointer
159         self.dirty = True
160
161
162     def set_peer_auth(self, peer_authority):
163         self.peer_authority = peer_authority
164         self['peer_authority'] = peer_authority
165         self.dirty = True
166
167     ##
168     # Return the name (HRN) of the record
169
170     def get_name(self):
171         """
172         Return the name (HRN) of the record
173         """
174         return self.hrn
175
176     ##
177     # Return the type of the record
178
179     def get_type(self):
180         """
181         Return the type of the record
182         """
183         return self.type
184
185     ##
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
189
190     def get_pointer(self):
191         """
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
195         """
196         return self.pointer
197
198     ##
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
202
203     def get_gid_object(self):
204         """
205         Return the GID of the record, in the form of a GID object
206         """
207         return GID(string=self.gid)
208
209     ##
210     # Returns the value of a field
211
212     def get_field(self, fieldname, default=None):
213         # sometimes records act like classes, and sometimes they act like dicts
214         try:
215             return getattr(self, fieldname)
216         except AttributeError:
217             try:
218                  return self[fieldname]
219             except KeyError:
220                  if default != None:
221                      return default
222                  else:
223                      raise
224
225     ##
226     # Returns a list of field names in this record. 
227
228     def get_field_names(self):
229         """
230         Returns a list of field names in this record.
231         """
232         return self.fields.keys()
233
234     ##
235     # Given a field name ("hrn", "gid", ...) return the value of that field.
236     #
237     # @param fieldname is the name of field to be returned
238
239     def get_field_value_string(self, fieldname):
240         """
241         Given a field name ("hrn", "gid", ...) return the value of that field.
242         """
243         if fieldname == "authority":
244             val = get_authority(self['hrn'])
245         else:
246             try:
247                 val = getattr(self, fieldname)
248             except:
249                 val = self[fieldname] 
250         if isinstance(val, str):
251             return "'" + str(val) + "'"
252         else:
253             return str(val)
254
255     ##
256     # Given a list of field names, return a list of values for those public.
257     #
258     # @param fieldnames is a list of field names
259
260     def get_field_value_strings(self, fieldnames):
261         """
262         Given a list of field names, return a list of values for those public.
263         """
264         return [ self.get_field_value_string (fieldname) for fieldname in fieldnames ]
265
266     ##
267     # Return the record in the form of a dictionary
268
269     def as_dict(self):
270         """
271         Return the record in the form of a dictionary
272         """
273         return dict(self)
274
275     ##
276     # Load the record from a dictionary
277     #
278     # @param dict dictionary to load record public from
279
280     def load_from_dict(self, dict):
281         """
282         Load the record from a dictionary 
283         """
284         self.set_name(dict['hrn'])
285         gidstr = dict.get("gid", None)
286         if gidstr:
287             self.set_gid(dict['gid'])
288
289         if "pointer" in dict:
290            self.set_pointer(dict['pointer'])
291
292         self.set_type(dict['type'])
293         self.update(dict)        
294     
295     ##
296     # Save the record to a string. The string contains an XML representation of
297     # the record.
298
299     def save_to_string(self):
300         """
301         Save the record to a string. The string contains an XML representation of
302         the record.
303         """
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)
308         str = record.toxml()
309         #str = xmlrpclib.dumps((dict,), allow_none=True)
310         return str
311
312     ##
313     # Load the record from a string. The string is assumed to contain an XML
314     # representation of the record.
315
316     def load_from_string(self, str):
317         """
318         Load the record from a string. The string is assumed to contain an XML
319         representation of the record.
320         """
321         #dict = xmlrpclib.loads(str)[0][0]
322         
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)
328
329     ##
330     # Dump the record to stdout
331     #
332     # @param dump_parents if true, then the parents of the GID will be dumped
333
334     def dump(self, dump_parents=False):
335         """
336         Walk tree and dump records.
337         """
338         #print "RECORD", self.name
339         #print "        hrn:", self.name
340         #print "       type:", self.type
341         #print "        gid:"
342         #if (not self.gid):
343         #    print "        None"
344         #else:
345         #    self.get_gid_object().dump(8, dump_parents)
346         #print "    pointer:", self.pointer
347        
348         order = SfaRecord.fields.keys() 
349         for key in self.keys():
350             if key not in order:
351                 order.append(key)
352         for key in order:
353             if key in self and key in self.fields:
354                 if key in 'gid' and self[key]:
355                     gid = GID(string=self[key])
356                     print "     %s:" % key
357                     gid.dump(8, dump_parents)
358                 else:    
359                     print "     %s: %s" % (key, self[key])
360     
361     def getdict(self):
362         return dict(self)
363     
364
365 class UserRecord(SfaRecord):
366
367     fields = {
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'),
374         }
375     fields.update(SfaRecord.fields)
376     
377 class SliceRecord(SfaRecord):
378     fields = {
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'), 
385         }
386     fields.update(SfaRecord.fields)
387
388  
389 class NodeRecord(SfaRecord):
390     fields = {
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'),
396         }
397     fields.update(SfaRecord.fields)
398
399
400 class AuthorityRecord(SfaRecord):
401     fields =  {
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'),
410         }
411     fields.update(SfaRecord.fields)
412     
413