summaryrefslogtreecommitdiffstats
path: root/src/lib/Server/Plugins/Deps.py
blob: b186258cb3194f3cc22a88b0df09c23f55de665f (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
104
105
106
107
108
"""This plugin provides automatic dependency handling."""
__revision__ = '$Revision$'

import lxml.etree

import Bcfg2.Server.Plugin


class DNode(Bcfg2.Server.Plugin.INode):
    """DNode provides supports for single predicate types for dependencies."""
    raw = {'Group': "lambda x:'%s' in x.groups and predicate(x)"}
    containers = ['Group']

    def __init__(self, data, idict, parent=None):
        self.data = data
        self.contents = {}
        if parent == None:
            self.predicate = lambda x: True
        else:
            predicate = parent.predicate
            if data.tag in list(self.raw.keys()):
                self.predicate = eval(self.raw[data.tag] % (data.get('name')),
                                      {'predicate': predicate})
            else:
                raise Exception
        mytype = self.__class__
        self.children = []
        for item in data.getchildren():
            if item.tag in self.containers:
                self.children.append(mytype(item, idict, self))
            else:
                data = [(child.tag, child.get('name'))
                        for child in item.getchildren()]
                try:
                    self.contents[item.tag][item.get('name')] = data
                except KeyError:
                    self.contents[item.tag] = {item.get('name'): data}


class DepXMLSrc(Bcfg2.Server.Plugin.XMLSrc):
    __node__ = DNode


class Deps(Bcfg2.Server.Plugin.PrioDir,
           Bcfg2.Server.Plugin.StructureValidator):
    name = 'Deps'
    __version__ = '$Id$'
    __author__ = 'bcfg-dev@mcs.anl.gov'
    __child__ = DepXMLSrc

    def __init__(self, core, datastore):
        Bcfg2.Server.Plugin.PrioDir.__init__(self, core, datastore)
        Bcfg2.Server.Plugin.StructureValidator.__init__(self)
        self.cache = {}

    def HandleEvent(self, event):
        self.cache = {}
        Bcfg2.Server.Plugin.PrioDir.HandleEvent(self, event)

    def validate_structures(self, metadata, structures):
        entries = []
        prereqs = []
        for structure in structures:
            for entry in structure.getchildren():
                if (entry.tag, entry.get('name')) not in entries \
                       and not isinstance(entry, lxml.etree._Comment):
                    entries.append((entry.tag, entry.get('name')))
        entries.sort()
        entries = tuple(entries)
        gdata = list(metadata.groups)
        gdata.sort()
        gdata = tuple(gdata)
        if (entries, gdata) in self.cache:
            prereqs = self.cache[(entries, gdata)]
        else:
            [src.Cache(metadata) for src in list(self.entries.values())]

            toexamine = list(entries[:])
            while toexamine:
                entry = toexamine.pop()
                matching = [src for src in list(self.entries.values())
                            if src.cache and entry[0] in src.cache[1]
                            and entry[1] in src.cache[1][entry[0]]]
                if len(matching) > 1:
                    prio = [int(src.priority) for src in matching]
                    if prio.count(max(prio)) > 1:
                        self.logger.error("Found conflicting %s sources with same priority for %s, pkg %s" %
                                          (entry[0].lower(), metadata.hostname, entry[1]))
                        raise Bcfg2.Server.Plugin.PluginExecutionError
                    index = prio.index(max(prio))
                    matching = [matching[index]]

                if not matching:
                    continue
                elif len(matching) == 1:
                    for prq in matching[0].cache[1][entry[0]][entry[1]]:
                        if prq not in prereqs and prq not in entries:
                            toexamine.append(prq)
                            prereqs.append(prq)
            self.cache[(entries, gdata)] = prereqs

        newstruct = lxml.etree.Element("Independent")
        for tag, name in prereqs:
            try:
                lxml.etree.SubElement(newstruct, tag, name=name)
            except:
                self.logger.error("Failed to add dep entry for %s:%s" % (tag, name))
        structures.append(newstruct)