2 # Thierry Parmentelat - INRIA
7 from types import StringTypes
9 from PLC.Faults import *
10 from PLC.Parameter import Parameter
11 from PLC.Filter import Filter
12 from PLC.Table import Row, Table
14 from PLC.ForeignNodes import ForeignNodes,ForeignNode
18 Stores the list of peering PLCs in the peers table.
19 See the Row class for more details
23 primary_key = 'peer_id'
25 'peer_id' : Parameter (int, "Peer identifier"),
26 'peername' : Parameter (str, "Peer name"),
27 'peer_url' : Parameter (str, "Peer API url"),
28 'person_id' : Parameter (int, "Person_id of the account storing credentials - temporary"),
29 'node_ids' : Parameter ([int], "This peer's nodes ids")
32 def validate_peer_url (self, url):
34 Validate URL, checks it looks like https
36 invalid_url = PLCInvalidArgument("Invalid URL")
37 if not re.compile ("^https://.*$").match(url) :
41 def manage_node (self, foreign_node, add_if_true_del_if_false=True, commit=True):
43 Add foreign node to a peer
46 assert 'peer_id' in self
47 assert 'node_id' in foreign_node
49 peer_id = self['peer_id']
50 node_id = foreign_node ['node_id']
52 if add_if_true_del_if_false:
54 sql = "INSERT INTO peer_node VALUES (%d,%d)" % (peer_id,node_id)
56 if self['node_ids'] is None:
57 self['node_ids']=[node_id,]
58 self['node_ids'].append(node_id)
61 sql = "DELETE FROM peer_node WHERE peer_id=%d AND node_id=%d" % (peer_id,node_id)
63 self['node_ids'].remove(node_id)
68 def refresh_nodes (self, current_peer_nodes):
70 refreshes the foreign_nodes and peer_node tables
71 expected input is the current list of nodes as returned by GetNodes
73 returns the number of new nodes on this peer (can be negative)
76 peer_id = self['peer_id']
78 # we get the whole table just in case
79 # a host would have switched from one plc to the other
80 local_foreign_nodes = ForeignNodes (self.api)
81 # new to index it by hostname for searching later
82 local_foreign_nodes.hostname_index()
84 ### mark entries for this peer outofdate
86 for foreign_node in local_foreign_nodes:
87 if foreign_node['peer_id'] == peer_id:
88 foreign_node.uptodate=False
91 ### these fields get copied through
92 ### xxx need to figure how to revert unix timestamp to db timestamp format
93 remote_fields = ['boot_state','model','version','date_created','last_updated']
96 ### scan the new entries, and mark them uptodate
97 for node in current_peer_nodes:
98 hostname = node['hostname']
100 foreign_node = local_foreign_nodes.hostname_locate(hostname)
101 if foreign_node['peer_id'] != peer_id:
102 ### the node has changed its plc, needs to update peer_node
103 old_peer_id = foreign_node['peer_id']
104 old_peers=Peers(self.api,[peer_id])
106 old_peers[0].manage_node(foreign_node,False)
107 self.manage_node(foreign_node,True)
108 foreign_node['peer_id'] = peer_id
109 ### update it anyway: copy other relevant fields
110 for field in remote_fields:
111 foreign_node[field]=node[field]
112 # this row is now valid
113 foreign_node.uptodate=True
116 new_foreign_node = ForeignNode(self.api, {'hostname':hostname})
117 for field in remote_fields:
118 new_foreign_node[field]=node[field]
119 ### need to sync so we get a node_id
120 new_foreign_node.sync()
121 new_foreign_node.uptodate = True
122 self.manage_node(new_foreign_node,True)
123 local_foreign_nodes.hostname_add_by(new_foreign_node)
126 ### delete entries that are not uptodate
127 for foreign_node in local_foreign_nodes:
128 if not foreign_node.uptodate:
129 foreign_node.delete()
131 return len(current_peer_nodes)-old_count
134 def delete (self, commit=True):
139 assert 'peer_id' in self
141 self['deleted'] = True
146 Maps to the peers table in the database
149 def __init__ (self, api, peer_filter = None, columns = None):
150 Table.__init__(self, api, Peer, columns)
152 sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
153 ", ".join(self.columns)
155 if peer_filter is not None:
156 if isinstance(peer_filter, (list, tuple, set)):
157 # Separate the list into integers and strings
158 ints = filter(lambda x: isinstance(x, (int, long)), peer_filter)
159 strs = filter(lambda x: isinstance(x, StringTypes), peer_filter)
160 peer_filter = Filter(Peer.fields, {'peer_id': ints, 'peername': strs})
161 sql += " AND (%s)" % peer_filter.sql(api, "OR")
162 elif isinstance(peer_filter, dict):
163 peer_filter = Filter(Peer.fields, peer_filter)
164 sql += " AND (%s)" % peer_filter.sql(api, "AND")