peer x foreign_node relationship in a separate peer_node table -- uses new db interface
[plcapi.git] / PLC / Peers.py
index 8be0521..5499994 100644 (file)
@@ -11,6 +11,8 @@ from PLC.Parameter import Parameter
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
 
+from PLC.ForeignNodes import ForeignNodes,ForeignNode
+
 class Peer (Row):
     """
     Stores the list of peering PLCs in the peers table. 
@@ -36,6 +38,96 @@ class Peer (Row):
            raise invalid_url
        return url
 
+    def manage_node (self, foreign_node, add_if_true_del_if_false=True, commit=True):
+        """
+        Add foreign node to a peer
+        """
+
+        assert 'peer_id' in self
+        assert 'node_id' in foreign_node
+
+        peer_id = self['peer_id']
+        node_id = foreign_node ['node_id']
+
+        if add_if_true_del_if_false:
+            ### ADDING
+            sql = "INSERT INTO peer_node VALUES (%d,%d)" % (peer_id,node_id)
+            self.api.db.do(sql)
+            if self['node_ids'] is None:
+                self['node_ids']=[node_id,]
+            self['node_ids'].append(node_id)
+            ### DELETING
+        else:
+            sql = "DELETE FROM peer_node WHERE peer_id=%d AND node_id=%d" % (peer_id,node_id)
+            self.api.db.do(sql)
+            self['node_ids'].remove(node_id)
+
+        if commit:
+            self.api.db.commit()
+
+    def refresh_nodes (self, current_peer_nodes):
+        """
+        refreshes the foreign_nodes and peer_node tables
+        expected input is the current list of nodes as returned by GetNodes
+
+        returns the number of new nodes on this peer (can be negative)
+        """
+
+        peer_id = self['peer_id']
+        
+       # we get the whole table just in case 
+       # a host would have switched from one plc to the other
+       local_foreign_nodes = ForeignNodes (self.api)
+       
+       ### mark entries for this peer outofdate
+        old_count=0;
+       for foreign_node in local_foreign_nodes:
+           if foreign_node['peer_id'] == peer_id:
+               foreign_node.uptodate=False
+                old_count += 1
+
+        ### these fields get copied through
+        ### xxx need to figure how to revert unix timestamp to db timestamp format
+#        remote_fields = ['boot_state','model','version','date_created','last_updated']
+        remote_fields = ['boot_state','model','version']
+        
+       ### scan the new entries, and mark them uptodate
+       for node in current_peer_nodes:
+           hostname = node['hostname']
+            try:
+                foreign_node = ForeignNodes(self.api,{'hostname':hostname})[0]
+                if foreign_node['peer_id'] != peer_id:
+                    ### the node has changed its plc, needs to update peer_node
+                    old_peer_id = foreign_node['peer_id']
+                    old_peers=Peers(self.api,[peer_id])
+                    assert old_peer[0]
+                    old_peers[0].manage_node(foreign_node,False)
+                    self.manage_node(foreign_node,True)
+                    foreign_node['peer_id'] = peer_id
+               ### update it anyway: copy other relevant fields
+                for field in remote_fields:
+                    foreign_node[field]=node[field]
+                # this row is now valid
+                foreign_node.uptodate=True
+                foreign_node.sync()
+           except:
+                new_foreign_node = ForeignNode(self.api, {'hostname':hostname})
+                for field in remote_fields:
+                    new_foreign_node[field]=node[field]
+                ### need to sync so we get a node_id
+                new_foreign_node.sync()
+                new_foreign_node.uptodate = True
+                self.manage_node(new_foreign_node,True)
+
+
+       ### delete entries that are not uptodate
+        for foreign_node in local_foreign_nodes:
+            if not foreign_node.uptodate:
+                foreign_node.delete()
+
+        return len(current_peer_nodes)-old_count
+        
+        
     def delete (self, commit=True):
        """
        Delete peer