3fb18fc49593d8b82ee36f6eeb674b652165f7f3
[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         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