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