check in latest updates to documentation
[sfa.git] / util / record.py
index 7c01abd..2d6d7ac 100644 (file)
@@ -1,19 +1,48 @@
-# record.py
-#
-# implements support for geni records
+##
+# Implements support for geni records
 #
 # TODO: Use existing PLC database methods? or keep this separate?
+##
 
-from pg import DB
+import report
+from gid import *
 
-# Record is a tuple (Name, GID, Type, Info)
-#    info is implemented as a pointer to a PLC record
-#    privkey is stored for convenience on the registry for entities which
-#        the registry holds their private keys
+##
+# 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():
-    def __init__(self, name=None, gid=None, type=None, pointer=None, privkey=None, dict=None):
-        self.dirty=True
+
+    ##
+    # 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 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):
+        self.dirty = True
+        self.pl_info = None
+        self.geni_info = None
         if name:
             self.set_name(name)
         if gid:
@@ -22,40 +51,139 @@ class GeniRecord():
             self.set_type(type)
         if pointer:
             self.set_pointer(pointer)
-        if privkey:
-            self.set_privkey(privkey)
         if dict:
             self.set_name(dict['name'])
             self.set_gid(dict['gid'])
             self.set_type(dict['type'])
             self.set_pointer(dict['pointer'])
-            self.set_privkey(dict['privkey'])
+            if "pl_info" in dict:
+               self.set_pl_info(dict["pl_info"])
+            if "geni_info" in dict:
+               self.set_geni_info(dict["geni_info"])
+
+    ##
+    # Set the name of the record
+    #
+    # @param name is a string containing the HRN
 
     def set_name(self, name):
         self.name = name
         self.dirty = True
 
+    ##
+    # Set the GID of the record
+    #
+    # @param gid is a GID object or the string representation of a GID object
+
     def set_gid(self, gid):
-        self.gid = gid
+        if isinstance(gid, str):
+            self.gid = gid
+        else:
+            self.gid = gid.save_to_string(save_parents=True)
         self.dirty = True
 
+    ##
+    # Set the type of the record
+    #
+    # @param type is a string: user | sa | ma | slice | component
+
     def set_type(self, type):
         self.type = type
         self.dirty = True
 
+    ##
+    # Set the pointer of the record
+    #
+    # @param pointer is an integer containing the ID of a PLC record
+
     def set_pointer(self, pointer):
         self.pointer = pointer
         self.dirty = True
 
-    def set_privkey(self, privkey):
-        self.privkey = privkey
+    ##
+    # Set the PLC info of the record
+    #
+    # @param pl_info is a dictionary containing planetlab info
+
+    def set_pl_info(self, pl_info):
+        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):
+        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 self.name
+
+    ##
+    # Return the type of the record
+
+    def get_type(self):
+        return self.type
+
+    ##
+    # 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
+
+    def get_pointer(self):
+        return self.pointer
+
+    ##
+    # Return the GID of the record, in the form of a GID object
+    # TODO: not the best name for the function, because we have things called
+    # gidObjects in the Cred
+
+    def get_gid_object(self):
+        return GID(string=self.gid)
+
+    ##
+    # 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.
+
     def get_key(self):
         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
+
     def get_field_names(self):
-        return ["name", "gid", "type", "pointer", "privkey"]
+        return ["name", "gid", "type", "pointer"]
+
+    ##
+    # Given a field name ("name", "gid", ...) return the value of that field.
+    #
+    # @param name is the name of field to be returned
 
     def get_field_value_string(self, fieldname):
         if fieldname == "key":
@@ -67,109 +195,57 @@ class GeniRecord():
         else:
             return str(val)
 
+    ##
+    # Given a list of field names, return a list of values for those fields.
+    #
+    # @param fieldnames is a list of field names
+
     def get_field_value_strings(self, fieldnames):
         strs = []
         for fieldname in fieldnames:
             strs.append(self.get_field_value_string(fieldname))
         return strs
 
+    ##
+    # 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] = self.getattr(name)
+            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
 
-# GeniTable
-#
-# Represents a single table on a registry for a single authority.
-
-class GeniTable():
-    def __init__(self, create=False, hrn="unspecified.default.registry", cninfo=None, privkey=None, gid=None):
-        # XXX privkey/gid are necessary so the table can generate GIDs for its
-        #    records; might move that out of here as it doesn't seem the right place
-
-        self.hrn = hrn
-
-        # pgsql doesn't like table names with "." in them, to replace it with "$"
-        self.tablename = self.hrn.replace(".", "$")
-
-        # establish a connection to the pgsql server
-        self.cnx = DB(cninfo['dbname'], cninfo['address'], port=cninfo['port'], user=cninfo['user'], passwd=cninfo['password'])[
-
-        # the private key is necessary for creation of GIDs
-        self.privkey = privkey
-
-        self.gid = gid
-
-        # if asked to create the table, then create it
-        if create:
-            self.create()
-
-    def create(self):
-        querystr = "CREATE TABLE " + self.tablename + " ( \
-                key text, \
-                name text, \
-                gid text, \
-                type text, \
-                privkey text, \
-                pointer integer);"
-
-        self.cnx.query('DROP TABLE IF EXISTS ' + self.tablename)
-        self.cnx.query(querystr)
-
-    def insert(self, record):
-        fieldnames = ["key"] + record.get_field_names()
-        fieldvals = record.get_field_value_strings(fieldnames)
-        query_str = "INSERT INTO " + self.tablename + \
-                       "(" + ",".join(fieldnames) + ") " + \
-                       "VALUES(" + ",".join(fieldvals) + ")"
-        #print query_str
-        self.cnx.query(query_str)
-
-    def update(self, record):
-        names = record.get_field_names()
-        pairs = []
-        for name in names:
-           val = record.get_field_value_string(name)
-           pairs.append(name + " = " + val)
-        update = ", ".join(pairs)
-
-        query_str = "UPDATE " + self.tablename+ " SET " + update + " WHERE key = '" + record.get_key() + "'"
-        #print query_str
-        self.cnx.query(query_str)
-
-    def resolve_raw(self, type, hrn):
-        query_str = "SELECT * FROM " + self.tablename + " WHERE name = '" + hrn + "'"
-        dict_list = self.cnx.query(query_str).dictresult()
-        result_dict_list = []
-        for dict in dict_list:
-           if (type=="*") or (dict['type'] == type):
-               result_dict_list.append(dict)
-        return result_dict_list
-
-    def resolve(self, type, hrn):
-        result_dict_list = self.resolve_raw(type, hrn)
-        result_rec_list = []
-        for dict in result_dict_list:
-            result_rec_list.append(GeniRecord(dict=dict))
-        return result_rec_list
-
-    def create_gid(self, hrn, uuid, pubkey):
-        gid = GID(subject=hrn, uuid=uuid, hrn=hrn)
-        gid.set_pubkey(pubkey)
-        gid.set_issuer(key=self.privkey, subject=self.hrn)
-        gid.set_parent(self.gid)
-        gid.encode()
-        gid.sign()
-
-        return gid
-
-    def update_gid(self, record)
-        old_gid = GID(string = record.get_gid())
-        pubkey = old_gid.get_pubkey()
-
-        gid = self.create_gid(old_gid.get_hrn(), old_gid.get_uuid(), old_gid.get_pubkey())
-
-        record.set_gid(gid.save_to_string())
+    ##
+    # Dump the record to stdout
+    #
+    # @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:"
+        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]
+