summaryrefslogtreecommitdiffstats
path: root/doc/server/plugins/generators/tgenshi.txt
blob: 43a02f253e7c1887fb2a8b4216d20517f64978c1 (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
.. -*- mode: rst -*-

.. _server-plugins-generators-tgenshi-index:

=======
TGenshi
=======

.. warning::

    The TGenshi plugin is deprecated.  You should instead use
    :ref:`server-plugins-generators-cfg-genshi` in the Cfg plugin.

This page documents the TGenshi plugin. This plugin works with version
0.4 and newer of the genshi library.

The TGenshi plugin allows you to use the `Genshi
<http://genshi.edgewall.org>`_ templating system to create files,
instead of the various diff-based methods offered by the Cfg
plugin. It also allows you to include the results of probes executed
on the client in the created files.

To begin, you will need to download and install the Genshi templating engine.

To install on CentOS or RHEL, run::

    sudo yum install python-genshi

Once it is installed, you can enable it by adding ``TGenshi`` to the
generators line in ``/etc/bcfg2.conf`` on your Bcfg server. For example::

    plugins = Base,Bundler,Cfg,...,TGenshi

The TGenshi plugin makes use of a Cfg-like directory structure
located in in a TGenshi subdirectory of your repository, usually
``/var/lib/bcfg2/TGenshi``. Each file has a directory containing two file
types, template and info. Templates are named according to the genshi
format used; template.txt uses the genshi text format, and template.xml
uses the XML format.

If used with Genshi 0.5 or later the plugin also supports the `new
style
<http://genshi.edgewall.org/wiki/Documentation/0.5.x/text-templates.html>`_
text template format for files named template.newtxt. One of the
advantages of the new format is that it does not use # as a command
delimiter, making it easier to utilize for configuration files that
use # as a comment character.

Only one template format may be used per file served. Info files are
identical to those used in ``Cfg``, and ``info.xml`` files are
supported.

Inside of templates
===================

* **metadata** is the client's :ref:`metadata
  <server-plugins-grouping-metadata-clientmetadata>`
* **metadata.Properties** is an xml document of unstructured data (only
  available when used in conjunction with the
  :ref:`server-plugins-connectors-properties` plugin)
* **name** is the path name specified in bcfg
* **path** is the path to the TGenshi template.  It starts with a
    leading slash, and is relative to the Bcfg2 specification root.
    E.g., ``/Cfg/etc/foo.conf/foo.conf.genshi`` or
    ``/TGenshi/etc/foo.conf/template.newtxt.H_foo.example.com``

See the genshi `documentation
<http://genshi.edgewall.org/wiki/Documentation>`_ for examples of
Genshi syntax.

Examples: Old Genshi Syntax
---------------------------

Genshi's web pages recommend against using this syntax, as it may
disappear from future releases.

Group Negation
^^^^^^^^^^^^^^

Templates are also useful for cases where more sophisticated boolean
operations than those supported by Cfg are needed. For example, the
template::

    #if "ypbound" in metadata.groups and "workstation" in metadata.groups
    client is ypbound workstation
    #end
    #if "ubuntu" not in metadata.groups and "desktop" in metadata.groups
    client is a desktop, but not an ubuntu desktop
    #end

Produces:

.. code-block:: xml

    <Path type="file" name="/bar.conf" owner="root" mode="0644" group="root">client is ypbound workstation
    client is a desktop, but not an ubuntu desktop
    </Path>

This flexibility provides the ability to build much more compact and
succinct definitions of configuration contents than Cfg can.

Troubleshooting
===============

When developing a template, you can see what the template would
generate on a client with :ref:`bcfg2-info <server-bcfg2-info>`::

    bcfg2-info buildfile <path> <hostname>

E.g.::

    bcfg2-info buildfile /etc/foo.conf foo.example.com

To generate a file with an altsrc attribute, you can run::

    bcfg2-info buildfile /etc/foo/foo.conf --altsrc=/etc/foo.conf \
        foo.example.com

Sometimes, it's useful to be able to do more in-depth troubleshooting
by running the template manually. To do this, run ``bcfg2-info
debug``, and, once in the Python interpreter, run::

    metadata = self.build_metadata("<hostname>")
    path = "<relative path to template (see note below)>"
    
``path`` should be set to the path to the template file with a leading
slash, relative to the Bcfg2 specification root. See `Inside of
Templates`_ for examples.

Then, run::
    
    import os, Bcfg2.Options
    from genshi.template import TemplateLoader, NewTextTemplate
    name = os.path.dirname(path[path.find('/', 1):])
    setup = Bcfg2.Options.OptionParser({'repo':
                                        Bcfg2.Options.SERVER_REPOSITORY})
    setup.parse('--')
    template = TemplateLoader().load(setup['repo'] + path, cls=NewTextTemplate)
    print template.generate(metadata=metadata, path=path, name=name).render()

This gives you more fine-grained control over how your template is
rendered.

You can also use this approach to render templates that depend on
:ref:`altsrc <server-plugins-structures-altsrc>` tags by setting
``path`` to the path to the template, and setting ``name`` to the path
to the file to be generated, e.g.::

    metadata = self.build_metadata("foo.example.com")
    path = "/Cfg/etc/sysconfig/network-scripts/ifcfg-template/ifcfg-template.genshi"
    name = "/etc/sysconfig/network-scripts/ifcfg-bond0"

File permissions
================

File permissions for entries handled by TGenshi are controlled via the
use of :ref:`server-info` files. Note that you **cannot** use both a
Permissions entry and a Path entry to handle the same file.

Error handling
================

Situations may arise where a templated file cannot be generated due to
missing or incomplete information.  A TemplateError can be raised to
force a bind failure and prevent sending an incomplete file to the
client.  For example, this template::

    {% python
        from genshi.template import TemplateError
        grp = None
        for g in metadata.groups:
            if g.startswith('ganglia-gmond-'):
                grp = g
                break
        else:
            raise TemplateError, "Missing group"
    %}\

will fail to bind if the client is not a member of a group starting with
"ganglia-gmond-".  The syslogs on the server will contain this message::

    bcfg2-server[5957]: Genshi template error: Missing group
    bcfg2-server[5957]: Failed to bind entry: Path /etc/ganglia/gmond.conf

indicating the bind failure and message raised with the TemplateError.

FAQs
====

**Question**

How do I escape the $ (dollar sign) in a TGenshi text template? For
example, if I want to include SVN (subversion) keywords like $Id$ or
$HeadURL$ in TGenshi-generated files, or am templating a bourne shell
(sh/bash) script or Makefile (make).

**Answer**

Use $$ (double dollar sign) to output a literal $ (dollarsign)
in a TGenshi text template. So instead of $Id$, you'd use
$$Id$$. See also Genshi tickets `#282: Document $$ escape
convention <http://genshi.edgewall.org/ticket/282>`_ and
`#283: Allow for redefinition of template syntax per-file
<http://genshi.edgewall.org/ticket/283>`_.

Examples
========

.. toctree::
   :glob:
   :maxdepth: 1

   examples/genshi/*