2 # Implements support for geni records
4 # TODO: Use existing PLC database methods? or keep this separate?
10 from types import StringTypes
12 import geni.util.report
14 from geni.util.gid import *
15 from geni.util.rspec import *
16 from geni.util.parameter import *
18 class GeniRecord(dict):
20 The GeniRecord class implements a Geni Record. A GeniRecord is a tuple
21 (Name, GID, Type, Info).
23 Name specifies the HRN of the object
24 GID is the GID of the object
25 Type is user | authority | slice | component
27 Info is comprised of the following sub-fields
28 pointer = a pointer to the record in the PL database
30 The pointer is interpreted depending on the type of the record. For example,
31 if the type=="user", then pointer is assumed to be a person_id that indexes
32 into the persons table.
34 A given HRN may have more than one record, provided that the records are
39 'hrn': Parameter(str, "Human readable name of object"),
40 'gid': Parameter(str, "GID of the object"),
41 'type': Parameter(str, "Record type"),
42 #'last_updated': Parameter(int, 'Date and time of last update'),
43 #'date_created': Parameter(int, 'Date and time this record was created'),
47 'pointer': Parameter(int, "Internal ID")
51 # Create a Geni Record
53 # @param name if !=None, assign the name of the record
54 # @param gid if !=None, assign the gid of the record
55 # @param type one of user | authority | slice | component
56 # @param pointer is a pointer to a PLC record
57 # @param dict if !=None, then fill in this record from the dictionary
59 def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None, string=None):
72 self.set_pointer(pointer)
74 self.load_from_dict(dict)
76 self.load_from_string(string)
79 def update(self, new_dict):
80 if isinstance(new_dict, list):
81 new_dict = new_dict[0]
83 # Convert any boolean strings to real bools
85 if isinstance(new_dict[key], StringTypes):
86 if new_dict[key].lower() in ["true"]:
88 elif new_dict[key].lower() in ["false"]:
90 dict.update(self, new_dict)
93 # Set the name of the record
95 # @param name is a string containing the HRN
97 def set_name(self, name):
99 Set the name of the record
105 # Set the GID of the record
107 # @param gid is a GID object or the string representation of a GID object
109 def set_gid(self, gid):
111 Set the GID of the record
114 if isinstance(gid, StringTypes):
117 self.gid = gid.save_to_string(save_parents=True)
121 # Set the type of the record
123 # @param type is a string: user | authority | slice | component
125 def set_type(self, type):
127 Set the type of the record
133 # Set the pointer of the record
135 # @param pointer is an integer containing the ID of a PLC record
137 def set_pointer(self, pointer):
139 Set the pointer of the record
141 self.pointer = pointer
145 # Return the name (HRN) of the record
149 Return the name (HRN) of the record
154 # Return the type of the record
158 Return the type of the record
163 # Return the pointer of the record. The pointer is an integer that may be
164 # used to look up the record in the PLC database. The evaluation of pointer
165 # depends on the type of the record
167 def get_pointer(self):
169 Return the pointer of the record. The pointer is an integer that may be
170 used to look up the record in the PLC database. The evaluation of pointer
171 depends on the type of the record
176 # Return the GID of the record, in the form of a GID object
177 # TODO: not the best name for the function, because we have things called
178 # gidObjects in the Cred
180 def get_gid_object(self):
182 Return the GID of the record, in the form of a GID object
184 return GID(string=self.gid)
187 # Return a key that uniquely identifies this record among all records in
188 # Geni. This key is used to uniquely identify the record in the Geni
193 Return a key that uniquely identifies this record among all records in
194 Geni. This key is used to uniquely identify the record in the Geni
197 return self.name + "#" + self.type
200 # Returns a list of field names in this record.
202 def get_field_names(self):
204 Returns a list of field names in this record.
206 return ["name", "gid", "type", "pointer"]
209 # Given a field name ("name", "gid", ...) return the value of that field.
211 # @param name is the name of field to be returned
213 def get_field_value_string(self, fieldname):
215 Given a field name ("name", "gid", ...) return the value of that field.
217 if fieldname == "key":
220 val = getattr(self, fieldname)
221 if isinstance(val, str):
222 return "'" + str(val) + "'"
227 # Given a list of field names, return a list of values for those fields.
229 # @param fieldnames is a list of field names
231 def get_field_value_strings(self, fieldnames):
233 Given a list of field names, return a list of values for those fields.
236 for fieldname in fieldnames:
237 strs.append(self.get_field_value_string(fieldname))
241 # Return the record in the form of a dictionary
245 Return the record in the form of a dictionary
250 # Load the record from a dictionary
252 # @param dict dictionary to load record fields from
254 def load_from_dict(self, dict):
256 Load the record from a dictionary
258 self.set_name(dict['name'])
259 gidstr = dict.get("gid", None)
261 self.set_gid(dict['gid'])
263 if "pointer" in dict:
264 self.set_pointer(dict['pointer'])
266 self.set_type(dict['type'])
267 self['hrn'] = dict['name']
271 # Save the record to a string. The string contains an XML representation of
274 def save_to_string(self):
276 Save the record to a string. The string contains an XML representation of
279 dict = self.as_dict()
280 record = RecordSpec()
281 record.parseDict(dict)
283 #str = xmlrpclib.dumps((dict,), allow_none=True)
287 # Load the record from a string. The string is assumed to contain an XML
288 # representation of the record.
290 def load_from_string(self, str):
292 Load the record from a string. The string is assumed to contain an XML
293 representation of the record.
295 #dict = xmlrpclib.loads(str)[0][0]
297 record = RecordSpec()
298 record.parseString(str)
299 record_dict = record.toDict()
300 geni_dict = record_dict['record']
301 self.load_from_dict(geni_dict)
304 # Dump the record to stdout
306 # @param dump_parents if true, then the parents of the GID will be dumped
308 def dump(self, dump_parents=False):
310 Walk tree and dump records.
312 #print "RECORD", self.name
313 #print " hrn:", self.name
314 #print " type:", self.type
319 # self.get_gid_object().dump(8, dump_parents)
320 #print " pointer:", self.pointer
322 order = GeniRecord.fields.keys()
323 for key in self.keys():
327 if key in (self and self.fields):
328 if key in 'gid' and self[key]:
329 gid = GID(string=self[key])
331 gid.dump(8, dump_parents)
333 print " %s: %s" % (key, self[key])
339 class UserRecord(GeniRecord):
342 'email': Parameter(str, 'email'),
343 'first_name': Parameter(str, 'First name'),
344 'last_name': Parameter(str, 'Last name'),
345 'phone': Parameter(str, 'Phone Number'),
346 'key': Parameter(str, 'Public key'),
347 'slice': Parameter([str], 'List of slices this user belongs to'),
349 fields.update(GeniRecord.fields)
352 'roles': Parameter([str], 'List of roles'),
353 'title': Parameter(str, 'Title'),
354 'sites': Parameter([str], 'List of sites this user belongs to'),
355 'enabled': Parameter(bool, 'Is this person enabled'),
357 internal_fields.update(GeniRecord.internal_fields)
359 class SliceRecord(GeniRecord):
361 'name': Parameter(str, 'Slice name'),
362 'url': Parameter(str, 'Slice url'),
363 'expires': Parameter(int, 'Date and time this slice exipres'),
364 'researcher': Parameter([str], 'List of users for this slice'),
365 'description': Parameter([str], 'Description of this slice'),
367 fields.update(GeniRecord.fields)
370 'site': Parameter(str, 'Site this slice belongs to'),
371 'instantiation': Parameter(str, 'Slice instantiation'),
372 'nodes': Parameter([str], 'List of nodes this slice is instantiated on'),
373 'max_nodes': Parameter(int, 'Maximum number of nodes this slice is allowed on')
375 internal_fields.update(GeniRecord.internal_fields)
377 class NodeRecord(GeniRecord):
379 'hostname': Parameter(str, 'This nodes dns name'),
380 'node_type': Parameter(str, 'Type of node this is'),
381 'node_type': Parameter(str, 'Type of node this is'),
382 'latitude': Parameter(str, 'latitude'),
383 'longitude': Parameter(str, 'longitude'),
385 fields.update(GeniRecord.fields)
388 'slice_ids_whitelist': Parameter([str], 'List of allowed slices on this node'),
389 'site': Parameter(str, 'Site this node belongs to'),
390 'slices': Parameter([str], 'List of instantiated slices on this node'),
391 'boot_state': Parameter(str, 'This nodes boot state'),
392 'session': Parameter(str, 'This nodes session key'),
393 'ssh_rsa_key': Parameter(str, 'Last known ssh host key'),
394 'verified': Parameter(str, 'Whether the node configuration is verified correct'),
395 'last_contact': Parameter(int, 'Date and time this node last phoned home'),
396 'run_level': Parameter(str, 'Run level'),
397 'version': Parameter(str, 'Node software version'),
398 'key': Parameter(str, 'Node key'),
399 'boot_noonce': Parameter(str, 'Random value generate at nodes last boot'),
400 'model': Parameter(str, 'Model of node'),
401 'ports': Parameter([int], 'List of pcu ports this node is connected to')
403 internal_fields.update(GeniRecord.internal_fields)
405 class AuthorityRecord(GeniRecord):
407 'name': Parameter(str, 'Name'),
408 'login_base': Parameter(str, 'login base'),
409 'enabled': Parameter(bool, 'Is this site enabled'),
410 'url': Parameter(str, 'URL'),
411 'nodes': Parameter([str], 'List of nodes at this site'),
412 'operator': Parameter([str], 'List of operators'),
413 'researcher': Parameter([str], 'List of researchers'),
414 'PI': Parameter([str], 'List of Principal Investigators'),
416 fields.update(GeniRecord.fields)
419 'nodes': Parameter([str], 'List of nodes at this site'),
420 'slices': Parameter([str], 'List of slices instantiated by this site'),
421 'abbreviated_name': Parameter(str, 'Abbreviated name'),
422 'owners': Parameter([str], 'List of owners'),
423 'max_slices': Parameter(int, 'Maximum number of slices this site can instantiate'),
424 'max_slivers': Parameter(int, 'Maximum number of slivers this site can instantiate'),
425 'pi': Parameter([str], 'List of pis'),
426 'is_public': Parameter(bool, 'Is this site public'),
429 internal_fields.update(GeniRecord.internal_fields)