summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCasey Dahlin <cdahlin@redhat.com>2009-01-19 23:50:12 -0500
committerCasey Dahlin <cdahlin@redhat.com>2009-01-19 23:50:12 -0500
commit33646380d145a38ea56a0af192560b47f96d7bf8 (patch)
tree29180605f36f1693731993235f16a9550d586588
parent132ec3528cc0ed2b86056339f80a918904eb5b99 (diff)
downloadupstate-33646380d145a38ea56a0af192560b47f96d7bf8.tar.gz
upstate-33646380d145a38ea56a0af192560b47f96d7bf8.tar.xz
upstate-33646380d145a38ea56a0af192560b47f96d7bf8.zip
Make state machine use text configurationHEADmaster
-rw-r--r--statemachine.py110
1 files changed, 72 insertions, 38 deletions
diff --git a/statemachine.py b/statemachine.py
index deb8bb7..647b35b 100644
--- a/statemachine.py
+++ b/statemachine.py
@@ -3,6 +3,7 @@ __docformat__ = 'restructuredtext'
from category import Category
from pattern import Pattern
+from confparse import Conf, WhenSpec, OnSpec, ExecSpec
import setcross
class StateMachine:
@@ -11,15 +12,50 @@ class StateMachine:
of states which are "up."
"""
- def __init__(self):
+ def __init__(self, conf_str = None, conf_file = None):
"""
- Create a new state machine
+ Create a new state machine. `conf_file` if specified is a file to load
+ configuration from. `conf_str` if specified is a configuration string.
+ If both are specified `conf_file` takes precedence, and `conf_str` is
+ used on error.
"""
self.up = set()
self.wanted = set()
- self.valid_supercats = set()
self.deps = []
self.event_triggers = []
+ if conf_file != None:
+ try:
+ file = open(conf_file)
+ conf_str = file.read()
+ file.close()
+ except:
+ pass
+ if conf_str != None:
+ self.load_conf(conf_str)
+
+ def load_conf(self, str):
+ """
+ Load some string configuration into this state machine.
+ """
+ conf = Conf(str)
+ for block in conf.propmatches:
+ self.load_conf_block(block)
+
+ def load_conf_block(self, block):
+ """
+ Load a single block of text configuration. `block` is the parse tree
+ node at the root of the block.
+ """
+ cat = block.pattern.to_category()
+ for prop in block.properties:
+ prop = prop.spec
+ if prop.__class__ == WhenSpec:
+ self.deps.append((cat, prop.waiting_for.to_category()))
+ elif prop.__class__ == OnSpec:
+ self.event_triggers.append(
+ (prop.waiting_for.to_category(), cat))
+ else: # prop.__class__ == ExecSpec
+ pass #TODO: Exec support
def emit(self, event):
"""
@@ -33,18 +69,6 @@ class StateMachine:
def bring_up(self, cat, wanted=True):
"""
- Move states in the given Category `cat` from down to up.
- """
- retval = False
- for supercat in self.valid_supercats:
- newcat = supercat.intersect(cat)
- if newcat == None:
- continue
- retval = retval or self.__bring_up(newcat, wanted)
- return retval
-
- def __bring_up(self, cat, wanted=True):
- """
Move states in the given Category `cat` from down to up. Don't check to
see if the category makes sense first.
"""
@@ -58,13 +82,15 @@ class StateMachine:
else:
found.append(res)
if found == None:
- self.add_hold(cat, wanted)
- sm.emit(Category("ε"))
+ if self.add_hold(cat, wanted):
+ sm.emit(Category("ε"))
return True
to_add = self.cat_cross(found)
+ added = False
for x in to_add:
- self.add_hold(x, wanted)
- sm.emit(Category("ε"))
+ added = self.add_hold(x, wanted) or added
+ if added:
+ sm.emit(Category("ε"))
return True
def cat_cross(self, found):
@@ -89,17 +115,19 @@ class StateMachine:
def add_hold(self, cat, wanted):
"""
- Add a hold to a state. Does not check dependencies.
+ Add a hold to a state. Does not check dependencies. Returns False if the
+ state was up, True if it wasn't.
"""
for x in self.up:
if cat.subset_of(x):
- return
+ return False
if x.subset_of(cat):
self.up.remove(x)
self.up.add(cat)
- return
+ return True
self.up.add(cat)
if wanted: self.wanted.add(cat)
+ return True
def bring_down(self, cat, rec=False):
"""
@@ -140,11 +168,13 @@ class StateMachine:
return a new Category that contains only the states in `dependents` that
could match states in `dependencies`.
"""
- retval = []
+ retval = set()
for cat in self.up:
if dependencies.superset_of(cat):
- retval.append(dependents.intersect_args(**cat.args))
- return set(retval) | dependents.inverse_set()
+ retval.add(dependents.intersect_args(**cat.args))
+ if None in retval:
+ retval.remove(None)
+ return retval | dependents.inverse_set()
def get_applicable_deps(self, cat):
"""
@@ -168,27 +198,31 @@ def nm(*args): return Pattern(False, *args) # Reads as "don't match." See above
def any(): return nm() # Match anything. Implementation reads "don't match nothing"
if __name__ == "__main__":
- sm = StateMachine()
- sm.deps.append((Category("mounted", type=m("nfs")), Category("network_up")))
- sm.deps.append((Category("mounted", type=nm("nfs")), Category("found_disk")))
- sm.deps.append((Category("mounted"), Category("vol_conf")))
+ sm = StateMachine(conf_str = """
+mounted(type: nfs):
+ when network_up
+
+mounted(type: ! nfs):
+ when found_disk
- sm.valid_supercats.add(Category("network_up"))
- sm.valid_supercats.add(Category("vol_conf"))
- sm.valid_supercats.add(Category("found_disk"))
- sm.valid_supercats.add(Category("mounted", devname=any(), mountpoint=any()))
+mounted:
+ when vol_conf
- sm.event_triggers.append((Category("fstab_line"), Category("vol_conf", src=m("fstabd"))))
+mounted(auto: 1): auto
+vol_conf(src: fstabd) on fstab_line
+""")
sm.bring_up(Category("network_up"))
sm.bring_up(Category("found_disk", uuid=m("d3adb3ef"), devname=m("/dev/sda"), label=m("myroot")))
sm.bring_up(Category("mounted"))
print sm
print "--"
- sm.emit(Category("fstab_line", label=m("myroot"), type=m("ext3"), mountpoint=m("/")))
- sm.emit(Category("fstab_line", devname=m("foosrv.com:/vol/home"), type=m("nfs"), mountpoint=m("/home")))
- sm.emit(Category("fstab_line", devname=m("foosrv.com:/vol/beefs"), type=m("nfs"), mountpoint=m("/beefs")))
- sm.bring_up(Category("mounted", devname=any(), mountpoint=any()))
+ sm.emit(Category("fstab_line", label=m("myroot"), type=m("ext3"), mountpoint=m("/"), auto=m("1")))
+ sm.emit(Category("fstab_line", devname=m("foosrv.com:/vol/home"), type=m("nfs"), mountpoint=m("/home"), auto=m("0")))
+ sm.emit(Category("fstab_line", devname=m("foosrv.com:/vol/beefs"), type=m("nfs"), mountpoint=m("/beefs"), auto=m("0")))
+ print sm
+ print "--"
+ sm.bring_up(Category("mounted"))
print sm
print "--"
sm.bring_down(Category("network_up"))