1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
__docformat__ = 'restructuredtext'
from category import Category
from pattern import Pattern
class StateMachine:
"""
The state machine contains a list of dependencies between states, and a list
of states which are "up."
"""
def __init__(self):
"""
Create a new state machine
"""
self.holds = {}
self.deps = []
def assert_state(self, cat):
"""
Move states in the given Category `cat` from down to up.
"""
found = None
for (match, dependency) in self.get_applicable_deps(cat):
res = self.get_satisfied_states(cat, dependency)
print dependency, res
if len(res) == 0:
res = cat.subtract(match)
if found == None:
found = res
else:
found = self.intersect_list(found, res)
if found == None:
self.add_hold(cat)
return True
if len(found) == 0:
return False
for x in found:
self.add_hold(x)
return True
def intersect_list(self, cats1, cats2):
"""
Given two lists of categories, return a list of categories such that a
state appearing in at least one category in each list will appear in at
least one category in the returned list.
"""
retval = set()
for x in cats1:
for y in cats2:
inter = x.intersect(y)
if inter != None:
retval.add(inter)
return retval
def add_hold(self, cat):
"""
Add a hold to a state. Does not check dependencies.
"""
if self.holds.has_key(cat):
self.holds[cat] = self.holds[cat] + 1
else:
self.holds[cat] = 1
def get_satisfied_states(self, dependents, dependencies):
"""
Given that states in `dependents` depend on states in `dependencies`,
return a new Category that contains only the states in `dependents` that
could match states in `dependencies`.
"""
retval = []
for key, val in self.holds.iteritems():
if dependencies.equiv(key) and val > 0:
retval.append(dependents.fill(key.args))
return set(retval)
def get_applicable_deps(self, cat):
"""
Find dependencies that might apply to members of `cat`
"""
retval = []
for (x, y) in self.deps:
if x.equiv(cat):
retval.append((x, y.fill(cat.intersect(x).args)))
return retval
def __str__(self):
return "\n".join(["%s: %s" % (v, k) for k, v in self.holds.iteritems()])
def __repr__(self):
return str(self)
if __name__ == "__main__":
sm = StateMachine()
sm.deps.append((Category("mounted", type=Pattern(True, "nfs")), Category("network_up")))
sm.deps.append((Category("mounted", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False), type=Pattern(False, "nfs")), Category("found_disk", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False))))
sm.deps.append((Category("mounted", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False)), Category("vol_conf", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False))))
sm.assert_state(Category("network_up"))
sm.assert_state(Category("vol_conf", uuid=Pattern(False), devname=Pattern(False), label=Pattern(True, "myroot"), type=Pattern(True, "ext3"), mountpoint=Pattern(True, "/")))
sm.assert_state(Category("vol_conf", uuid=Pattern(False), devname=Pattern(True, "foosrv.com:/vol/home"), label=Pattern(False), type=Pattern(True, "nfs"), mountpoint=Pattern(True, "/home")))
sm.assert_state(Category("found_disk", uuid=Pattern(True, "d3adb3ef"), devname=Pattern(True, "/dev/sda"), label=Pattern(True, "myroot")))
sm.assert_state(Category("mounted", uuid=Pattern(False), type=Pattern(False), devname=Pattern(False), label=Pattern(False), mountpoint=Pattern(False)))
print sm
|