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