diff options
author | Chris St. Pierre <chris.a.st.pierre@gmail.com> | 2011-09-19 11:04:03 -0400 |
---|---|---|
committer | Chris St. Pierre <chris.a.st.pierre@gmail.com> | 2011-09-19 11:04:03 -0400 |
commit | fe9b75662276326898458a68744b920ebd9d46b8 (patch) | |
tree | 999cf9ca885d38e23305408b37ff0b662686832d | |
parent | e6489338056d55805a66383bcd5cda6ed8caa22b (diff) | |
download | bcfg2-fe9b75662276326898458a68744b920ebd9d46b8.tar.gz bcfg2-fe9b75662276326898458a68744b920ebd9d46b8.tar.bz2 bcfg2-fe9b75662276326898458a68744b920ebd9d46b8.zip |
added Defaults plugin
-rw-r--r-- | doc/server/plugins/generators/rules.txt | 70 | ||||
-rw-r--r-- | doc/server/plugins/structures/defaults.txt | 31 | ||||
-rw-r--r-- | schemas/defaults.xsd | 68 | ||||
-rw-r--r-- | schemas/pkgtype.xsd | 48 | ||||
-rw-r--r-- | schemas/rules.xsd | 10 | ||||
-rw-r--r-- | schemas/servicetype.xsd | 35 | ||||
-rw-r--r-- | schemas/types.xsd | 14 | ||||
-rw-r--r-- | src/lib/Server/Lint/MergeFiles.py | 9 | ||||
-rw-r--r-- | src/lib/Server/Lint/RequiredAttrs.py | 94 | ||||
-rw-r--r-- | src/lib/Server/Lint/Validate.py | 18 | ||||
-rw-r--r-- | src/lib/Server/Lint/__init__.py | 2 | ||||
-rw-r--r-- | src/lib/Server/Plugin.py | 8 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Defaults.py | 51 |
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 |