svc/conntrack.in: Allow multiple networks in a peer pattern.
[tripe] / svc / conntrack.in
index 043c969..a31b268 100644 (file)
@@ -137,11 +137,11 @@ class Config (object):
 
   The most interesting thing is probably the `groups' slot, which stores a
   list of pairs (NAME, PATTERNS); the NAME is a string, and the PATTERNS a
-  list of (TAG, PEER, NET) triples.  The implication is that there should be
+  list of (TAG, PEER, NETS) triples.  The implication is that there should be
   precisely one peer from the set, and that it should be named TAG, where
-  (TAG, PEER, NET) is the first triple such that the host's primary IP
+  (TAG, PEER, NETS) is the first triple such that the host's primary IP
   address (if PEER is None -- or the IP address it would use for
-  communicating with PEER) is within the NET.
+  communicating with PEER) is within one of the networks defined by NETS.
   """
 
   def __init__(me, file):
@@ -239,18 +239,23 @@ class Config (object):
                                   (spec[i], e))
               i += 1
 
-            ## Parse the local network.
-            if len(spec) != i + 1:
-              raise ConfigError(me._file, lno, 'no network defined')
-            try:
-              net = parse_net(spec[i])
-            except Exception, e:
-              raise ConfigError(me._file, lno,
-                                "invalid IP network `%s': %s" %
-                                (spec[i], e))
+            ## Parse the list of local networks.
+            nets = []
+            while i < len(spec):
+              try:
+                net = parse_net(spec[i])
+              except Exception, e:
+                raise ConfigError(me._file, lno,
+                                  "invalid IP network `%s': %s" %
+                                  (spec[i], e))
+              else:
+                nets.append(net)
+              i += 1
+            if not nets:
+              raise ConfigError(me._file, lno, 'no networks defined')
 
             ## Add this entry to the list.
-            grplist.append((name, peer, net))
+            grplist.append((name, peer, nets))
 
     ## Fill in the default test address if necessary.
     if testaddr is None: testaddr = TESTADDR
@@ -271,10 +276,10 @@ def cmd_showgroups():
 def cmd_showgroup(g):
   try: pats = CF.groups[g]
   except KeyError: raise T.TripeJobError('unknown-group', g)
-  for t, p, n in pats:
+  for t, p, nn in pats:
     T.svcinfo('peer', t,
               'target', p and str(p) or '(default)',
-              'net', str(n))
+              'net', ' '.join(map(str, nn)))
 
 ###--------------------------------------------------------------------------
 ### Responding to a network up/down event.
@@ -360,36 +365,32 @@ def kickpeers():
       if T._debug: print '#   check group %s' % g
 
       ## Find out which peer in the group ought to be active.
-      ip = None
-      map = {}
+      statemap = {}
       want = None
-      for t, p, n in pp:
-        if p is None or not upness:
-          ipq = addr
-        else:
-          ipq = localaddr(p)
+      matchp = False
+      for t, p, nn in pp:
+        if p is None or not upness: ip = addr
+        else: ip = localaddr(p)
         if T._debug:
-          info = 'peer=%s; target=%s; net=%s; local=%s' % (
-            t, p or '(default)', n, straddr(ipq))
-        if upness and ip is None and \
-              ipq is not None and ipq.withinp(n):
+          info = 'peer = %s; target = %s; nets = %s; local = %s' % (
+            t, p or '(default)', ', '.join(map(str, nn)), straddr(ip))
+        if upness and not matchp and \
+           ip is not None and any(ip.withinp(n) for n in nn):
           if T._debug: print '#     %s: SELECTED' % info
-          map[t] = 'up'
+          statemap[t] = 'up'
           select.append('%s=%s' % (g, t))
-          if t == 'down' or t.startswith('down/'):
-            want = None
-          else:
-            want = t
-          ip = ipq
+          if t == 'down' or t.startswith('down/'): want = None
+          else: want = t
+          matchp = True
         else:
-          map[t] = 'down'
+          statemap[t] = 'down'
           if T._debug: print '#     %s: skipped' % info
 
       ## Shut down the wrong ones.
       found = False
-      if T._debug: print '#   peer-map = %r' % map
+      if T._debug: print '#   peer-map = %r' % statemap
       for p in peers:
-        what = map.get(p, 'leave')
+        what = statemap.get(p, 'leave')
         if what == 'up':
           found = True
           if T._debug: print '#   peer %s: already up' % p