summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2011-09-19 11:04:03 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2011-09-19 11:04:03 -0400
commitfe9b75662276326898458a68744b920ebd9d46b8 (patch)
tree999cf9ca885d38e23305408b37ff0b662686832d
parente6489338056d55805a66383bcd5cda6ed8caa22b (diff)
downloadbcfg2-fe9b75662276326898458a68744b920ebd9d46b8.tar.gz
bcfg2-fe9b75662276326898458a68744b920ebd9d46b8.tar.bz2
bcfg2-fe9b75662276326898458a68744b920ebd9d46b8.zip
added Defaults plugin
-rw-r--r--doc/server/plugins/generators/rules.txt70
-rw-r--r--doc/server/plugins/structures/defaults.txt31
-rw-r--r--schemas/defaults.xsd68
-rw-r--r--schemas/pkgtype.xsd48
-rw-r--r--schemas/rules.xsd10
-rw-r--r--schemas/servicetype.xsd35
-rw-r--r--schemas/types.xsd14
-rw-r--r--src/lib/Server/Lint/MergeFiles.py9
-rw-r--r--src/lib/Server/Lint/RequiredAttrs.py94
-rw-r--r--src/lib/Server/Lint/Validate.py18
-rw-r--r--src/lib/Server/Lint/__init__.py2
-rw-r--r--src/lib/Server/Plugin.py8
-rw-r--r--src/lib/Server/Plugins/Defaults.py51
13 files changed, 316 insertions, 142 deletions
diff --git a/doc/server/plugins/generators/rules.txt b/doc/server/plugins/generators/rules.txt
index b74c37a39..925ee6419 100644
--- a/doc/server/plugins/generators/rules.txt
+++ b/doc/server/plugins/generators/rules.txt
@@ -115,29 +115,29 @@ See :ref:`client-tools-actions`
Service Tag
-----------
-+------------+-------------------------------+-----------------------------------------------------+
-| Name | Description | Values |
-+============+===============================+=====================================================+
-| mode | Per Service Mode (New in 1.0) | (manual | default | supervised | interactive_only ) |
-+------------+-------------------------------+-----------------------------------------------------+
-| name | Service name or regular | String or regex |
-| | expression | |
-+------------+-------------------------------+-----------------------------------------------------+
-| status | Should the service be on or | (on | off | ignore) |
-| | off (default: off). | |
-+------------+-------------------------------+-----------------------------------------------------+
-| target | Service command for restart | String |
-| | (default: restart) | |
-+------------+-------------------------------+-----------------------------------------------------+
-| type | Driver to use on the client | (chkconfig | deb | rc-update | smf | upstart) |
-| | to manage this service. | |
-+------------+-------------------------------+-----------------------------------------------------+
-| sequence | Order for service startup | integer |
-| | (debian services only) | |
-+------------+-------------------------------+-----------------------------------------------------+
-| parameters | Pass parameters to service | String |
-| | (Upstart services only) | |
-+------------+-------------------------------+-----------------------------------------------------+
++------------+-------------------------------+---------------------------------------------------------+
+| Name | Description | Values |
++============+===============================+=========================================================+
+| mode | Per Service Mode (New in 1.0) | (manual | default | supervised | interactive_only ) |
++------------+-------------------------------+---------------------------------------------------------+
+| name | Service name or regular | String or regex |
+| | expression | |
++------------+-------------------------------+---------------------------------------------------------+
+| status | Should the service be on or | (on | off | ignore) |
+| | off (default: off). | |
++------------+-------------------------------+---------------------------------------------------------+
+| target | Service command for restart | String |
+| | (default: restart) | |
++------------+-------------------------------+---------------------------------------------------------+
+| type | Driver to use on the client | (chkconfig | deb | rc-update | smf | upstart | |
+| | to manage this service. | systemd | freebsd | launchd ) |
++------------+-------------------------------+---------------------------------------------------------+
+| sequence | Order for service startup | integer |
+| | (debian services only) | |
++------------+-------------------------------+---------------------------------------------------------+
+| parameters | Pass parameters to service | String |
+| | (Upstart services only) | |
++------------+-------------------------------+---------------------------------------------------------+
Service mode descriptions
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -354,30 +354,12 @@ how to assign Rules to a host's literal configuration.
Using Regular Expressions in Rules
==================================
-The ``name`` attribute in Rules supports the use of regular expressions
-to match multiple abstract configuration entries. For instance, to
-make all Service entries use the ``systemd`` tool on Fedora 15 and the
-``chkconfig`` tool on Fedora 14, you could do the following.
-
-.. code-block:: xml
-
- <Rules priority="0">
- <Group name="fedora-15">
- <Service name=".*" type="systemd"/>
- </Group>
- <Group name="fedora-14">
- <Service name=".*" type="chkconfig"/>
- </Group>
- </Rules>
+The ``name`` attribute in Rules supports the use of regular
+expressions to match multiple abstract configuration entries.
Regular expressions are anchored at both ends, so ``<Service
name="bcfg2".../>`` will *not* match a Service named ``bcfg2-server``;
you'd have to explicitly specify ``<Service name="bcfg2.*".../>``.
Note that only one Rule can apply to any abstract entry, so you cannot
-specify multiple regexs to match the same rule. In the use case
-above, you would have to specify the services fully (except for type)
-in the bundles.
-
-Attributes specified in a bundle have precedence over attributes
-specified in Rules, so you can use Rules to set defaults.
+specify multiple regexs to match the same rule.
diff --git a/doc/server/plugins/structures/defaults.txt b/doc/server/plugins/structures/defaults.txt
new file mode 100644
index 000000000..58b9feddb
--- /dev/null
+++ b/doc/server/plugins/structures/defaults.txt
@@ -0,0 +1,31 @@
+.. -*- mode: rst -*-
+
+.. _server-plugins-structures-defaults:
+
+==========
+ Defaults
+==========
+
+The Defaults plugin can be used to populate default attributes for
+entries. Defaults is *not* a Generator plugin, so it does not
+actually bind an entry; Defaults are applied after an entry has been
+bound, and only populate attributes that are not yet set.
+
+Like :ref:`server-plugins-generators-rules`, Defaults supports regular
+expressions in the name attribute.
+
+For instance, to make all Service entries use the ``systemd`` tool
+on Fedora 15 and the ``chkconfig`` tool on Fedora 14, you could do::
+
+ <Defaults priority="0">
+ <Group name="fedora-15">
+ <Service name=".*" type="systemd"/>
+ </Group>
+ <Group name="fedora-14">
+ <Service name=".*" type="chkconfig"/>
+ </Group>
+ </Defaults>
+
+If you were to specify a ``type`` attribute for a Service entry in
+Rules (or a ``type`` attribute for a BoundService entry in Bundler),
+that would take precendence over the default.
diff --git a/schemas/defaults.xsd b/schemas/defaults.xsd
new file mode 100644
index 000000000..d449f023a
--- /dev/null
+++ b/schemas/defaults.xsd
@@ -0,0 +1,68 @@
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xml:lang="en">
+
+ <xsd:annotation>
+ <xsd:documentation>
+ string enumeration definitions for bcfg2
+ Narayan Desai, Argonne National Laboratory
+ $Id$
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:include schemaLocation="servicetype.xsd"/>
+ <xsd:include schemaLocation="types.xsd"/>
+ <xsd:include schemaLocation="pkgtype.xsd"/>
+
+ <xsd:complexType name="ActionType">
+ <xsd:attribute type="ActionTimingEnum" name="timing"/>
+ <xsd:attribute type="ActionWhenEnum" name="when"/>
+ <xsd:attribute type="ActionStatusEnum" name="status"/>
+ <xsd:attribute type="xsd:string" name="name" use="required"/>
+ <xsd:attribute type="xsd:string" name="command"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="PathType">
+ <xsd:attribute type="PathTypeEnum" name="type"/>
+ <xsd:attribute type="xsd:string" name="name" use="required"/>
+ <xsd:attribute type="xsd:string" name="dev_type"/>
+ <xsd:attribute type="xsd:string" name="major"/>
+ <xsd:attribute type="xsd:string" name="minor"/>
+ <xsd:attribute type="xsd:string" name="mode"/>
+ <xsd:attribute type="xsd:string" name="perms"/>
+ <xsd:attribute type="xsd:string" name="owner"/>
+ <xsd:attribute type="xsd:string" name="group"/>
+ <xsd:attribute type="xsd:string" name="recursive"/>
+ <xsd:attribute type="xsd:string" name="prune"/>
+ <xsd:attribute type="xsd:string" name="to"/>
+ <xsd:attribute type="xsd:string" name="vcstype"/>
+ <xsd:attribute type="xsd:string" name="revision"/>
+ <xsd:attribute type="xsd:string" name="sourceurl"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="DContainerType">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="Service" type="ServiceType"/>
+ <xsd:element name="Package" type="PackageType"/>
+ <xsd:element name="Path" type="PathType"/>
+ <xsd:element name="Action" type="ActionType"/>
+ <xsd:element name="Group" type="DContainerType"/>
+ <xsd:element name="Client" type="DContainerType"/>
+ </xsd:choice>
+ <xsd:attribute name="name" type="xsd:string"/>
+ <xsd:attribute name="negate" type="xsd:boolean"/>
+ </xsd:complexType>
+
+ <xsd:element name="Defaults">
+ <xsd:complexType>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="Service" type="ServiceType"/>
+ <xsd:element name="Package" type="PackageType"/>
+ <xsd:element name="Path" type="PathType"/>
+ <xsd:element name="Action" type="ActionType"/>
+ <xsd:element name="PostInstall" type="PostInstallType"/>
+ <xsd:element name="Group" type="DContainerType"/>
+ <xsd:element name="Client" type="DContainerType"/>
+ </xsd:choice>
+ <xsd:attribute name="priority" type="xsd:integer" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+</xsd:schema>
diff --git a/schemas/pkgtype.xsd b/schemas/pkgtype.xsd
index 70a466448..6c3821f82 100644
--- a/schemas/pkgtype.xsd
+++ b/schemas/pkgtype.xsd
@@ -13,20 +13,20 @@
<xsd:import namespace="http://genshi.edgewall.org/"
schemaLocation="genshi.xsd"/>
- <xsd:complexType name='PackageType'>
- <xsd:choice minOccurs='0' maxOccurs='unbounded'>
- <xsd:element name='Instance'>
+ <xsd:complexType name="PackageType">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="Instance">
<xsd:complexType>
- <xsd:attribute name='arch' type='xsd:string'/>
- <xsd:attribute name='epoch' type='xsd:string'/>
- <xsd:attribute name='version' type='xsd:string'/>
- <xsd:attribute name='release' type='xsd:string'/>
- <xsd:attribute name='simplefile' type='xsd:string'/>
- <xsd:attribute name='pkg_verify' type='xsd:string'/>
- <xsd:attribute name='verify_flags' type='xsd:string'/>
- <xsd:attribute name='installed_action' type='xsd:string'/>
- <xsd:attribute name='version_fail_action' type='xsd:string'/>
- <xsd:attribute name='verify_fail_action' type='xsd:string'/>
+ <xsd:attribute name="arch" type="xsd:string"/>
+ <xsd:attribute name="epoch" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="release" type="xsd:string"/>
+ <xsd:attribute name="simplefile" type="xsd:string"/>
+ <xsd:attribute name="pkg_verify" type="xsd:boolean"/>
+ <xsd:attribute name="verify_flags" type="xsd:string"/>
+ <xsd:attribute name="installed_action" type="xsd:string"/>
+ <xsd:attribute name="version_fail_action" type="xsd:string"/>
+ <xsd:attribute name="verify_fail_action" type="xsd:string"/>
<xsd:attributeGroup ref="py:genshiAttrs"/>
</xsd:complexType>
</xsd:element>
@@ -38,17 +38,17 @@
<xsd:element ref="py:with"/>
<xsd:element ref="py:replace"/>
</xsd:choice>
- <xsd:attribute type='xsd:string' name='name' use="required"/>
- <xsd:attribute type='xsd:string' name='version'/>
- <xsd:attribute type='xsd:string' name='file'/>
- <xsd:attribute type='xsd:string' name='verify'/>
- <xsd:attribute type='xsd:string' name='simplefile'/>
- <xsd:attribute type='xsd:string' name='multiarch'/>
- <xsd:attribute type='xsd:string' name='srcs'/>
- <xsd:attribute type='xsd:string' name='type'/>
- <xsd:attribute type='xsd:string' name='bname'/>
- <xsd:attribute name='pkg_checks' type='xsd:string'/>
- <xsd:attribute name='verify_flags' type='xsd:string'/>
+ <xsd:attribute type="xsd:string" name="name" use="required"/>
+ <xsd:attribute type="xsd:string" name="version"/>
+ <xsd:attribute type="xsd:string" name="file"/>
+ <xsd:attribute type="xsd:boolean" name="verify"/>
+ <xsd:attribute type="xsd:string" name="simplefile"/>
+ <xsd:attribute type="xsd:string" name="multiarch"/>
+ <xsd:attribute type="xsd:string" name="srcs"/>
+ <xsd:attribute type="PackageTypeEnum" name="type"/>
+ <xsd:attribute type="xsd:string" name="bname"/>
+ <xsd:attribute name="pkg_checks" type="xsd:string"/>
+ <xsd:attribute name="verify_flags" type="xsd:string"/>
<xsd:attributeGroup ref="py:genshiAttrs"/>
</xsd:complexType>
</xsd:schema>
diff --git a/schemas/rules.xsd b/schemas/rules.xsd
index 5446f9a95..3d9870dfb 100644
--- a/schemas/rules.xsd
+++ b/schemas/rules.xsd
@@ -16,11 +16,11 @@
schemaLocation="genshi.xsd"/>
<xsd:complexType name='ActionType'>
- <xsd:attribute type='ActionTimingEnum' name='timing' use='required'/>
- <xsd:attribute type='ActionWhenEnum' name='when' use='required'/>
- <xsd:attribute type='ActionStatusEnum' name='status' use='required'/>
- <xsd:attribute type='xsd:string' name='name' use='required'/>
- <xsd:attribute type='xsd:string' name='command' use='required'/>
+ <xsd:attribute type='ActionTimingEnum' name='timing'/>
+ <xsd:attribute type='ActionWhenEnum' name='when'/>
+ <xsd:attribute type='ActionStatusEnum' name='status'/>
+ <xsd:attribute type='xsd:string' name='name'/>
+ <xsd:attribute type='xsd:string' name='command'/>
<xsd:attributeGroup ref="py:genshiAttrs"/>
</xsd:complexType>
diff --git a/schemas/servicetype.xsd b/schemas/servicetype.xsd
index 07971a427..f88260c39 100644
--- a/schemas/servicetype.xsd
+++ b/schemas/servicetype.xsd
@@ -9,15 +9,16 @@
</xsd:documentation>
</xsd:annotation>
+ <xsd:include schemaLocation="types.xsd"/>
<xsd:import namespace="http://genshi.edgewall.org/"
schemaLocation="genshi.xsd"/>
- <xsd:complexType name='ServiceType'>
- <xsd:choice minOccurs='0' maxOccurs='unbounded'>
- <xsd:element name='User'>
+ <xsd:complexType name="ServiceType">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="User">
<xsd:complexType>
- <xsd:attribute name='address' type='xsd:string' use='required'/>
- <xsd:attribute name='mask' type='xsd:string' use='required'/>
+ <xsd:attribute name="address" type="xsd:string" use="required"/>
+ <xsd:attribute name="mask" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element ref="py:def"/>
@@ -28,18 +29,18 @@
<xsd:element ref="py:with"/>
<xsd:element ref="py:replace"/>
</xsd:choice>
- <xsd:attribute name='name' type='xsd:string' use='required'/>
- <xsd:attribute name='status' type='xsd:string' use='required'/>
- <xsd:attribute name='type' type='xsd:string' use='required'/>
- <xsd:attribute name='port' type='xsd:string'/>
- <xsd:attribute name='protocol' type='xsd:string'/>
- <xsd:attribute name='mode' type='xsd:string'/>
- <xsd:attribute name='custom' type='xsd:string'/>
- <xsd:attribute name='FMRI' type='xsd:string'/>
- <xsd:attribute name='supervised' type='xsd:string'/>
- <xsd:attribute name='sequence' type='xsd:string'/>
- <xsd:attribute name='target' type='xsd:string'/>
- <xsd:attribute name='parameters' type='xsd:string'/>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="status" type="StatusEnum"/>
+ <xsd:attribute name="type" type="ServiceTypeEnum"/>
+ <xsd:attribute name="port" type="xsd:string"/>
+ <xsd:attribute name="protocol" type="xsd:string"/>
+ <xsd:attribute name="mode" type="xsd:string"/>
+ <xsd:attribute name="custom" type="xsd:string"/>
+ <xsd:attribute name="FMRI" type="xsd:string"/>
+ <xsd:attribute name="supervised" type="xsd:string"/>
+ <xsd:attribute name="sequence" type="xsd:string"/>
+ <xsd:attribute name="target" type="xsd:string"/>
+ <xsd:attribute name="parameters" type="xsd:string"/>
<xsd:attributeGroup ref="py:genshiAttrs"/>
</xsd:complexType>
diff --git a/schemas/types.xsd b/schemas/types.xsd
index 44d2d3df9..dde7a856b 100644
--- a/schemas/types.xsd
+++ b/schemas/types.xsd
@@ -39,6 +39,7 @@
<xsd:restriction base='xsd:string'>
<xsd:enumeration value='on'/>
<xsd:enumeration value='off'/>
+ <xsd:enumeration value="ignore"/>
</xsd:restriction>
</xsd:simpleType>
@@ -64,4 +65,17 @@
</xsd:restriction>
</xsd:simpleType>
+ <xsd:simpleType name="ServiceTypeEnum">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="chkconfig"/>
+ <xsd:enumeration value="deb"/>
+ <xsd:enumeration value="rc-update"/>
+ <xsd:enumeration value="smf"/>
+ <xsd:enumeration value="upstart"/>
+ <xsd:enumeration value="systemd"/>
+ <xsd:enumeration value="launchd"/>
+ <xsd:enumeration value="freebsd"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
</xsd:schema>
diff --git a/src/lib/Server/Lint/MergeFiles.py b/src/lib/Server/Lint/MergeFiles.py
index 27e7aa99a..52fea3d9b 100644
--- a/src/lib/Server/Lint/MergeFiles.py
+++ b/src/lib/Server/Lint/MergeFiles.py
@@ -1,7 +1,6 @@
import os
from copy import deepcopy
from difflib import SequenceMatcher
-import Bcfg2.Options
import Bcfg2.Server.Lint
class MergeFiles(Bcfg2.Server.Lint.ServerPlugin):
@@ -27,10 +26,10 @@ class MergeFiles(Bcfg2.Server.Lint.ServerPlugin):
def check_probes(self):
probes = self.core.plugins['Probes'].probes.entries
for mset in self.get_similar(probes):
- self.LintError("merge-cfg",
- "The following probes are similar: %s. "
- "Consider merging them into a single probe." %
- ", ".join([p for p in mset]))
+ self.LintError("merge-cfg",
+ "The following probes are similar: %s. "
+ "Consider merging them into a single probe." %
+ ", ".join([p for p in mset]))
def get_similar(self, entries):
if "threshold" in self.config:
diff --git a/src/lib/Server/Lint/RequiredAttrs.py b/src/lib/Server/Lint/RequiredAttrs.py
index a94bbb3ed..4d4e99f32 100644
--- a/src/lib/Server/Lint/RequiredAttrs.py
+++ b/src/lib/Server/Lint/RequiredAttrs.py
@@ -10,20 +10,33 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin):
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']}
+ 'Path': {
+ 'device': ['name', 'owner', 'group', 'dev_type'],
+ 'directory': ['name', 'owner', 'group', 'perms'],
+ 'file': ['name', 'owner', 'group', 'perms', '__text__'],
+ 'hardlink': ['name', 'to'],
+ 'symlink': ['name', 'to'],
+ 'ignore': ['name'],
+ 'nonexistent': ['name'],
+ 'permissions': ['name', 'owner', 'group', 'perms'],
+ 'vcs': ['vcstype', 'revision', 'sourceurl']},
+ 'Service': {
+ 'chkconfig': ['name'],
+ 'deb': ['name'],
+ 'rc-update': ['name'],
+ 'smf': ['name', 'FMRI'],
+ 'upstart': ['name']},
+ 'Action': ['name', 'timing', 'when', 'status', 'command'],
+ 'Package': ['name']}
def Run(self):
- self.check_rules()
- self.check_bundles()
self.check_packages()
+ if "Defaults" in self.core.plugins:
+ self.logger.info("Defaults plugin enabled; skipping required "
+ "attribute checks")
+ else:
+ self.check_rules()
+ self.check_bundles()
def check_packages(self):
""" check package sources for Source entries with missing attrs """
@@ -70,22 +83,34 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin):
except (lxml.etree.XMLSyntaxError, AttributeError):
xdata = lxml.etree.parse(bundle.template.filepath).getroot()
- for path in xdata.xpath("//BoundPath"):
+ for path in xdata.xpath("//*[substring(name(), 1, 5) = 'Bound']"):
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
+ name = entry.get('name')
+ tag = entry.tag
+ if tag.startswith("Bound"):
+ tag = tag[5:]
+ if tag not in self.required_attrs:
+ self.LintError("unknown-entry-tag",
+ "Unknown entry tag '%s': %s" %
+ (entry.tag, self.RenderXML(entry)))
+
+ if isinstance(self.required_attrs[tag], dict):
+ etype = entry.get('type')
+ if etype in self.required_attrs[tag]:
+ required_attrs = set(self.required_attrs[tag][etype] +
+ ['type'])
+ else:
+ self.LintError("unknown-entry-type",
+ "Unknown %s type %s: %s" %
+ (tag, etype, self.RenderXML(entry)))
+ return
+ else:
+ required_attrs = set(self.required_attrs[tag])
+ attrs = set(entry.attrib.keys())
if 'dev_type' in required_attrs:
dev_type = entry.get('dev_type')
@@ -93,17 +118,20 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin):
# 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 '__text__' in required_attrs:
+ required_attrs.pop('__text__')
+ if not entry.text:
+ self.LintError("required-attrs-missing",
+ "Text missing for %s %s in %s: %s" %
+ (entry.tag, name, filename,
+ self.RenderXML(entry)))
- if not pathset.issuperset(required_attrs):
+ if not attrs.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,
+ "The following required attribute(s) are "
+ "missing for %s %s in %s: %s\n%s" %
+ (entry.tag, name, filename,
+ ", ".join([attr
+ for attr in
+ required_attrs.difference(attrs)]),
self.RenderXML(entry)))
diff --git a/src/lib/Server/Lint/Validate.py b/src/lib/Server/Lint/Validate.py
index ebf621c22..19fd61d25 100644
--- a/src/lib/Server/Lint/Validate.py
+++ b/src/lib/Server/Lint/Validate.py
@@ -5,7 +5,6 @@ import os
from subprocess import Popen, PIPE, STDOUT
import sys
-import Bcfg2.Options
import Bcfg2.Server.Lint
class Validate(Bcfg2.Server.Lint.ServerlessPlugin):
@@ -21,6 +20,7 @@ class Validate(Bcfg2.Server.Lint.ServerlessPlugin):
"%s/Pkgmgr/*.xml":"%s/pkglist.xsd",
"%s/Base/*.xml":"%s/base.xsd",
"%s/Rules/*.xml":"%s/rules.xsd",
+ "%s/Defaults/*.xml":"%s/defaults.xsd",
"%s/etc/report-configuration.xml":"%s/report-configuration.xsd",
"%s/Svcmgr/*.xml":"%s/services.xsd",
"%s/Deps/*.xml":"%s/deps.xsd",
@@ -45,21 +45,21 @@ class Validate(Bcfg2.Server.Lint.ServerlessPlugin):
if filelist:
# avoid loading schemas for empty file lists
+ schemafile = schemaname % schemadir
try:
- schema = lxml.etree.XMLSchema(lxml.etree.parse(schemaname %
- schemadir))
+ schema = lxml.etree.XMLSchema(lxml.etree.parse(schemafile))
except IOError:
e = sys.exc_info()[1]
- self.LintError("input-output-error", e.message)
+ self.LintError("input-output-error", str(e))
continue
- except:
+ except lxml.etree.XMLSchemaParseError:
+ e = sys.exc_info()[1]
self.LintError("schema-failed-to-parse",
- "Failed to process schema %s" %
- (schemaname % schemadir))
+ "Failed to process schema %s: %s" %
+ (schemafile, e))
continue
for filename in filelist:
- self.validate(filename, schemaname % schemadir,
- schema=schema)
+ self.validate(filename, schemafile, schema=schema)
self.check_properties()
diff --git a/src/lib/Server/Lint/__init__.py b/src/lib/Server/Lint/__init__.py
index f15c90557..f47059ac4 100644
--- a/src/lib/Server/Lint/__init__.py
+++ b/src/lib/Server/Lint/__init__.py
@@ -107,7 +107,7 @@ class ErrorHandler (object):
"duplicate-package":"error",
"multiple-default-groups":"error",
"required-infoxml-attrs-missing":"error",
- "unknown-path-type":"error",
+ "unknown-entry-type":"error",
"required-attrs-missing":"error",
"extra-attrs":"warning",
"schema-failed-to-parse":"warning",
diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py
index bf55ad271..36423e5cd 100644
--- a/src/lib/Server/Plugin.py
+++ b/src/lib/Server/Plugin.py
@@ -789,10 +789,10 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked):
def get_attrs(self, entry, metadata):
""" get a list of attributes to add to the entry during the bind """
- if False in [src.Cache(metadata)
- for src in list(self.entries.values())]:
- self.logger.error("Called before data loaded")
- raise PluginExecutionError
+ for src in list(self.entries.values()):
+ if src.Cache(metadata) == False:
+ self.logger.error("Called before data loaded")
+ raise PluginExecutionError
matching = [src for src in list(self.entries.values())
if (src.cache and
entry.tag in src.cache[1] and
diff --git a/src/lib/Server/Plugins/Defaults.py b/src/lib/Server/Plugins/Defaults.py
new file mode 100644
index 000000000..23104946e
--- /dev/null
+++ b/src/lib/Server/Plugins/Defaults.py
@@ -0,0 +1,51 @@
+"""This generator provides rule-based entry mappings."""
+__revision__ = '$Revision$'
+
+import re
+import Bcfg2.Server.Plugin
+import Bcfg2.Server.Plugins.Rules
+
+class Defaults(Bcfg2.Server.Plugins.Rules.Rules,
+ Bcfg2.Server.Plugin.StructureValidator):
+ """Set default attributes on bound entries"""
+ name = 'Defaults'
+ __version__ = '$Id$'
+ __author__ = 'bcfg-dev@mcs.anl.gov'
+
+ # Rules is a Generator that happens to implement all of the
+ # functionality we want, so we overload it, but Defaults should
+ # _not_ handle any entries; it does its stuff in the structure
+ # validation phase. so we overload Handle(s)Entry and HandleEvent
+ # to ensure that Defaults handles no entries, even though it's a
+ # Generator.
+
+ def HandlesEntry(self, entry, metadata):
+ return False
+
+ def HandleEntry(self, entry, metadata):
+ raise PluginExecutionError
+
+ def HandleEvent(self, event):
+ Bcfg2.Server.Plugin.XMLDirectoryBacked.HandleEvent(self, event)
+
+ def validate_structures(self, metadata, structures):
+ """ Apply defaults """
+ for struct in structures:
+ for entry in struct.iter():
+ if entry.tag.startswith("Bound"):
+ is_bound = True
+ entry.tag = entry.tag[5:]
+ else:
+ is_bound = False
+ try:
+ try:
+ self.BindEntry(entry, metadata)
+ except Bcfg2.Server.Plugin.PluginExecutionError:
+ # either no matching defaults (which is okay),
+ # or multiple matching defaults (which is not
+ # okay, but is logged). either way, we don't
+ # care about the error.
+ pass
+ finally:
+ if is_bound:
+ entry.tag = "Bound" + entry.tag