summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/server/plugins/connectors/properties.txt17
-rw-r--r--doc/server/plugins/structures/bundler/index.txt44
-rw-r--r--schemas/bundle.xsd16
-rw-r--r--schemas/info.xsd3
-rw-r--r--src/lib/Server/Plugin.py34
-rw-r--r--src/lib/Server/Plugins/Properties.py10
6 files changed, 84 insertions, 40 deletions
diff --git a/doc/server/plugins/connectors/properties.txt b/doc/server/plugins/connectors/properties.txt
index ef408916e..9fb0dba87 100644
--- a/doc/server/plugins/connectors/properties.txt
+++ b/doc/server/plugins/connectors/properties.txt
@@ -41,9 +41,20 @@ templates as ``metadata.Properties[<filename>]``. The
data attribute is an LXML element object. (Documented
`here <http://codespeak.net/lxml/tutorial.html#the-element-class>`_)
-Currently, no access methods are defined for this data, but as we
-formulate common use cases, we will add them to the !PropertyFile class
-as methods. This will simplify templates.
+Currently, only one access method is defined for this data, ``Match``.
+``Match`` parses the Group and Client tags in the file and returns a
+list of elements that apply to the client described by a set of
+metadata. (See :ref:`server-plugins-structures-bundler-index` for
+more details on how Group and Client tags are parsed.) For instance::
+
+ {% python
+ ntp_servers = [el.text
+ for el in metadata.Properties['ntp.xml'].Match(metadata):
+ if el.tag == "Server"]
+ %}
+
+As we formulate more common use cases, we will add them to the
+!PropertyFile class as methods. This will simplify templates.
Accessing Properties contents from TGenshi
==========================================
diff --git a/doc/server/plugins/structures/bundler/index.txt b/doc/server/plugins/structures/bundler/index.txt
index 0d0054a2c..c84d6cdbe 100644
--- a/doc/server/plugins/structures/bundler/index.txt
+++ b/doc/server/plugins/structures/bundler/index.txt
@@ -16,14 +16,15 @@ entries. For example, a bundle could say that the configuration file
describe the particular version of ``/etc/passwd`` that a given client
will receive.
-Groups can be used inside of bundles to differentiate which entries
-particular clients will recieve; this is useful for the case where
-entries are named differently across systems; for example, one linux
-distro may have a package called openssh while another uses the name
-ssh. Configuration entries nested inside of Group elements only apply
-to clients who are a member of those groups; multiple nested groups must
-all apply. Also, groups may be negated; entries included in such groups
-will only apply to clients who are not a member of said group.
+Group and Client tags can be used inside of bundles to differentiate
+which entries particular clients will recieve; this is useful for the
+case where entries are named differently across systems; for example,
+one linux distro may have a package called openssh while another uses
+the name ssh. Configuration entries nested inside of Group elements
+only apply to clients who are a member of those groups; multiple
+nested groups must all apply. Also, groups may be negated; entries
+included in such groups will only apply to clients who are not a
+member of said group. The same applies to Client elements.
The following is an annotated copy of a bundle:
@@ -54,20 +55,25 @@ The following is an annotated copy of a bundle:
<Package name='ssh'/>
<Service name='ssh'/>
</Group>
+ <Client name='trust.example.com'>
+ <Path name='/etc/ssh/shosts.equiv'/>
+ </Client>
</Bundle>
-In this bundle, most of the entries are common to all systems. Clients in
-group **deb** get one extra package and service, while clients in group
-**rpm** get two extra packages and an extra service. In addition, clients
-in group **fedora** *and* group **rpm** get one extra package entries,
-unless they are not in the **fc14** group, in which case, they get an
-extra package. Notice that this file doesn't describe which versions
-of these entries that clients should get, only that they should get
-them. (Admittedly, this example is slightly contrived, but demonstrates
-how group entries can be used in bundles)
+In this bundle, most of the entries are common to all systems. Clients
+in group **deb** get one extra package and service, while clients in
+group **rpm** get two extra packages and an extra service. In
+addition, clients in group **fedora** *and* group **rpm** get one
+extra package entries, unless they are not in the **fc14** group, in
+which case, they get an extra package. The client
+**trust.example.com** gets one extra file that is not distributed to
+any other clients. Notice that this file doesn't describe which
+versions of these entries that clients should get, only that they
+should get them. (Admittedly, this example is slightly contrived, but
+demonstrates how group entries can be used in bundles)
+----------------------------+-------------------------------+
-| Group | Entry |
+| Group/Hostname | Entry |
+============================+===============================+
| all | /etc/ssh/ssh_host_dsa_key |
+----------------------------+-------------------------------+
@@ -101,6 +107,8 @@ how group entries can be used in bundles)
+----------------------------+-------------------------------+
| deb | Service ssh |
+----------------------------+-------------------------------+
+| trust.example.com | /etc/ssh/shosts.equiv |
++----------------------------+-------------------------------+
Genshi templates
================
diff --git a/schemas/bundle.xsd b/schemas/bundle.xsd
index 1ea44c991..b226e1078 100644
--- a/schemas/bundle.xsd
+++ b/schemas/bundle.xsd
@@ -93,6 +93,14 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
+ <xsd:element name='Client' type='GroupType'>
+ <xsd:annotation>
+ <xsd:documentation>
+ Elements within Client tags only apply to the named client
+ (or vice-versa; see #element_negate below)
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
<xsd:element ref="py:def"/>
<xsd:element ref="py:match"/>
<xsd:element ref="py:choose"/>
@@ -207,6 +215,14 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
+ <xsd:element name='Client' type='GroupType'>
+ <xsd:annotation>
+ <xsd:documentation>
+ Elements within Client tags only apply to the named client
+ (or vice-versa; see #element_negate below)
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
<xsd:element ref="py:def"/>
<xsd:element ref="py:match"/>
<xsd:element ref="py:choose"/>
diff --git a/schemas/info.xsd b/schemas/info.xsd
index 983513d66..96ccbe56c 100644
--- a/schemas/info.xsd
+++ b/schemas/info.xsd
@@ -22,6 +22,8 @@
<xsd:element name='Info' type='InfoType'/>
<xsd:element name='Group' type='GroupType' minOccurs='0'
maxOccurs='unbounded'/>
+ <xsd:element name='Client' type='GroupType' minOccurs='0'
+ maxOccurs='unbounded'/>
</xsd:choice>
<xsd:attribute type='xsd:string' name='name' use='required'/>
<xsd:attribute type='xsd:boolean' name='negate' />
@@ -31,6 +33,7 @@
<xsd:complexType>
<xsd:choice minOccurs='0' maxOccurs='unbounded'>
<xsd:element name='Group' type='GroupType'/>
+ <xsd:element name='Client' type='GroupType'/>
<xsd:element name='Info' type='InfoType'/>
</xsd:choice>
</xsd:complexType>
diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py
index ac9479d44..69b38c4ff 100644
--- a/src/lib/Server/Plugin.py
+++ b/src/lib/Server/Plugin.py
@@ -457,17 +457,29 @@ class StructFile(XMLFileBacked):
work = {lambda x: True: xdata.getchildren()}
while work:
(predicate, worklist) = work.popitem()
- self.fragments[predicate] = [item for item in worklist if item.tag != 'Group'
- and not isinstance(item, lxml.etree._Comment)]
- for group in [item for item in worklist if item.tag == 'Group']:
- # if only python had forceable early-binding
- if group.get('negate', 'false') in ['true', 'True']:
- cmd = "lambda x:'%s' not in x.groups and predicate(x)"
- else:
- cmd = "lambda x:'%s' in x.groups and predicate(x)"
-
- newpred = eval(cmd % (group.get('name')), {'predicate': predicate})
- work[newpred] = group.getchildren()
+ self.fragments[predicate] = \
+ [item for item in worklist
+ if (item.tag != 'Group' and
+ item.tag != 'Client' and
+ not isinstance(item,
+ lxml.etree._Comment))]
+ for item in worklist:
+ cmd = None
+ if item.tag == 'Group':
+ if item.get('negate', 'false').lower() == 'true':
+ cmd = "lambda x:'%s' not in x.groups and predicate(x)"
+ else:
+ cmd = "lambda x:'%s' in x.groups and predicate(x)"
+ elif item.tag == 'Client':
+ if item.get('negate', 'false').lower() == 'true':
+ cmd = "lambda x:x.hostname != '%s' and predicate(x)"
+ else:
+ cmd = "lambda x:x.hostname == '%s' and predicate(x)"
+ # else, ignore item
+ if cmd is not None:
+ newpred = eval(cmd % item.get('name'),
+ {'predicate':predicate})
+ work[newpred] = item.getchildren()
def Match(self, metadata):
"""Return matching fragments of independent."""
diff --git a/src/lib/Server/Plugins/Properties.py b/src/lib/Server/Plugins/Properties.py
index 2888ef1d1..c5d2acc44 100644
--- a/src/lib/Server/Plugins/Properties.py
+++ b/src/lib/Server/Plugins/Properties.py
@@ -4,15 +4,9 @@ import lxml.etree
import Bcfg2.Server.Plugin
-class PropertyFile(Bcfg2.Server.Plugin.XMLFileBacked):
+class PropertyFile(Bcfg2.Server.Plugin.StructFile):
"""Class for properties files."""
-
- def Index(self):
- """Build data into an xml object."""
- try:
- self.data = lxml.etree.XML(self.data)
- except lxml.etree.XMLSyntaxError:
- Bcfg2.Server.Plugin.logger.error("Failed to parse %s" % self.name)
+ pass
class PropDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked):