## so turn them all off.
cp = RawConfigParser()
cp.read(me._file)
+ if T._debug: print '# reread config'
## Save the test address. Make sure it's vaguely sensible. The default
## is probably good for most cases, in fact, since that address isn't
### This will be a configuration file.
CF = None
+def straddr(a): return S.inet_ntoa(pack('>L', a))
+def strmask(m):
+ for i in xrange(33):
+ if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return i
+ return straddr(m)
+
+def cmd_showconfig():
+ T.svcinfo('test-addr=%s' % CF.testaddr)
+def cmd_showgroups():
+ for sec, pats in CF.groups:
+ T.svcinfo(sec)
+def cmd_showgroup(g):
+ for s, p in CF.groups:
+ if s == g:
+ pats = p
+ break
+ else:
+ raise T.TripeJobError, 'unknown-group', g
+ for t, p, a, m in pats:
+ T.svcinfo('peer', t,
+ 'target', p or '(default)',
+ 'net', '%s/%s' % (straddr(a), strmask(m)))
+
###--------------------------------------------------------------------------
### Responding to a network up/down event.
def kickpeers():
while True:
upness, reason = _kick.get()
+ if T._debug: print '# kickpeers %s: %s' % (upness, reason)
+ select = []
## Make sure the configuration file is up-to-date. Don't worry if we
## can't do anything useful.
addr = localaddr(CF.testaddr)
if addr is None:
upness = False
+ else:
+ addr = None
+ if not T._debug: pass
+ elif addr: print '# local address = %s' % straddr(addr)
+ else: print '# offline'
## Now decide what to do.
changes = []
for g, pp in CF.groups:
+ if T._debug: print '# check group %s' % g
## Find out which peer in the group ought to be active.
- want = None # unequal to any string
- if upness:
- for t, p, a, m in pp:
- if p is None:
- aq = addr
+ ip = None
+ map = {}
+ want = None
+ for t, p, a, m in pp:
+ if p is None or not upness:
+ ipq = addr
+ else:
+ ipq = localaddr(p)
+ if T._debug:
+ info = 'peer=%s; target=%s; net=%s/%s; local=%s' % (
+ t, p or '(default)', straddr(a), strmask(m), straddr(ipq))
+ if upness and ip is None and \
+ ipq is not None and (ipq & m) == a:
+ if T._debug: print '# %s: SELECTED' % info
+ map[t] = 'up'
+ select.append('%s=%s' % (g, t))
+ if t == 'down' or t.startswith('down/'):
+ want = None
else:
- aq = localaddr(p)
- if aq is not None and (aq & m) == a:
want = t
- break
+ ip = ipq
+ else:
+ map[t] = 'down'
+ if T._debug: print '# %s: skipped' % info
## Shut down the wrong ones.
found = False
+ if T._debug: print '# peer-map = %r' % map
for p in peers:
- if p == want:
+ what = map.get(p, 'leave')
+ if what == 'up':
found = True
- elif p.startswith(g) and p != want:
- changes.append(lambda p=p: SM.kill(p))
+ if T._debug: print '# peer %s: already up' % p
+ elif what == 'down':
+ def _(p = p):
+ try:
+ SM.kill(p)
+ except T.TripeError, exc:
+ if exc.args[0] == 'unknown-peer':
+ ## Inherently racy; don't worry about this.
+ pass
+ else:
+ raise
+ if T._debug: print '# peer %s: bring down' % p
+ changes.append(_)
## Start the right one if necessary.
if want is not None and not found:
- changes.append(lambda: T._simple(SM.svcsubmit('connect', 'active',
- want)))
+ def _(want = want):
+ try:
+ SM.svcsubmit('connect', 'active', want)
+ except T.TripeError, exc:
+ SM.warn('conntrack', 'connect-failed', want, *exc.args)
+ if T._debug: print '# peer %s: bring up' % want
+ changes.append(_)
## Commit the changes.
if changes:
- SM.notify('conntrack', upness and 'up' or 'down', *reason)
+ SM.notify('conntrack', upness and 'up' or 'down', *select + reason)
for c in changes: c()
def netupdown(upness, reason):
"""
me._mons = []
me._loop = D.mainloop.glib.DBusGMainLoop()
+ me._state = 'startup'
me._reconnect()
def addmon(me, mon):
if me._bus is not None:
mon.attach(me._bus)
- def _reconnect(me):
+ def _reconnect(me, hunoz = None):
"""
Start connecting to the bus.
If we fail the first time, retry periodically.
"""
+ if me._state == 'startup':
+ T.aside(SM.notify, 'conntrack', 'dbus-connection', 'startup')
+ elif me._state == 'connected':
+ T.aside(SM.notify, 'conntrack', 'dbus-connection', 'lost')
+ else:
+ T.aside(SM.notify, 'conntrack', 'dbus-connection',
+ 'state=%s' % me._state)
+ me._state == 'reconnecting'
me._bus = None
if me._try_connect():
G.timeout_add_seconds(5, me._try_connect)
If we succeed, attach the monitors.
"""
try:
- bus = D.SystemBus(mainloop = me._loop, private = True)
- except D.DBusException:
+ addr = OS.getenv('TRIPE_CONNTRACK_BUS')
+ if addr == 'SESSION':
+ bus = D.SessionBus(mainloop = me._loop, private = True)
+ elif addr is not None:
+ bus = D.bus.BusConnection(addr, mainloop = me._loop)
+ else:
+ bus = D.SystemBus(mainloop = me._loop, private = True)
+ for m in me._mons:
+ m.attach(bus)
+ except D.DBusException, e:
return True
me._bus = bus
+ me._state = 'connected'
bus.call_on_disconnection(me._reconnect)
- for m in me._mons:
- m.attach(bus)
+ T.aside(SM.notify, 'conntrack', 'dbus-connection', 'connected')
return False
###--------------------------------------------------------------------------
Add the D-Bus monitor here, because we might send commands off immediately,
and we want to make sure the server connection is up.
"""
- T.Coroutine(kickpeers).switch()
- dbm = DBusMonitor()
- dbm.addmon(NetworkManagerMonitor())
- dbm.addmon(MaemoICdMonitor())
- G.timeout_add_seconds(300, lambda: (netupdown(True, ['interval-timer'])
- or True))
+ global DBM
+ T.Coroutine(kickpeers, name = 'kickpeers').switch()
+ DBM = DBusMonitor()
+ DBM.addmon(NetworkManagerMonitor())
+ DBM.addmon(MaemoICdMonitor())
+ G.timeout_add_seconds(30, lambda: (netupdown(True, ['interval-timer'])
+ or True))
def parse_options():
"""
return lambda *args: T.defer(netupdown, upness, ['manual'] + list(args))
service_info = [('conntrack', VERSION, {
'up': (0, None, '', cmd_updown(True)),
- 'down': (0, None, '', cmd_updown(False))
+ 'down': (0, None, '', cmd_updown(False)),
+ 'show-config': (0, 0, '', cmd_showconfig),
+ 'show-groups': (0, 0, '', cmd_showgroups),
+ 'show-group': (1, 1, 'GROUP', cmd_showgroup)
})]
if __name__ == '__main__':