summaryrefslogtreecommitdiffstats
path: root/statemachine.py
blob: cc90793a4cf4673eed2589a8f1580270f260578a (plain)
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