summaryrefslogtreecommitdiffstats
path: root/src/lib/Server/Lint/RequiredAttrs.py
blob: 9f00a4e249c78c634691daf25ca9a75ff271e41f (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
109
import os.path
import lxml.etree
import Bcfg2.Server.Lint
import Bcfg2.Server.Plugins.Packages

class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin):
    """ verify attributes for configuration entries (as defined in
    doc/server/configurationentries) """

    def __init__(self, *args, **kwargs):
        Bcfg2.Server.Lint.ServerPlugin.__init__(self, *args, **kwargs)
        self.required_attrs = {
            'device': ['name', 'owner', 'group', 'dev_type'],
            'directory': ['name', 'owner', 'group', 'perms'],
            'file': ['name', 'owner', 'group', 'perms'],
            'hardlink': ['name', 'to'],
            'symlink': ['name', 'to'],
            'ignore': ['name'],
            'nonexistent': ['name'],
            'permissions': ['name', 'owner', 'group', 'perms'],
            'vcs': ['vcstype', 'revision', 'sourceurl']}

    def Run(self):
        self.check_rules()
        self.check_bundles()
        self.check_packages()

    def check_packages(self):
        """ check package sources for Source entries with missing attrs """
        if 'Packages' in self.core.plugins:
            for source in self.core.plugins['Packages'].sources:
                if isinstance(source, Bcfg2.Server.Plugins.Packages.PulpSource):
                    if not source.id:
                        self.LintError("required-attrs-missing",
                                       "The required attribute id is missing "
                                       "from a Pulp source: %s" %
                                       self.RenderXML(source.xsource))
                else:
                    if not source.url and not source.rawurl:
                        self.LintError("required-attrs-missing",
                                       "A %s source must have either a url or "
                                       "rawurl attribute: %s" %
                                       (source.ptype,
                                        self.RenderXML(source.xsource)))

                if (not isinstance(source,
                                   Bcfg2.Server.Plugins.Packages.APTSource) and
                    source.recommended):
                    self.LintError("extra-attrs",
                                   "The recommended attribute is not "
                                   "supported on %s sources: %s" %
                                   (source.ptype,
                                    self.RenderXML(source.xsource)))

    def check_rules(self):
        """ check Rules for Path entries with missing attrs """
        if 'Rules' in self.core.plugins:
            for rules in self.core.plugins['Rules'].entries.values():
                xdata = rules.pnode.data
                for path in xdata.xpath("//Path"):
                    self.check_entry(path, os.path.join(self.config['repo'],
                                                        rules.name))

    def check_bundles(self):
        """ check bundles for BoundPath entries with missing attrs """
        if 'Bundler' in self.core.plugins:
            for bundle in self.core.plugins['Bundler'].entries.values():
                try:
                    xdata = lxml.etree.XML(bundle.data)
                except AttributeError:
                    xdata = lxml.etree.parse(bundle.template.filepath).getroot()

                for path in xdata.xpath("//BoundPath"):
                    self.check_entry(path, bundle.name)

    def check_entry(self, entry, filename):
        """ generic entry check """
        if self.HandlesFile(filename):
            pathname = entry.get('name')
            pathtype = entry.get('type')
            pathset = set(entry.attrib.keys())
            try:
                required_attrs = set(self.required_attrs[pathtype] + ['type'])
            except KeyError:
                self.LintError("unknown-path-type",
                               "Unknown path type %s: %s" %
                               (pathtype, self.RenderXML(entry)))
                return

            if 'dev_type' in required_attrs:
                dev_type = entry.get('dev_type')
                if dev_type in ['block', 'char']:
                    # check if major/minor are specified
                    required_attrs |= set(['major', 'minor'])

            if pathtype == 'file' and not entry.text:
                self.LintError("required-attrs-missing",
                               "Text missing for %s %s in %s: %s" %
                               (entry.tag, pathname, filename,
                                self.RenderXML(entry)))

            if not pathset.issuperset(required_attrs):
                self.LintError("required-attrs-missing",
                               "The required attributes %s are missing for %s %sin %s:\n%s" %
                               (",".join([attr
                                          for attr in
                                          required_attrs.difference(pathset)]),
                                entry.tag, pathname, filename,
                                self.RenderXML(entry)))