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