Just hacked a simple FSM (Finite State Machine) in Python
this morning. It's not in a stage I can publish it yet, but
I can already give an example of usage...
The purpose for me is to have a replacement to "mon" to
monitor my machines. "Mon" is very powerful and flexible,
but for whatever reason, I have never been able to master it
enough to get really what I'd need and I wanted something
simpler and more in line with my past experience of real
time telecommunication systems developper.
A simple test system monitoring a network device
with my
brand new "pymachine" would first define the transition
table of the machine:
#!/usr/bin/python
import time, sched, pymachine, commands
class WatchDevice:
def __init__(self, device="eth0"):
self.device=device
self.machine=pymachine.PyMachine()
# Definition of the FSM
self.machine.addState("off")
self.machine.addEvent("off", "isOn", self.isOn);
self.machine.addState("on")
self.machine.addEvent("on", "isOff", self.isOff);
self.machine.addEvent("on", "pingFails", self.pingFails);
self.machine.addState("isolated")
self.machine.addEvent("isolated", "isOff", self.isOff);
self.machine.addEvent("isolated", "pingOK", self.pingOK);
This one has 3 states (off, on and isolated) and 4 events
(isOn, isOff, pingFails and pingOK). It would also need to
define a couple of handlers:
# Definition of the handlers
self.handler1=pymachine.Handler(self.handlerTestDevice,
(), 5, 1)
self.machine.startHandler(self.handler1)
self.handler2=pymachine.Handler(self.handlerTestPing,
(), 5, 60)
Here we've defined 2 handlers, the first one is occurring
every second and started right now, the second one is
occurring every minute and will be started later on. The
methods implementing the transitions and the handlers can
then be coded:
# Transitions
def isOn(self, args):
print "%s is on" % self.device
self.machine.setState("on")
self.machine.restartHandler(self.handler2)
def isOff(self, args):
print "%s is off" % self.device
self.machine.setState("off")
self.machine.stopHandler(self.handler2)
def pingFails(self, args):
print "%s is isolated" % self.device
self.machine.setState("isolated")
def pingOK(self, args):
print "%s is ok" % self.device
self.machine.setState("on")
# Handlers
def handlerTestDevice(self, machine, handler, args):
run=commands.getstatusoutput("/sbin/ifconfig | grep %s" %
self.device)
#print run
if run[0] == 0:
machine.sendEvent("isOn")
else:
machine.sendEvent("isOff")
def handlerTestPing(self, machine, handler, args):
run=commands.getstatusoutput("/bin/ping -I %s -w10 -c5
192.127.127.11" % self.device)
#print run
if run[0] == 0:
machine.sendEvent("pingOK")
else:
machine.sendEvent("pingFails")
And the machine can be started:
def run(self):
self.machine.run()
watch=WatchDevice()
watch.run()
What's the interest of this type of programing? FSM are
often safer, simpler to implement and simpler to test than
traditional programing as soon as the number of
inter-dependent tests is growing. Here, the transitions are
clearly related to a couple (state, event) and can be tested
as such.
I'll try to post the full library when it'll be more
complete. In the meantime (or if I forget), drop me an email if you are
interested.