- RefreshPeer & AddSliceToNodes had bugs
[plcapi.git] / PLC / Peers.py
index d4fed75..872a867 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,99 @@ 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)
+        # new to index it by hostname for searching later
+        local_foreign_nodes.hostname_index()
+       
+       ### 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']
+
+        
+       ### scan the new entries, and mark them uptodate
+       for node in current_peer_nodes:
+           hostname = node['hostname']
+            try:
+                foreign_node = local_foreign_nodes.hostname_locate(hostname)
+                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)
+                local_foreign_nodes.hostname_add_by(new_foreign_node)
+
+
+       ### 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
@@ -51,14 +146,14 @@ class Peers (Table):
     Maps to the peers table in the database
     """
     
-    def __init__ (self, api, peer_filter = None):
-        Table.__init__(self, api, Peer)
+    def __init__ (self, api, peer_filter = None, columns = None):
+        Table.__init__(self, api, Peer, columns)
 
        sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
-              ", ".join(Peer.fields)
+              ", ".join(self.columns)
 
         if peer_filter is not None:
-            if isinstance(peer_filter, list):
+            if isinstance(peer_filter, (list, tuple, set)):
                 # Separate the list into integers and strings
                 ints = filter(lambda x: isinstance(x, (int, long)), peer_filter)
                 strs = filter(lambda x: isinstance(x, StringTypes), peer_filter)