use self.get_auth_info
[sfa.git] / geni / util / record.py
1 ##
2 # Implements support for geni 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 import geni.util.report
13
14 from geni.trust.gid import *
15 from geni.util.rspec import *
16 from geni.util.parameter import *
17
18 class GeniRecord(dict):
19     """ 
20     The GeniRecord class implements a Geni Record. A GeniRecord is a tuple
21     (Name, GID, Type, Info).
22  
23     Name specifies the HRN 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     fields = {
39         'hrn': Parameter(str, "Human readable name of object"),
40         'gid': Parameter(str, "GID of the object"),
41         'type': Parameter(str, "Record type"),
42         #'last_updated': Parameter(int, 'Date and time of last update'),
43         #'date_created': Parameter(int, 'Date and time this record was created'),
44     }
45
46     internal_fields = {
47         'pointer': Parameter(int, "Internal ID")
48     }
49
50     ##
51     # Create a Geni Record
52     #
53     # @param name if !=None, assign the name of the record
54     # @param gid if !=None, assign the gid of the record
55     # @param type one of user | authority | slice | component
56     # @param pointer is a pointer to a PLC record
57     # @param dict if !=None, then fill in this record from the dictionary
58
59     def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None, string=None):
60         self.dirty = True
61         self.name = None
62         self.gid = None
63         self.type = None
64         self.pointer = None
65         if name:
66             self.set_name(name)
67         if gid:
68             self.set_gid(gid)
69         if type:
70             self.set_type(type)
71         if pointer:
72             self.set_pointer(pointer)
73         if dict:
74             self.load_from_dict(dict)
75         if string:
76             self.load_from_string(string)
77
78     
79     def update(self, new_dict):
80         if isinstance(new_dict, list):
81             new_dict = new_dict[0]
82
83         # Convert any boolean strings to real bools
84         for key in new_dict:
85             if isinstance(new_dict[key], StringTypes):
86                 if new_dict[key].lower() in ["true"]:
87                     new_dict[key] = True
88                 elif new_dict[key].lower() in ["false"]:
89                     new_dict[key] = False
90         dict.update(self, new_dict)
91
92     ##
93     # Set the name of the record
94     #
95     # @param name is a string containing the HRN
96
97     def set_name(self, name):
98         """
99         Set the name of the record
100         """
101         self.name = name
102         self.dirty = True
103
104     ##
105     # Set the GID of the record
106     #
107     # @param gid is a GID object or the string representation of a GID object
108
109     def set_gid(self, gid):
110         """
111         Set the GID of the record
112         """
113
114         if isinstance(gid, StringTypes):
115             self.gid = gid
116         else:
117             self.gid = gid.save_to_string(save_parents=True)
118         self.dirty = True
119
120     ##
121     # Set the type of the record
122     #
123     # @param type is a string: user | authority | slice | component
124
125     def set_type(self, type):
126         """
127         Set the type of the record
128         """
129         self.type = type
130         self.dirty = True
131
132     ##
133     # Set the pointer of the record
134     #
135     # @param pointer is an integer containing the ID of a PLC record
136
137     def set_pointer(self, pointer):
138         """
139         Set the pointer of the record
140         """
141         self.pointer = pointer
142         self.dirty = True
143
144     ##
145     # Return the name (HRN) of the record
146
147     def get_name(self):
148         """
149         Return the name (HRN) of the record
150         """
151         return self.name
152
153     ##
154     # Return the type of the record
155
156     def get_type(self):
157         """
158         Return the type of the record
159         """
160         return self.type
161
162     ##
163     # Return the pointer of the record. The pointer is an integer that may be
164     # used to look up the record in the PLC database. The evaluation of pointer
165     # depends on the type of the record
166
167     def get_pointer(self):
168         """
169         Return the pointer of the record. The pointer is an integer that may be
170         used to look up the record in the PLC database. The evaluation of pointer
171         depends on the type of the record
172         """
173         return self.pointer
174
175     ##
176     # Return the GID of the record, in the form of a GID object
177     # TODO: not the best name for the function, because we have things called
178     # gidObjects in the Cred
179
180     def get_gid_object(self):
181         """
182         Return the GID of the record, in the form of a GID object
183         """
184         return GID(string=self.gid)
185
186     ##
187     # Return a key that uniquely identifies this record among all records in
188     # Geni. This key is used to uniquely identify the record in the Geni
189     # database.
190
191     def get_key(self):
192         """
193         Return a key that uniquely identifies this record among all records in
194         Geni. This key is used to uniquely identify the record in the Geni
195         database.
196         """
197         return self.name + "#" + self.type
198
199     ##
200     # Returns a list of field names in this record. 
201
202     def get_field_names(self):
203         """
204         Returns a list of field names in this record.
205         """
206         return ["name", "gid", "type", "pointer"]
207
208     ##
209     # Given a field name ("name", "gid", ...) return the value of that field.
210     #
211     # @param name is the name of field to be returned
212
213     def get_field_value_string(self, fieldname):
214         """
215         Given a field name ("name", "gid", ...) return the value of that field.
216         """
217         if fieldname == "key":
218             val = self.get_key()
219         else:
220             val = getattr(self, fieldname)
221         if isinstance(val, str):
222             return "'" + str(val) + "'"
223         else:
224             return str(val)
225
226     ##
227     # Given a list of field names, return a list of values for those fields.
228     #
229     # @param fieldnames is a list of field names
230
231     def get_field_value_strings(self, fieldnames):
232         """
233         Given a list of field names, return a list of values for those fields.
234         """
235         strs = []
236         for fieldname in fieldnames:
237             strs.append(self.get_field_value_string(fieldname))
238         return strs
239
240     ##
241     # Return the record in the form of a dictionary
242
243     def as_dict(self):
244         """
245         Return the record in the form of a dictionary
246         """
247         return dict(self)
248
249     ##
250     # Load the record from a dictionary
251     #
252     # @param dict dictionary to load record fields from
253
254     def load_from_dict(self, dict):
255         """
256         Load the record from a dictionary 
257         """
258         self.set_name(dict['name'])
259         gidstr = dict.get("gid", None)
260         if gidstr:
261             self.set_gid(dict['gid'])
262
263         if "pointer" in dict:
264            self.set_pointer(dict['pointer'])
265
266         self.set_type(dict['type'])
267         self['hrn'] = dict['name'] 
268         self.update(dict)        
269     
270     ##
271     # Save the record to a string. The string contains an XML representation of
272     # the record.
273
274     def save_to_string(self):
275         """
276         Save the record to a string. The string contains an XML representation of
277         the record.
278         """
279         dict = self.as_dict()
280         record = RecordSpec()
281         record.parseDict(dict)
282         str = record.toxml()
283         #str = xmlrpclib.dumps((dict,), allow_none=True)
284         return str
285
286     ##
287     # Load the record from a string. The string is assumed to contain an XML
288     # representation of the record.
289
290     def load_from_string(self, str):
291         """
292         Load the record from a string. The string is assumed to contain an XML
293         representation of the record.
294         """
295         #dict = xmlrpclib.loads(str)[0][0]
296         
297         record = RecordSpec()
298         record.parseString(str)
299         record_dict = record.toDict()
300         geni_dict = record_dict['record']
301         self.load_from_dict(geni_dict)
302
303     ##
304     # Dump the record to stdout
305     #
306     # @param dump_parents if true, then the parents of the GID will be dumped
307
308     def dump(self, dump_parents=False):
309         """
310         Walk tree and dump records.
311         """
312         #print "RECORD", self.name
313         #print "        hrn:", self.name
314         #print "       type:", self.type
315         #print "        gid:"
316         #if (not self.gid):
317         #    print "        None"
318         #else:
319         #    self.get_gid_object().dump(8, dump_parents)
320         #print "    pointer:", self.pointer
321        
322         order = GeniRecord.fields.keys() 
323         for key in self.keys():
324             if key not in order:
325                 order.append(key)
326         for key in order:
327             if key in (self and self.fields):
328                 if key in 'gid' and self[key]:
329                     gid = GID(string=self[key])
330                     print "     %s:" % key
331                     gid.dump(8, dump_parents)
332                 else:    
333                     print "     %s: %s" % (key, self[key])
334     
335     def getdict(self):
336         return dict(self)
337     
338
339 class UserRecord(GeniRecord):
340
341     fields = {
342         'email': Parameter(str, 'email'),
343         'first_name': Parameter(str, 'First name'),
344         'last_name': Parameter(str, 'Last name'),
345         'phone': Parameter(str, 'Phone Number'),
346         'key': Parameter(str, 'Public key'),
347         'slice': Parameter([str], 'List of slices this user belongs to'),
348         }
349     fields.update(GeniRecord.fields)
350  
351     internal_fields = {
352         'roles': Parameter([str], 'List of roles'),
353         'title': Parameter(str, 'Title'),
354         'sites': Parameter([str], 'List of sites this user belongs to'),
355         'enabled': Parameter(bool, 'Is this person enabled'),
356         }
357     internal_fields.update(GeniRecord.internal_fields)
358     
359 class SliceRecord(GeniRecord):
360     fields = {
361         'name': Parameter(str, 'Slice name'),
362         'url': Parameter(str, 'Slice url'),
363         'expires': Parameter(int, 'Date and time this slice exipres'),
364         'researcher': Parameter([str], 'List of users for this slice'),
365         'description': Parameter([str], 'Description of this slice'), 
366         }
367     fields.update(GeniRecord.fields)
368
369     internal_fields = {
370         'site': Parameter(str, 'Site this slice belongs to'),
371         'instantiation': Parameter(str, 'Slice instantiation'),
372         'nodes': Parameter([str], 'List of nodes this slice is instantiated on'),
373         'max_nodes': Parameter(int, 'Maximum number of nodes this slice is allowed on')
374         }
375     internal_fields.update(GeniRecord.internal_fields)
376  
377 class NodeRecord(GeniRecord):
378     fields = {
379         'hostname': Parameter(str, 'This nodes dns name'),
380         'node_type': Parameter(str, 'Type of node this is'),
381         'node_type': Parameter(str, 'Type of node this is'),
382         'latitude': Parameter(str, 'latitude'),
383         'longitude': Parameter(str, 'longitude'),
384         }
385     fields.update(GeniRecord.fields)
386
387     internal_fields = {
388         'slice_ids_whitelist': Parameter([str], 'List of allowed slices on this node'),
389         'site': Parameter(str, 'Site this node belongs to'),
390         'slices': Parameter([str], 'List of instantiated slices on this node'),
391         'boot_state': Parameter(str, 'This nodes boot state'),
392         'session': Parameter(str, 'This nodes session key'),
393         'ssh_rsa_key': Parameter(str, 'Last known ssh host key'),
394         'verified': Parameter(str, 'Whether the node configuration is verified correct'),
395         'last_contact': Parameter(int, 'Date and time this node last phoned home'),
396         'run_level': Parameter(str, 'Run level'),
397         'version': Parameter(str, 'Node software version'),
398         'key': Parameter(str, 'Node key'),
399         'boot_noonce': Parameter(str, 'Random value generate at nodes last boot'),
400         'model': Parameter(str, 'Model of node'),
401         'ports': Parameter([int], 'List of pcu ports this node is connected to') 
402         }
403     internal_fields.update(GeniRecord.internal_fields)
404
405 class AuthorityRecord(GeniRecord):
406     fields =  {
407         'name': Parameter(str, 'Name'),
408         'login_base': Parameter(str, 'login base'),
409         'enabled': Parameter(bool, 'Is this site enabled'),
410         'url': Parameter(str, 'URL'),
411         'nodes': Parameter([str], 'List of nodes at this site'),  
412         'operator': Parameter([str], 'List of operators'),
413         'researcher': Parameter([str], 'List of researchers'),
414         'PI': Parameter([str], 'List of Principal Investigators'),
415         }
416     fields.update(GeniRecord.fields)
417     
418     internal_fields = {
419         'nodes': Parameter([str], 'List of nodes at this site'),  
420         'slices': Parameter([str], 'List of slices instantiated by this site'),
421         'abbreviated_name': Parameter(str, 'Abbreviated name'),
422         'owners': Parameter([str], 'List of owners'),
423         'max_slices': Parameter(int, 'Maximum number of slices this site can instantiate'),
424         'max_slivers': Parameter(int, 'Maximum number of slivers this site can instantiate'),
425         'pi': Parameter([str], 'List of pis'),
426         'is_public': Parameter(bool, 'Is this site public'),
427         
428         }
429     internal_fields.update(GeniRecord.internal_fields)