2 # Implements support for geni records
4 # TODO: Use existing PLC database methods? or keep this separate?
8 from types import StringTypes
10 from geni.util.rspec import *
11 from geni.util.parameter import *
13 class GeniRecord(dict):
15 The GeniRecord class implements a Geni Record. A GeniRecord is a tuple
16 (Name, GID, Type, Info).
18 Name specifies the HRN of the object
19 GID is the GID of the object
20 Type is user | authority | slice | component
22 Info is comprised of the following sub-fields
23 pointer = a pointer to the record in the PL database
25 The pointer is interpreted depending on the type of the record. For example,
26 if the type=="user", then pointer is assumed to be a person_id that indexes
27 into the persons table.
29 A given HRN may have more than one record, provided that the records are
34 'hrn': Parameter(str, "Human readable name of object"),
35 'gid': Parameter(str, "GID of the object"),
36 'type': Parameter(str, "Record type"),
37 #'last_updated': Parameter(int, 'Date and time of last update'),
38 #'date_created': Parameter(int, 'Date and time this record was created'),
42 'pointer': Parameter(int, "Internal ID")
46 # Create a Geni Record
48 # @param name if !=None, assign the name of the record
49 # @param gid if !=None, assign the gid of the record
50 # @param type one of user | authority | slice | component
51 # @param pointer is a pointer to a PLC record
52 # @param dict if !=None, then fill in this record from the dictionary
54 def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None, string=None):
67 self.set_pointer(pointer)
69 self.load_from_dict(dict)
71 self.load_from_string(string)
74 def update(self, new_dict):
75 if isinstance(new_dict, list):
76 new_dict = new_dict[0]
78 # Convert any boolean strings to real bools
80 if isinstance(new_dict[key], StringTypes):
81 if new_dict[key].lower() in ["true"]:
83 elif new_dict[key].lower() in ["false"]:
85 dict.update(self, new_dict)
88 # Set the name of the record
90 # @param name is a string containing the HRN
92 def set_name(self, name):
94 Set the name of the record
100 # Set the GID of the record
102 # @param gid is a GID object or the string representation of a GID object
104 def set_gid(self, gid):
106 Set the GID of the record
109 if isinstance(gid, StringTypes):
112 self.gid = gid.save_to_string(save_parents=True)
116 # Set the type of the record
118 # @param type is a string: user | authority | slice | component
120 def set_type(self, type):
122 Set the type of the record
128 # Set the pointer of the record
130 # @param pointer is an integer containing the ID of a PLC record
132 def set_pointer(self, pointer):
134 Set the pointer of the record
136 self.pointer = pointer
140 # Return the name (HRN) of the record
144 Return the name (HRN) of the record
149 # Return the type of the record
153 Return the type of the record
158 # Return the pointer of the record. The pointer is an integer that may be
159 # used to look up the record in the PLC database. The evaluation of pointer
160 # depends on the type of the record
162 def get_pointer(self):
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
171 # Return the GID of the record, in the form of a GID object
172 # TODO: not the best name for the function, because we have things called
173 # gidObjects in the Cred
175 def get_gid_object(self):
177 Return the GID of the record, in the form of a GID object
179 return GID(string=self.gid)
182 # Return a key that uniquely identifies this record among all records in
183 # Geni. This key is used to uniquely identify the record in the Geni
188 Return a key that uniquely identifies this record among all records in
189 Geni. This key is used to uniquely identify the record in the Geni
192 return self.name + "#" + self.type
195 # Returns a list of field names in this record.
197 def get_field_names(self):
199 Returns a list of field names in this record.
201 return ["name", "gid", "type", "pointer"]
204 # Given a field name ("name", "gid", ...) return the value of that field.
206 # @param name is the name of field to be returned
208 def get_field_value_string(self, fieldname):
210 Given a field name ("name", "gid", ...) return the value of that field.
212 if fieldname == "key":
215 val = getattr(self, fieldname)
216 if isinstance(val, str):
217 return "'" + str(val) + "'"
222 # Given a list of field names, return a list of values for those fields.
224 # @param fieldnames is a list of field names
226 def get_field_value_strings(self, fieldnames):
228 Given a list of field names, return a list of values for those fields.
231 for fieldname in fieldnames:
232 strs.append(self.get_field_value_string(fieldname))
236 # Return the record in the form of a dictionary
240 Return the record in the form of a dictionary
245 # Load the record from a dictionary
247 # @param dict dictionary to load record fields from
249 def load_from_dict(self, dict):
251 Load the record from a dictionary
253 self.set_name(dict['name'])
254 gidstr = dict.get("gid", None)
256 self.set_gid(dict['gid'])
258 if "pointer" in dict:
259 self.set_pointer(dict['pointer'])
261 self.set_type(dict['type'])
262 self['hrn'] = dict['name']
266 # Save the record to a string. The string contains an XML representation of
269 def save_to_string(self):
271 Save the record to a string. The string contains an XML representation of
274 dict = self.as_dict()
275 record = RecordSpec()
276 record.parseDict(dict)
278 #str = xmlrpclib.dumps((dict,), allow_none=True)
282 # Load the record from a string. The string is assumed to contain an XML
283 # representation of the record.
285 def load_from_string(self, str):
287 Load the record from a string. The string is assumed to contain an XML
288 representation of the record.
290 #dict = xmlrpclib.loads(str)[0][0]
292 record = RecordSpec()
293 record.parseString(str)
294 record_dict = record.toDict()
295 geni_dict = record_dict['record']
296 self.load_from_dict(geni_dict)
299 # Dump the record to stdout
301 # @param dump_parents if true, then the parents of the GID will be dumped
303 def dump(self, dump_parents=False):
305 Walk tree and dump records.
307 #print "RECORD", self.name
308 #print " hrn:", self.name
309 #print " type:", self.type
314 # self.get_gid_object().dump(8, dump_parents)
315 #print " pointer:", self.pointer
317 order = GeniRecord.fields.keys()
318 for key in self.keys():
322 if key in (self and self.fields):
323 if key in 'gid' and self[key]:
324 gid = GID(string=self[key])
326 gid.dump(8, dump_parents)
328 print " %s: %s" % (key, self[key])
334 class UserRecord(GeniRecord):
337 'email': Parameter(str, 'email'),
338 'first_name': Parameter(str, 'First name'),
339 'last_name': Parameter(str, 'Last name'),
340 'phone': Parameter(str, 'Phone Number'),
341 'key': Parameter(str, 'Public key'),
342 'slice': Parameter([str], 'List of slices this user belongs to'),
344 fields.update(GeniRecord.fields)
347 'roles': Parameter([str], 'List of roles'),
348 'title': Parameter(str, 'Title'),
349 'sites': Parameter([str], 'List of sites this user belongs to'),
350 'enabled': Parameter(bool, 'Is this person enabled'),
352 internal_fields.update(GeniRecord.internal_fields)
354 class SliceRecord(GeniRecord):
356 'name': Parameter(str, 'Slice name'),
357 'url': Parameter(str, 'Slice url'),
358 'expires': Parameter(int, 'Date and time this slice exipres'),
359 'researcher': Parameter([str], 'List of users for this slice'),
360 'description': Parameter([str], 'Description of this slice'),
362 fields.update(GeniRecord.fields)
365 'site': Parameter(str, 'Site this slice belongs to'),
366 'instantiation': Parameter(str, 'Slice instantiation'),
367 'nodes': Parameter([str], 'List of nodes this slice is instantiated on'),
368 'max_nodes': Parameter(int, 'Maximum number of nodes this slice is allowed on')
370 internal_fields.update(GeniRecord.internal_fields)
372 class NodeRecord(GeniRecord):
374 'hostname': Parameter(str, 'This nodes dns name'),
375 'node_type': Parameter(str, 'Type of node this is'),
376 'node_type': Parameter(str, 'Type of node this is'),
377 'latitude': Parameter(str, 'latitude'),
378 'longitude': Parameter(str, 'longitude'),
380 fields.update(GeniRecord.fields)
383 'slice_ids_whitelist': Parameter([str], 'List of allowed slices on this node'),
384 'site': Parameter(str, 'Site this node belongs to'),
385 'slices': Parameter([str], 'List of instantiated slices on this node'),
386 'boot_state': Parameter(str, 'This nodes boot state'),
387 'session': Parameter(str, 'This nodes session key'),
388 'ssh_rsa_key': Parameter(str, 'Last known ssh host key'),
389 'verified': Parameter(str, 'Whether the node configuration is verified correct'),
390 'last_contact': Parameter(int, 'Date and time this node last phoned home'),
391 'run_level': Parameter(str, 'Run level'),
392 'version': Parameter(str, 'Node software version'),
393 'key': Parameter(str, 'Node key'),
394 'boot_noonce': Parameter(str, 'Random value generate at nodes last boot'),
395 'model': Parameter(str, 'Model of node'),
396 'ports': Parameter([int], 'List of pcu ports this node is connected to')
398 internal_fields.update(GeniRecord.internal_fields)
400 class AuthorityRecord(GeniRecord):
402 'name': Parameter(str, 'Name'),
403 'login_base': Parameter(str, 'login base'),
404 'enabled': Parameter(bool, 'Is this site enabled'),
405 'url': Parameter(str, 'URL'),
406 'nodes': Parameter([str], 'List of nodes at this site'),
407 'operator': Parameter([str], 'List of operators'),
408 'researcher': Parameter([str], 'List of researchers'),
409 'PI': Parameter([str], 'List of Principal Investigators'),
411 fields.update(GeniRecord.fields)
414 'nodes': Parameter([str], 'List of nodes at this site'),
415 'slices': Parameter([str], 'List of slices instantiated by this site'),
416 'abbreviated_name': Parameter(str, 'Abbreviated name'),
417 'owners': Parameter([str], 'List of owners'),
418 'max_slices': Parameter(int, 'Maximum number of slices this site can instantiate'),
419 'max_slivers': Parameter(int, 'Maximum number of slivers this site can instantiate'),
420 'pi': Parameter([str], 'List of pis'),
421 'is_public': Parameter(bool, 'Is this site public'),
424 internal_fields.update(GeniRecord.internal_fields)