X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=geni%2Futil%2Frecord.py;h=27b6c83db78cabf88ef0968eba36f37fd2dfdd08;hb=095e10f25ef5736a4522ae0525c3041dcb40a7e9;hp=80384d9fc6e0d5dd49df682017fa0f5bb5b8ccac;hpb=2bae7c848a00f1fcf034c1e269176844056c6f99;p=sfa.git diff --git a/geni/util/record.py b/geni/util/record.py index 80384d9f..27b6c83d 100644 --- a/geni/util/record.py +++ b/geni/util/record.py @@ -4,46 +4,60 @@ # TODO: Use existing PLC database methods? or keep this separate? ## -import report +### $Id$ +### $URL$ + from types import StringTypes -from gid import * -from geni.util.rspec import * -## -# The GeniRecord class implements a Geni Record. A GeniRecord is a tuple -# (Name, GID, Type, Info). -# -# Name specifies the HRN of the object -# GID is the GID of the object -# Type is user | sa | ma | slice | component -# -# Info is comprised of the following sub-fields -# pointer = a pointer to the record in the PL database -# pl_info = planetlab-specific info (when talking to client) -# geni_info = geni-specific info (when talking to client) -# -# The pointer is interpreted depending on the type of the record. For example, -# if the type=="user", then pointer is assumed to be a person_id that indexes -# into the persons table. -# -# A given HRN may have more than one record, provided that the records are -# of different types. For example, planetlab.us.arizona may have both an SA -# and a MA record, but cannot have two SA records. -class GeniRecord: +import geni.util.report + +from geni.trust.gid import * +from geni.util.rspec import * +from geni.util.parameter import * + +class GeniRecord(dict): + """ + The GeniRecord class implements a Geni Record. A GeniRecord is a tuple + (Name, GID, Type, Info). + + Name specifies the HRN of the object + GID is the GID of the object + Type is user | authority | slice | component + + Info is comprised of the following sub-fields + pointer = a pointer to the record in the PL database + + The pointer is interpreted depending on the type of the record. For example, + if the type=="user", then pointer is assumed to be a person_id that indexes + into the persons table. + + A given HRN may have more than one record, provided that the records are + of different types. + """ + + fields = { + 'hrn': Parameter(str, "Human readable name of object"), + 'gid': Parameter(str, "GID of the object"), + 'type': Parameter(str, "Record type"), + #'last_updated': Parameter(int, 'Date and time of last update'), + #'date_created': Parameter(int, 'Date and time this record was created'), + } + + internal_fields = { + 'pointer': Parameter(int, "Internal ID") + } ## # Create a Geni Record # # @param name if !=None, assign the name of the record # @param gid if !=None, assign the gid of the record - # @param type one of user | sa | ma | slice | component + # @param type one of user | authority | slice | component # @param pointer is a pointer to a PLC record # @param dict if !=None, then fill in this record from the dictionary def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None, string=None): self.dirty = True - self.pl_info = None - self.geni_info = None self.name = None self.gid = None self.type = None @@ -61,12 +75,29 @@ class GeniRecord: if string: self.load_from_string(string) + + def update(self, new_dict): + if isinstance(new_dict, list): + new_dict = new_dict[0] + + # Convert any boolean strings to real bools + for key in new_dict: + if isinstance(new_dict[key], StringTypes): + if new_dict[key].lower() in ["true"]: + new_dict[key] = True + elif new_dict[key].lower() in ["false"]: + new_dict[key] = False + dict.update(self, new_dict) + ## # Set the name of the record # # @param name is a string containing the HRN def set_name(self, name): + """ + Set the name of the record + """ self.name = name self.dirty = True @@ -76,6 +107,10 @@ class GeniRecord: # @param gid is a GID object or the string representation of a GID object def set_gid(self, gid): + """ + Set the GID of the record + """ + if isinstance(gid, StringTypes): self.gid = gid else: @@ -85,9 +120,12 @@ class GeniRecord: ## # Set the type of the record # - # @param type is a string: user | sa | ma | slice | component + # @param type is a string: user | authority | slice | component def set_type(self, type): + """ + Set the type of the record + """ self.type = type self.dirty = True @@ -97,59 +135,28 @@ class GeniRecord: # @param pointer is an integer containing the ID of a PLC record def set_pointer(self, pointer): + """ + Set the pointer of the record + """ self.pointer = pointer self.dirty = True - ## - # Set the PLC info of the record - # - # @param pl_info is a dictionary containing planetlab info - - def set_pl_info(self, pl_info): - if isinstance(pl_info, list): - pl_info = pl_info[0] - self.pl_info = pl_info - self.dirty = True - - ## - # Set the geni info the record - # - # @param geni_info is a dictionary containing geni info - - def set_geni_info(self, geni_info): - if isinstance(geni_info, list): - geni_info = geni_info[0] - self.geni_info = geni_info - self.dirty = True - - ## - # Return the pl_info of the record, or an empty dictionary if none exists - - def get_pl_info(self): - if self.pl_info: - return self.pl_info - else: - return {} - - ## - # Return the geni_info of the record, or an empty dictionary if none exists - - def get_geni_info(self): - if self.geni_info: - return self.geni_info - else: - return {} - ## # Return the name (HRN) of the record def get_name(self): + """ + Return the name (HRN) of the record + """ return self.name ## # Return the type of the record def get_type(self): + """ + Return the type of the record + """ return self.type ## @@ -158,6 +165,11 @@ class GeniRecord: # depends on the type of the record def get_pointer(self): + """ + Return the pointer of the record. The pointer is an integer that may be + used to look up the record in the PLC database. The evaluation of pointer + depends on the type of the record + """ return self.pointer ## @@ -166,6 +178,9 @@ class GeniRecord: # gidObjects in the Cred def get_gid_object(self): + """ + Return the GID of the record, in the form of a GID object + """ return GID(string=self.gid) ## @@ -174,14 +189,20 @@ class GeniRecord: # database. def get_key(self): + """ + Return a key that uniquely identifies this record among all records in + Geni. This key is used to uniquely identify the record in the Geni + database. + """ return self.name + "#" + self.type ## - # Returns a list of field names in this record. pl_info, geni_info are not - # included because they are not part of the record that is stored in the - # database, but are rather computed values from other entities + # Returns a list of field names in this record. def get_field_names(self): + """ + Returns a list of field names in this record. + """ return ["name", "gid", "type", "pointer"] ## @@ -190,6 +211,9 @@ class GeniRecord: # @param name is the name of field to be returned def get_field_value_string(self, fieldname): + """ + Given a field name ("name", "gid", ...) return the value of that field. + """ if fieldname == "key": val = self.get_key() else: @@ -205,6 +229,9 @@ class GeniRecord: # @param fieldnames is a list of field names def get_field_value_strings(self, fieldnames): + """ + Given a list of field names, return a list of values for those fields. + """ strs = [] for fieldname in fieldnames: strs.append(self.get_field_value_string(fieldname)) @@ -214,18 +241,10 @@ class GeniRecord: # Return the record in the form of a dictionary def as_dict(self): - dict = {} - names = self.get_field_names() - for name in names: - dict[name] = getattr(self, name) - - if self.pl_info: - dict['pl_info'] = self.pl_info - - if self.geni_info: - dict['geni_info'] = self.geni_info - - return dict + """ + Return the record in the form of a dictionary + """ + return dict(self) ## # Load the record from a dictionary @@ -233,24 +252,30 @@ class GeniRecord: # @param dict dictionary to load record fields from def load_from_dict(self, dict): + """ + Load the record from a dictionary + """ self.set_name(dict['name']) gidstr = dict.get("gid", None) if gidstr: self.set_gid(dict['gid']) - self.set_type(dict['type']) - self.set_pointer(dict['pointer']) - if "pl_info" in dict: - self.set_pl_info(dict["pl_info"]) - if "geni_info" in dict: - self.set_geni_info(dict["geni_info"]) + if "pointer" in dict: + self.set_pointer(dict['pointer']) + self.set_type(dict['type']) + self['hrn'] = dict['name'] + self.update(dict) + ## # Save the record to a string. The string contains an XML representation of # the record. def save_to_string(self): - + """ + Save the record to a string. The string contains an XML representation of + the record. + """ dict = self.as_dict() record = RecordSpec() record.parseDict(dict) @@ -263,6 +288,10 @@ class GeniRecord: # representation of the record. def load_from_string(self, str): + """ + Load the record from a string. The string is assumed to contain an XML + representation of the record. + """ #dict = xmlrpclib.loads(str)[0][0] record = RecordSpec() @@ -277,32 +306,124 @@ class GeniRecord: # @param dump_parents if true, then the parents of the GID will be dumped def dump(self, dump_parents=False): - print "RECORD", self.name - print " hrn:", self.name - print " type:", self.type - print " gid:" - if (not self.gid): - print " None" - else: - self.get_gid_object().dump(8, dump_parents) - print " pointer:", self.pointer - - print " geni_info:" - geni_info = getattr(self, "geni_info", {}) - if geni_info: - for key in geni_info.keys(): - print " ", key, ":", geni_info[key] - - print " pl_info:" - pl_info = getattr(self, "pl_info", {}) - if pl_info: - - for key in pl_info.keys(): - print " ", key, ":", pl_info[key] - - + """ + Walk tree and dump records. + """ + #print "RECORD", self.name + #print " hrn:", self.name + #print " type:", self.type + #print " gid:" + #if (not self.gid): + # print " None" + #else: + # self.get_gid_object().dump(8, dump_parents) + #print " pointer:", self.pointer + + order = GeniRecord.fields.keys() + for key in self.keys(): + if key not in order: + order.append(key) + for key in order: + if key in (self and self.fields): + if key in 'gid' and self[key]: + gid = GID(string=self[key]) + print " %s:" % key + gid.dump(8, dump_parents) + else: + print " %s: %s" % (key, self[key]) + def getdict(self): - info = {'hrn': self.name, 'type': self.type, 'gid': self.gid} - info.update(getattr(self, "geni_info", {})) - info.update(getattr(self, "pl_info", {})) - return info + return dict(self) + + +class UserRecord(GeniRecord): + + fields = { + 'email': Parameter(str, 'email'), + 'first_name': Parameter(str, 'First name'), + 'last_name': Parameter(str, 'Last name'), + 'phone': Parameter(str, 'Phone Number'), + 'key': Parameter(str, 'Public key'), + 'slice': Parameter([str], 'List of slices this user belongs to'), + } + fields.update(GeniRecord.fields) + + internal_fields = { + 'roles': Parameter([str], 'List of roles'), + 'title': Parameter(str, 'Title'), + 'sites': Parameter([str], 'List of sites this user belongs to'), + 'enabled': Parameter(bool, 'Is this person enabled'), + } + internal_fields.update(GeniRecord.internal_fields) + +class SliceRecord(GeniRecord): + fields = { + 'name': Parameter(str, 'Slice name'), + 'url': Parameter(str, 'Slice url'), + 'expires': Parameter(int, 'Date and time this slice exipres'), + 'researcher': Parameter([str], 'List of users for this slice'), + 'description': Parameter([str], 'Description of this slice'), + } + fields.update(GeniRecord.fields) + + internal_fields = { + 'site': Parameter(str, 'Site this slice belongs to'), + 'instantiation': Parameter(str, 'Slice instantiation'), + 'nodes': Parameter([str], 'List of nodes this slice is instantiated on'), + 'max_nodes': Parameter(int, 'Maximum number of nodes this slice is allowed on') + } + internal_fields.update(GeniRecord.internal_fields) + +class NodeRecord(GeniRecord): + fields = { + 'hostname': Parameter(str, 'This nodes dns name'), + 'node_type': Parameter(str, 'Type of node this is'), + 'node_type': Parameter(str, 'Type of node this is'), + 'latitude': Parameter(str, 'latitude'), + 'longitude': Parameter(str, 'longitude'), + } + fields.update(GeniRecord.fields) + + internal_fields = { + 'slice_ids_whitelist': Parameter([str], 'List of allowed slices on this node'), + 'site': Parameter(str, 'Site this node belongs to'), + 'slices': Parameter([str], 'List of instantiated slices on this node'), + 'boot_state': Parameter(str, 'This nodes boot state'), + 'session': Parameter(str, 'This nodes session key'), + 'ssh_rsa_key': Parameter(str, 'Last known ssh host key'), + 'verified': Parameter(str, 'Whether the node configuration is verified correct'), + 'last_contact': Parameter(int, 'Date and time this node last phoned home'), + 'run_level': Parameter(str, 'Run level'), + 'version': Parameter(str, 'Node software version'), + 'key': Parameter(str, 'Node key'), + 'boot_noonce': Parameter(str, 'Random value generate at nodes last boot'), + 'model': Parameter(str, 'Model of node'), + 'ports': Parameter([int], 'List of pcu ports this node is connected to') + } + internal_fields.update(GeniRecord.internal_fields) + +class AuthorityRecord(GeniRecord): + fields = { + 'name': Parameter(str, 'Name'), + 'login_base': Parameter(str, 'login base'), + 'enabled': Parameter(bool, 'Is this site enabled'), + 'url': Parameter(str, 'URL'), + 'nodes': Parameter([str], 'List of nodes at this site'), + 'operator': Parameter([str], 'List of operators'), + 'researcher': Parameter([str], 'List of researchers'), + 'PI': Parameter([str], 'List of Principal Investigators'), + } + fields.update(GeniRecord.fields) + + internal_fields = { + 'nodes': Parameter([str], 'List of nodes at this site'), + 'slices': Parameter([str], 'List of slices instantiated by this site'), + 'abbreviated_name': Parameter(str, 'Abbreviated name'), + 'owners': Parameter([str], 'List of owners'), + 'max_slices': Parameter(int, 'Maximum number of slices this site can instantiate'), + 'max_slivers': Parameter(int, 'Maximum number of slivers this site can instantiate'), + 'pi': Parameter([str], 'List of pis'), + 'is_public': Parameter(bool, 'Is this site public'), + + } + internal_fields.update(GeniRecord.internal_fields)