switch from sa/ma to authority, fix update_membership_list
[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 import report
8 from types import StringTypes
9 from gid import *
10 from geni.util.rspec import *
11
12
13 class GeniRecord:
14     """ 
15     The GeniRecord class implements a Geni Record. A GeniRecord is a tuple
16     (Name, GID, Type, Info).
17  
18     Name specifies the HRN of the object
19     GID is the GID of the object
20     Type is user | authority | slice | component
21  
22     Info is comprised of the following sub-fields
23            pointer = a pointer to the record in the PL database
24            pl_info = planetlab-specific info (when talking to client)
25            geni_info = geni-specific info (when talking to client)
26  
27     The pointer is interpreted depending on the type of the record. For example,
28     if the type=="user", then pointer is assumed to be a person_id that indexes
29     into the persons table.
30  
31     A given HRN may have more than one record, provided that the records are
32     of different types.
33     """
34
35     ##
36     # Create a Geni Record
37     #
38     # @param name if !=None, assign the name of the record
39     # @param gid if !=None, assign the gid of the record
40     # @param type one of user | authority | slice | component
41     # @param pointer is a pointer to a PLC record
42     # @param dict if !=None, then fill in this record from the dictionary
43
44     def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None, string=None):
45         self.dirty = True
46         self.pl_info = None
47         self.geni_info = None
48         self.name = None
49         self.gid = None
50         self.type = None
51         self.pointer = None
52         if name:
53             self.set_name(name)
54         if gid:
55             self.set_gid(gid)
56         if type:
57             self.set_type(type)
58         if pointer:
59             self.set_pointer(pointer)
60         if dict:
61             self.load_from_dict(dict)
62         if string:
63             self.load_from_string(string)
64
65     ##
66     # Set the name of the record
67     #
68     # @param name is a string containing the HRN
69
70     def set_name(self, name):
71         """
72         Set the name of the record
73         """
74         self.name = name
75         self.dirty = True
76
77     ##
78     # Set the GID of the record
79     #
80     # @param gid is a GID object or the string representation of a GID object
81
82     def set_gid(self, gid):
83         """
84         Set the GID of the record
85         """
86
87         if isinstance(gid, StringTypes):
88             self.gid = gid
89         else:
90             self.gid = gid.save_to_string(save_parents=True)
91         self.dirty = True
92
93     ##
94     # Set the type of the record
95     #
96     # @param type is a string: user | authority | slice | component
97
98     def set_type(self, type):
99         """
100         Set the type of the record
101         """
102         self.type = type
103         self.dirty = True
104
105     ##
106     # Set the pointer of the record
107     #
108     # @param pointer is an integer containing the ID of a PLC record
109
110     def set_pointer(self, pointer):
111         """
112         Set the pointer of the record
113         """
114         self.pointer = pointer
115         self.dirty = True
116
117     ##
118     # Set the PLC info of the record
119     #
120     # @param pl_info is a dictionary containing planetlab info
121
122     def set_pl_info(self, pl_info):
123         """
124         Set the PLC info of the record
125         """ 
126         if isinstance(pl_info, list):
127             pl_info = pl_info[0]
128         
129         # Convert any boolean strings to real bools
130         for key in pl_info:
131             if isinstance(pl_info[key], StringTypes):
132                 if pl_info[key].lower() in ["true"]:
133                     pl_info[key] = True
134                 elif pl_info[key].lower() in ["false"]:
135                     pl_info[key] = False   
136         self.pl_info = pl_info
137         self.dirty = True
138
139     ##
140     # Set the geni info the record
141     #
142     # @param geni_info is a dictionary containing geni info
143
144     def set_geni_info(self, geni_info):
145         """
146         Set the geni info the record
147         """
148         if isinstance(geni_info, list):
149             geni_info = geni_info[0]
150         self.geni_info = geni_info
151         self.dirty = True
152
153     ##
154     # Return the pl_info of the record, or an empty dictionary if none exists
155
156     def get_pl_info(self):
157         """
158         Return the pl_info of the record, or an empty dictionary if none exists
159         """
160         if self.pl_info:
161             return self.pl_info
162         else:
163             return {}
164
165     ##
166     # Return the geni_info of the record, or an empty dictionary if none exists
167
168     def get_geni_info(self):
169         """
170         Return the geni_info of the record, or an empty dictionary if none exists
171         """
172         if self.geni_info:
173             return self.geni_info
174         else:
175             return {}
176
177     ##
178     # Return the name (HRN) of the record
179
180     def get_name(self):
181         """
182         Return the name (HRN) of the record
183         """
184         return self.name
185
186     ##
187     # Return the type of the record
188
189     def get_type(self):
190         """
191         Return the type of the record
192         """
193         return self.type
194
195     ##
196     # Return the pointer of the record. The pointer is an integer that may be
197     # used to look up the record in the PLC database. The evaluation of pointer
198     # depends on the type of the record
199
200     def get_pointer(self):
201         """
202         Return the pointer of the record. The pointer is an integer that may be
203         used to look up the record in the PLC database. The evaluation of pointer
204         depends on the type of the record
205         """
206         return self.pointer
207
208     ##
209     # Return the GID of the record, in the form of a GID object
210     # TODO: not the best name for the function, because we have things called
211     # gidObjects in the Cred
212
213     def get_gid_object(self):
214         """
215         Return the GID of the record, in the form of a GID object
216         """
217         return GID(string=self.gid)
218
219     ##
220     # Return a key that uniquely identifies this record among all records in
221     # Geni. This key is used to uniquely identify the record in the Geni
222     # database.
223
224     def get_key(self):
225         """
226         Return a key that uniquely identifies this record among all records in
227         Geni. This key is used to uniquely identify the record in the Geni
228         database.
229         """
230         return self.name + "#" + self.type
231
232     ##
233     # Returns a list of field names in this record. pl_info, geni_info are not
234     # included because they are not part of the record that is stored in the
235     # database, but are rather computed values from other entities
236
237     def get_field_names(self):
238         """
239         Returns a list of field names in this record. pl_info, geni_info are not
240         included because they are not part of the record that is stored in the
241         database, but are rather computed values from other entities
242         """
243         return ["name", "gid", "type", "pointer"]
244
245     ##
246     # Given a field name ("name", "gid", ...) return the value of that field.
247     #
248     # @param name is the name of field to be returned
249
250     def get_field_value_string(self, fieldname):
251         """
252         Given a field name ("name", "gid", ...) return the value of that field.
253         """
254         if fieldname == "key":
255             val = self.get_key()
256         else:
257             val = getattr(self, fieldname)
258         if isinstance(val, str):
259             return "'" + str(val) + "'"
260         else:
261             return str(val)
262
263     ##
264     # Given a list of field names, return a list of values for those fields.
265     #
266     # @param fieldnames is a list of field names
267
268     def get_field_value_strings(self, fieldnames):
269         """
270         Given a list of field names, return a list of values for those fields.
271         """
272         strs = []
273         for fieldname in fieldnames:
274             strs.append(self.get_field_value_string(fieldname))
275         return strs
276
277     ##
278     # Return the record in the form of a dictionary
279
280     def as_dict(self):
281         """
282         Return the record in the form of a dictionary
283         """
284         dict = {}
285         names = self.get_field_names()
286         for name in names:
287             dict[name] = getattr(self, name)
288
289         if self.pl_info:
290             dict['pl_info'] = self.pl_info
291
292         if self.geni_info:
293             dict['geni_info'] = self.geni_info
294
295         return dict
296
297     ##
298     # Load the record from a dictionary
299     #
300     # @param dict dictionary to load record fields from
301
302     def load_from_dict(self, dict):
303         """
304         Load the record from a dictionary 
305         """
306         self.set_name(dict['name'])
307         gidstr = dict.get("gid", None)
308         if gidstr:
309             self.set_gid(dict['gid'])
310
311         self.set_type(dict['type'])
312         if "pointer" in dict:
313            self.set_pointer(dict['pointer'])
314         if "pl_info" in dict and dict['pl_info']:
315            self.set_pl_info(dict["pl_info"])
316         if "geni_info" in dict and dict['geni_info']:
317            self.set_geni_info(dict["geni_info"])
318
319     ##
320     # Save the record to a string. The string contains an XML representation of
321     # the record.
322
323     def save_to_string(self):
324         """
325         Save the record to a string. The string contains an XML representation of
326         the record.
327         """
328         dict = self.as_dict()
329         record = RecordSpec()
330         record.parseDict(dict)
331         str = record.toxml()
332         #str = xmlrpclib.dumps((dict,), allow_none=True)
333         return str
334
335     ##
336     # Load the record from a string. The string is assumed to contain an XML
337     # representation of the record.
338
339     def load_from_string(self, str):
340         """
341         Load the record from a string. The string is assumed to contain an XML
342         representation of the record.
343         """
344         #dict = xmlrpclib.loads(str)[0][0]
345         
346         record = RecordSpec()
347         record.parseString(str)
348         record_dict = record.toDict()
349         geni_dict = record_dict['record']
350         self.load_from_dict(geni_dict)
351
352     ##
353     # Dump the record to stdout
354     #
355     # @param dump_parents if true, then the parents of the GID will be dumped
356
357     def dump(self, dump_parents=False):
358         """
359         Walk tree and dump records.
360         """
361         print "RECORD", self.name
362         print "        hrn:", self.name
363         print "       type:", self.type
364         print "        gid:"
365         if (not self.gid):
366             print "        None"
367         else:
368             self.get_gid_object().dump(8, dump_parents)
369         print "    pointer:", self.pointer
370
371         print "  geni_info:"
372         geni_info = getattr(self, "geni_info", {})
373         if geni_info:
374             for key in geni_info.keys():
375                 print "       ", key, ":", geni_info[key]
376
377         print "    pl_info:"
378         pl_info = getattr(self, "pl_info", {})
379         if pl_info:
380
381             for key in (s for s in pl_info.keys()\
382             if (s.endswith("_ids") or s.endswith("_id")) == False):
383                 print "       ", key, ":", pl_info[key]
384
385
386     def getdict(self):
387         info = {'hrn': self.name, 'type': self.type, 'gid': self.gid}
388         geni_info = getattr(self, "geni_info", {})
389         pl_info = getattr(self, "pl_info", {}) 
390         if geni_info:
391             info.update(geni_info)
392         if pl_info:
393             info.update(pl_info)
394         return info