(*) Peer has new fields person_ids and site_ids
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 12 Dec 2006 10:59:01 +0000 (10:59 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 12 Dec 2006 10:59:01 +0000 (10:59 +0000)
    also the former person_id field gets renamed as auth_person_id
(*) new method GetPeerName to access remote plc's name as configured in PLC_NAME
(*) System slices are cached - assuming PLC_SLICE_PREFIX are different, this is no problem
    so GetSlivers filters out remote system slices
(*) RefreshPeer returns *remote* peer name as 'peername'
    formerly 'plcname' returned *local* plc name
(*) Caching mechanism now should be operational in 3+ peers federations,
       that is to say GetPeerData returns only local and caller's objects, not third-peer's
       this requires various plc names to be correctly up to date
(*) RefreshPeer attempts to ensure this is true after a few hiccups,
       this might get improved once we have peer authentication
(*) various docs updated

PLC/Cache.py
PLC/Methods/AddPeer.py
PLC/Methods/DeleteNode.py
PLC/Methods/GetPeerData.py
PLC/Methods/GetPeerName.py [new file with mode: 0644]
PLC/Methods/GetSlivers.py
PLC/Methods/RefreshPeer.py
PLC/Methods/__init__.py
PLC/Peers.py
planetlab4.sql

index d6d449d..5a64a2a 100644 (file)
@@ -30,7 +30,34 @@ def class_attributes (classname):
 
 class Cache:
 
-    # an attempt to provide genericity in the caching algorithm
+    """
+    This class is the core of the RefreshPeer method's implementation,
+    that basically calls Cache:refresh_peer
+
+    It manages caching on a table-by-table basis, and performs required
+    transcoding from remote ids to local ids - that's the job of the
+    Transcoder class
+
+    For the tables (classes) that it handles, it uses the following
+    attributes
+    (*) primary_key is the name of the field where db indexes are stored
+    (*) class_key is used to implement equality on objects
+    (*) foreign_fields is the list of fields that are copied verbatim from
+        foreign objects
+    (*) foreign_xrefs is the list of columns that are subject to transcoding
+        (.) when obj[field] is an int, the transcoded value is directly
+        inserted in the table
+        (.) if it's a list, it is assumed that the relationship is maintained
+            in an external 2-column table. That's where the XrefTable class comes in
+
+    The relationship between slices, slice attribute types and slice attributes being
+    more complex, it is handled in a specifically customized version of update_table
+
+    Of course the order in which the tables are managed is important, with different
+    orders several iterations might be needed for the update process to converge.
+
+    Of course the timers field was introduced for optimization and could safely be removed
+    """
     
     def __init__ (self, api, peer_id, peer_server, auth):
 
@@ -100,7 +127,7 @@ class Cache:
                 sql = "INSERT INTO %s (%s_id,%s_id) VALUES (%d,%d)"% \
                       (self.tablename,self.lowerclass1,self.lowerclass2,id1,id2)
 
-# below is Tony's code but it's badly broken. I'm not sure we care in fact.
+# below is Tony's code but it's badly broken. I'm not sure we care much in fact.
 #          if id2_set:
 #              sql = "INSERT INTO %s select %d, %d " % \
 #                      self.tablename, id1, id2[0] 
@@ -123,12 +150,10 @@ class Cache:
     # peer_object_list list of objects at a given peer -         e.g. peer.GetSlices()
     # alien_xref_objs_dict : a dict {'classname':alien_obj_list} e.g. {'Node':peer.GetNodes()}
     #    we need an entry for each class mentioned in the class's foreign_xrefs
-    # lambda_ignore : the alien objects are ignored if this returns true
     def update_table (self,
                       classname,
                       alien_object_list,
                      alien_xref_objs_dict = {},
-                      lambda_ignore=lambda x:False,
                       report_name_conflicts = True):
         
         verbose ("============================== entering update_table on",classname)
@@ -172,18 +197,16 @@ class Cache:
            else:
                local_object.uptodate=True
 
+        for alien_object in alien_object_list:
+            verbose ('+++ Got alien object',alien_object)
+
         # scan the peer's local objects
         for alien_object in alien_object_list:
 
             object_name = alien_object[class_key]
 
-            ### ignore, e.g. system-wide slices
-            if lambda_ignore(alien_object):
-               verbose('Ignoring',object_name)
-                continue
+           verbose ('----- update_table (%s) - considering'%classname,object_name)
 
-           verbose ('update_table (%s) - Considering'%classname,object_name)
-                
             # optimizing : avoid doing useless syncs
             needs_sync = False
 
@@ -308,6 +331,8 @@ class Cache:
         from PLC.SliceAttributeTypes import SliceAttributeTypes
         from PLC.SliceAttributes import SliceAttribute, SliceAttributes
 
+        verbose ("============================== entering update_slice_attributes")
+
         # init
         peer_id = self.peer_id
         
@@ -405,7 +430,17 @@ class Cache:
         timers={}
         t_start=time.time()
         # xxx see also GetPeerData - peer_id arg unused yet
-        all_data = self.peer_server.GetPeerData (self.auth,0)
+        all_data = self.peer_server.GetPeerData (self.auth,self.api.config.PLC_NAME)
+
+        verbose ('Passed GetPeerData the name',self.api.config.PLC_NAME)
+        sks=all_data.keys()
+        sks.sort()
+        for k in sks:
+            f=all_data[k]
+            try:
+                verbose ('GetPeerData[%s] -> %d'%(k,len(f)))
+            except:
+                pass
 
         t_acquired = time.time()
        # refresh sites
@@ -460,14 +495,13 @@ class Cache:
         plocal_slices = all_data['Slices-local']
         all_slices = plocal_slices + all_data['Slices-peer']
 
-       def is_system_slice (slice):
-           return slice['creator_person_id'] == 1
+        # forget about ignoring remote system slices
+        # just update them too, we'll be able to filter them out later in GetSlivers
 
         nb_new_slices = self.update_table ('Slice', plocal_slices,
                                            {'Node': all_nodes,
                                             'Person': all_persons,
-                                            'Site': all_sites},
-                                          is_system_slice)
+                                            'Site': all_sites})
 
         t=time.time()
         timers['process-slices']=t-t0
@@ -490,7 +524,7 @@ class Cache:
         timers['time_all']      = t_end-t_start
         
         ### returned as-is by RefreshPeer
-        return {'plcname':self.api.config.PLC_NAME,
+        return {
                'new_sites':nb_new_sites,
                'new_keys':nb_new_keys,
                 'new_nodes':nb_new_nodes,
index 79982f5..ebb944d 100644 (file)
@@ -9,12 +9,12 @@ from PLC.Auth import Auth
 
 from PLC.Peers import Peer, Peers
 
-can_update = lambda(k,v): k in ['peername','peer_url','person_id']
+can_update = lambda(k,v): k in ['peername','peer_url','auth_person_id']
 
 class AddPeer (Method):
     """
     Creates a peer entry in the database and returns its id
-    Temporarily, requires to provide a person_id 
+    Temporarily, requires to provide an auth_person_id 
     this is used to store the credentials that we'll
     use when connecting to the peer's API
     """
index c8dc2d8..0f07230 100644 (file)
@@ -32,7 +32,6 @@ class DeleteNode(Method):
             raise PLCInvalidArgument, "No such node"
 
         node = nodes[0]
-       ### xxx here xxx
        PLCCheckLocalNode(node,"DeleteNode")
 
         # If we are not an admin, make sure that the caller is a
index 5f7b2f2..d6ef1e3 100644 (file)
@@ -32,31 +32,41 @@ class GetPeerData (Method):
     roles = ['admin']
 
     accepts = [Auth(),
-               Parameter (int, "Peer id"),
+               Mixed (Parameter (Peer.fields['peer_id']),
+                      Parameter (Peer.fields['peername'])),
                ]
     # for RefreshPeer 
-    returns = Parameter (dict,"Sites, Keys, Nodes, Persons, Slices")
+    returns = Parameter (dict,
+                         "Sites-local Sites-peer Keys-local Keys-peer "
+                         "Nodes-local Nodes-peer Persons-local Persons-peer "
+                         "SliceAttibuteTypes-local SliceAttibuteTypes-peer "
+                         "Slices-local Slices-peer "
+                         "SliceAttributes-local SliceAttributes-peer")
 
-    def call (self, auth, peer_id):
-        # xxx a peer cannot yet compute it's peer_id under another plc
-        # so we return all foreign objects by now
+    def call (self, auth, peer_id_or_peername):
+
+        # checking the argument
+        try:
+            peer_id = Peers(self.api,[peer_id_or_peername])[0]['peer_id']
+        except:
+            raise PLCInvalidArgument,'GetPeerData: no such peer %r'%peer_id_or_peername
         
         t_start = time.time()
         result = {
             'Sites-local' : Sites (self.api,{'peer_id':None}),
-            'Sites-peer' : Sites (self.api,{'~peer_id':None}),
+            'Sites-peer' : Sites (self.api,{'peer_id':peer_id}),
             'Keys-local' : Keys (self.api,{'peer_id':None}),
-            'Keys-peer' : Keys (self.api,{'~peer_id':None}),
+            'Keys-peer' : Keys (self.api,{'peer_id':peer_id}),
             'Nodes-local' : Nodes (self.api,{'peer_id':None}),
-            'Nodes-peer' : Nodes (self.api,{'~peer_id':None}),
+            'Nodes-peer' : Nodes (self.api,{'peer_id':peer_id}),
             'Persons-local' : Persons (self.api,{'peer_id':None}),
-            'Persons-peer' : Persons (self.api,{'~peer_id':None}),
+            'Persons-peer' : Persons (self.api,{'peer_id':peer_id}),
             'SliceAttibuteTypes-local' : SliceAttributeTypes (self.api,{'peer_id':None}),
-            'SliceAttibuteTypes-peer' : SliceAttributeTypes (self.api,{'~peer_id':None}),
+            'SliceAttibuteTypes-peer' : SliceAttributeTypes (self.api,{'peer_id':peer_id}),
             'Slices-local' : Slices (self.api,{'peer_id':None}),
-            'Slices-peer' : Slices (self.api,{'~peer_id':None}),
+            'Slices-peer' : Slices (self.api,{'peer_id':peer_id}),
             'SliceAttributes-local': SliceAttributes (self.api,{'peer_id':None}),
-            'SliceAttributes-peer': SliceAttributes (self.api,{'~peer_id':None}),
+            'SliceAttributes-peer': SliceAttributes (self.api,{'peer_id':peer_id}),
             }
         t_end = time.time()
         result['ellapsed'] = t_end-t_start
diff --git a/PLC/Methods/GetPeerName.py b/PLC/Methods/GetPeerName.py
new file mode 100644 (file)
index 0000000..9d0dc24
--- /dev/null
@@ -0,0 +1,19 @@
+from PLC.Method import Method
+from PLC.Parameter import Parameter
+from PLC.Auth import Auth
+
+from PLC.Peers import Peer, Peers
+
+class GetPeerName (Method):
+    """
+    Returns this peer's name, as defined in the config as PLC_NAME
+    """
+    roles = ['admin']
+
+    accepts = [Auth()]
+
+    returns = Parameter (Peer.fields['peername'])
+
+    def call (self, auth):
+        return self.api.config.PLC_NAME
+    
index bde2e44..060169f 100644 (file)
@@ -70,8 +70,8 @@ class GetSlivers(Method):
         else:
             all_nodes = Nodes(self.api, node_filter).dict()
 
-        # Get default slices
-        system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1'}).dict()
+        # Get local default slices
+        system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1', 'peer_id': None}).dict()
         system_slice_ids = [slice_attribute['slice_id'] for slice_attribute in system_slice_attributes.values()]
         system_slice_ids = dict.fromkeys(system_slice_ids)
        
index 21ebf0a..4d5d114 100644 (file)
@@ -16,42 +16,53 @@ from PLC.Cache import Cache
 
 class RefreshPeer(Method):
     """
-    Query a peer PLC for its list of nodes, and refreshes
-    the local database accordingly
-    
+    First queries a remote PLC for its name and updates the local peers table
+
+    Then proceeds with fetching objects on the remote PLC, and updates the
+    local database accordingly
+
+    It requires the remote peer to be aware of our own name (as configured in PLC_NAME)
+
     Returns a dict containing
-    (*) 'plcname' :   the peer name
-    (*) 'new_sites':  the number of new sites from that peer - may be negative
-    (*) 'new_keys':    
-    (*) 'new_nodes':   
-    (*) 'new_persons': 
-    (*) 'new_slices':  
+    (*) 'peername' :   the peer's name
+    (*) 'new_xxx':     the number of new objects from that peer - may be negative
+    (*) 'timers':      various stats on performance for optimization
+
     """
     
     roles = ['admin']
     
     accepts = [ Auth(),
-               Parameter (int, "Peer id"),
+                Mixed(Peer.fields['peer_id'],
+                      Peer.fields['peername']),
                 ]
     
-    returns = Parameter(dict, "plcname, new_sites, new_keys, new_nodes, new_persons, new_slices")
+    returns = Parameter(dict, 
+                        'new_sites '
+                        'new_keys '
+                        'new_nodes '
+                        'new_persons '
+                        'new_slice_attribute_types '
+                        'new_slices '
+                        'new_slice_attributes '
+                        'timers ')
 
-    def call (self, auth, peer_id):
+    def call (self, auth, peer_id_or_peername):
        
        ### retrieve peer info
-       peers = Peers (self.api,[peer_id])
+       peers = Peers (self.api,[peer_id_or_peername])
         try:
             peer=peers[0]
         except:
-            raise PLCInvalidArgument,'no such peer_id:%d'%peer_id
+            raise PLCInvalidArgument,'RefreshPeer: no such peer:%r'%peer_id_or_peername
        
        ### retrieve account info
-       person_id = peer['person_id']
-       persons = Persons (self.api,[person_id])
+       auth_person_id = peer['auth_person_id']
+       persons = Persons (self.api,[auth_person_id])
         try:
             person = persons[0]
         except:
-            raise PLCInvalidArgument,'no such person_id:%d'%person_id
+            raise PLCInvalidArgument,'RefreshPeer: no such person_id:%d'%auth_person_id
        
        ## connect to the peer's API
         url=peer['peer_url']
@@ -61,7 +72,29 @@ class RefreshPeer(Method):
        auth={ 'Username': person['email'],
               'AuthMethod' : 'password',
               'AuthString' : person['password'],
-              'Role' : 'admin' }
+              'Role' : 'admin' ,
+               }
+
+        # xxx
+        # right now we *need* the remote peer to know our name
+        # (this is used in the GetPeerData that we issue)
+        # in general this will be true
+        # however if anyone decides to change its own plc name things can get wrong
+        # doing this should ensure things become right again after some iterations
+        # that is, hopefully
+        # might wish to change this policy once we have peer authentication, maybe
+        
+        # make sure we have the right name for that peer
+        peername = apiserver.GetPeerName (auth)
+        peer.update_name(peername)
+
+        # we need a peer_id from there on
+        peer_id = peer['peer_id']
+
+        print 'Got peer_id',peer_id
 
        cache = Cache (self.api, peer_id, apiserver, auth)
-       return cache.refresh_peer ()
+        result = cache.refresh_peer ()
+        result['peername']=peername
+
+        return result
index 98473dd..33d4fce 100644 (file)
@@ -1 +1 @@
-methods = 'AddAddressType AddAddressTypeToAddress AddBootState AddConfFile AddConfFileToNodeGroup AddConfFileToNode AddKeyType AddMessage AddNetworkMethod AddNetworkType AddNodeGroup AddNodeNetwork AddNode AddNodeToNodeGroup AddNodeToPCU AddPCU AddPeer AddPersonKey AddPerson AddPersonToSite AddPersonToSlice AddRole AddRoleToPerson AddSiteAddress AddSite AddSliceAttribute AddSliceAttributeType AddSliceInstantiation AddSlice AddSliceToNodes AdmAddAddressType AdmAddNodeGroup AdmAddNodeNetwork AdmAddNode AdmAddNodeToNodeGroup AdmAddPersonKey AdmAddPerson AdmAddPersonToSite AdmAddSitePowerControlUnit AdmAddSite AdmAssociateNodeToPowerControlUnitPort AdmAuthCheck AdmDeleteAddressType AdmDeleteAllPersonKeys AdmDeleteNodeGroup AdmDeleteNodeNetwork AdmDeleteNode AdmDeletePersonKeys AdmDeletePerson AdmDeleteSitePowerControlUnit AdmDeleteSite AdmDisassociatePowerControlUnitPort AdmGenerateNodeConfFile AdmGetAllAddressTypes AdmGetAllKeyTypes AdmGetAllNodeNetworks AdmGetAllRoles AdmGetNodeGroupNodes AdmGetNodeGroups AdmGetNodes AdmGetPersonKeys AdmGetPersonRoles AdmGetPersonSites AdmGetPersons AdmGetPowerControlUnitNodes AdmGetPowerControlUnits AdmGetSiteNodes AdmGetSitePersons AdmGetSitePIs AdmGetSitePowerControlUnits AdmGetSites AdmGetSiteTechContacts AdmGrantRoleToPerson AdmIsPersonInRole AdmQueryConfFile AdmQueryNode AdmQueryPerson AdmQueryPowerControlUnit AdmQuerySite AdmRebootNode AdmRemoveNodeFromNodeGroup AdmRemovePersonFromSite AdmRevokeRoleFromPerson AdmSetPersonEnabled AdmSetPersonPrimarySite AdmUpdateNodeGroup AdmUpdateNodeNetwork AdmUpdateNode AdmUpdatePerson AdmUpdateSitePowerControlUnit AdmUpdateSite AuthCheck BlacklistKey BootCheckAuthentication BootGetNodeDetails BootNotifyOwners BootUpdateNode DeleteAddress DeleteAddressTypeFromAddress DeleteAddressType DeleteBootState DeleteConfFileFromNodeGroup DeleteConfFileFromNode DeleteConfFile DeleteKey DeleteKeyType DeleteMessage DeleteNetworkMethod DeleteNetworkType DeleteNodeFromNodeGroup DeleteNodeFromPCU DeleteNodeGroup DeleteNodeNetwork DeleteNode DeletePCU DeletePersonFromSite DeletePersonFromSlice DeletePerson DeleteRoleFromPerson DeleteRole DeleteSession DeleteSite DeleteSliceAttribute DeleteSliceAttributeType DeleteSliceFromNodes DeleteSliceInstantiation DeleteSlice GetAddresses GetAddressTypes GetBootStates GetConfFiles GetEvents GetKeys GetKeyTypes GetMessages GetNetworkMethods GetNetworkTypes GetNodeGroups GetNodeNetworks GetNodes GetPCUs GetPeerData GetPeers GetPersons GetRoles GetSession GetSites GetSliceAttributes GetSliceAttributeTypes GetSliceInstantiations GetSlices GetSlivers RebootNode RefreshPeer SetPersonPrimarySite SliceCreate SliceDelete UpdateAddress UpdateAddressType UpdateConfFile UpdateKey UpdateMessage UpdateNodeGroup UpdateNodeNetwork UpdateNode UpdatePCU UpdatePerson UpdateSite UpdateSliceAttribute UpdateSliceAttributeType UpdateSlice  system.listMethods  system.methodHelp  system.methodSignature  system.multicall'.split()
+methods = 'AddAddressType AddAddressTypeToAddress AddBootState AddConfFile AddConfFileToNodeGroup AddConfFileToNode AddKeyType AddMessage AddNetworkMethod AddNetworkType AddNodeGroup AddNodeNetwork AddNode AddNodeToNodeGroup AddNodeToPCU AddPCU AddPeer AddPersonKey AddPerson AddPersonToSite AddPersonToSlice AddRole AddRoleToPerson AddSiteAddress AddSite AddSliceAttribute AddSliceAttributeType AddSliceInstantiation AddSlice AddSliceToNodes AdmAddAddressType AdmAddNodeGroup AdmAddNodeNetwork AdmAddNode AdmAddNodeToNodeGroup AdmAddPersonKey AdmAddPerson AdmAddPersonToSite AdmAddSitePowerControlUnit AdmAddSite AdmAssociateNodeToPowerControlUnitPort AdmAuthCheck AdmDeleteAddressType AdmDeleteAllPersonKeys AdmDeleteNodeGroup AdmDeleteNodeNetwork AdmDeleteNode AdmDeletePersonKeys AdmDeletePerson AdmDeleteSitePowerControlUnit AdmDeleteSite AdmDisassociatePowerControlUnitPort AdmGenerateNodeConfFile AdmGetAllAddressTypes AdmGetAllKeyTypes AdmGetAllNodeNetworks AdmGetAllRoles AdmGetNodeGroupNodes AdmGetNodeGroups AdmGetNodes AdmGetPersonKeys AdmGetPersonRoles AdmGetPersonSites AdmGetPersons AdmGetPowerControlUnitNodes AdmGetPowerControlUnits AdmGetSiteNodes AdmGetSitePersons AdmGetSitePIs AdmGetSitePowerControlUnits AdmGetSites AdmGetSiteTechContacts AdmGrantRoleToPerson AdmIsPersonInRole AdmQueryConfFile AdmQueryNode AdmQueryPerson AdmQueryPowerControlUnit AdmQuerySite AdmRebootNode AdmRemoveNodeFromNodeGroup AdmRemovePersonFromSite AdmRevokeRoleFromPerson AdmSetPersonEnabled AdmSetPersonPrimarySite AdmUpdateNodeGroup AdmUpdateNodeNetwork AdmUpdateNode AdmUpdatePerson AdmUpdateSitePowerControlUnit AdmUpdateSite AuthCheck BlacklistKey BootCheckAuthentication BootGetNodeDetails BootNotifyOwners BootUpdateNode DeleteAddress DeleteAddressTypeFromAddress DeleteAddressType DeleteBootState DeleteConfFileFromNodeGroup DeleteConfFileFromNode DeleteConfFile DeleteKey DeleteKeyType DeleteMessage DeleteNetworkMethod DeleteNetworkType DeleteNodeFromNodeGroup DeleteNodeFromPCU DeleteNodeGroup DeleteNodeNetwork DeleteNode DeletePCU DeletePersonFromSite DeletePersonFromSlice DeletePerson DeleteRoleFromPerson DeleteRole DeleteSession DeleteSite DeleteSliceAttribute DeleteSliceAttributeType DeleteSliceFromNodes DeleteSliceInstantiation DeleteSlice GetAddresses GetAddressTypes GetBootStates GetConfFiles GetEvents GetKeys GetKeyTypes GetMessages GetNetworkMethods GetNetworkTypes GetNodeGroups GetNodeNetworks GetNodes GetPCUs GetPeerData GetPeerName GetPeers GetPersons GetRoles GetSession GetSites GetSliceAttributes GetSliceAttributeTypes GetSliceInstantiations GetSlices GetSlivers RebootNode RefreshPeer SetPersonPrimarySite SliceCreate SliceDelete UpdateAddress UpdateAddressType UpdateConfFile UpdateKey UpdateMessage UpdateNodeGroup UpdateNodeNetwork UpdateNode UpdatePCU UpdatePerson UpdateSite UpdateSliceAttribute UpdateSliceAttributeType UpdateSlice  system.listMethods  system.methodHelp  system.methodSignature  system.multicall'.split()
index 684361f..a80d87f 100644 (file)
@@ -25,7 +25,11 @@ class Peer (Row):
        'peer_id' : Parameter (int, "Peer identifier"),
        'peername' : Parameter (str, "Peer name"),
        'peer_url' : Parameter (str, "Peer API url"),
-       'person_id' : Parameter (int, "Person_id of the account storing credentials - temporary"),
+        ### xxx this trick is temporary, for peer authentication
+       'auth_person_id' : Parameter (int, "Person_id of the account storing credentials - temporary"),
+        ### cross refs
+        'site_ids' : Parameter ([int], "This peer's sites ids"),
+        'person_ids' : Parameter ([int], "This peer's persons ids"),
        'node_ids' : Parameter ([int], "This peer's nodes ids"),
        'slice_ids' : Parameter ([int], "This peer's slices ids"),
        }
@@ -39,6 +43,12 @@ class Peer (Row):
            raise invalid_url
        return url
 
+    ### for use by RefreshPeer, *not* a method of the API
+    def update_name (self,peername):
+        if self['peername'] != peername:
+            self['peername']=peername
+            self.sync()
+
     def delete (self, commit=True):
        """
        Delete peer
index bf3f156..39d30d8 100644 (file)
@@ -9,7 +9,7 @@
 --
 -- Copyright (C) 2006 The Trustees of Princeton University
 --
--- $Id: planetlab4.sql,v 1.51 2006/11/28 22:00:14 tmack Exp $
+-- $Id: planetlab4.sql,v 1.52 2006/11/29 17:57:27 tmack Exp $
 --
 
 --------------------------------------------------------------------------------
@@ -47,7 +47,7 @@ CREATE TABLE peers (
      peer_url text NOT NULL,      -- the url of that peer's API
      -- oops, looks like we have a dependency loop here
      --person_id integer REFERENCES persons NOT NULL, -- the account we use for logging in
-     person_id integer NOT NULL, -- the account we use for logging in
+     auth_person_id integer NOT NULL, -- the account we use for logging in
        
      deleted boolean NOT NULL DEFAULT false
 ) WITH OIDS;
@@ -299,7 +299,6 @@ CREATE TABLE nodes (
     model text, -- Hardware make and model
     boot_nonce text, -- Random nonce updated by Boot Manager
     version text, -- Boot CD version string updated by Boot Manager
-    -- XXX Should be key_id integer REFERENCES keys
     ssh_rsa_key text, -- SSH host key updated by Boot Manager
     key text, -- Node key generated by API when configuration file is downloaded
 
@@ -763,7 +762,19 @@ LEFT JOIN person_sites USING (person_id)
 LEFT JOIN person_keys USING (person_id)
 LEFT JOIN person_slices USING (person_id);
 
--- Nodes at each peer
+-- Objects at each peer
+CREATE VIEW peer_sites AS
+SELECT peer_id,
+array_accum(site_id) AS site_ids
+FROM sites
+GROUP BY peer_id;
+
+CREATE VIEW peer_persons AS
+SELECT peer_id,
+array_accum(person_id) AS person_ids
+FROM persons
+GROUP BY peer_id;
+
 CREATE VIEW peer_nodes AS
 SELECT peer_id,
 array_accum(node_id) AS node_ids
@@ -779,9 +790,13 @@ GROUP BY peer_id;
 CREATE VIEW view_peers AS
 SELECT 
 peers.*, 
+peer_sites.site_ids,
+peer_persons.person_ids,
 peer_nodes.node_ids,
 peer_slices.slice_ids
 FROM peers
+LEFT JOIN peer_sites USING (peer_id)
+LEFT JOIN peer_persons USING (peer_id)
 LEFT JOIN peer_nodes USING (peer_id)
 LEFT JOIN peer_slices USING (peer_id);