summaryrefslogtreecommitdiffstats
path: root/doc/server/plugins/structures/bundler/index.txt
blob: 31faeaf17348ec3b170c9166a850964f63749a4a (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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
.. -*- mode: rst -*-
.. vim: ft=rst

.. _server-plugins-structures-bundler:

=======
Bundler
=======

Bundler is used to describe groups of inter-dependent configuration
entries, such as the combination of packages, configuration files,
and service activations that comprise typical Unix daemons. Bundles are
used to add groups of configuration entries to the inventory of client
configurations, as opposed to describing particular versions of those
entries. For example, a bundle could say that the configuration file
``/etc/passwd`` should be included in a configuration, but will not
describe the particular version of ``/etc/passwd`` that a given client
will receive.

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``. See :ref:`xml-group-client-tags` for details
and a longer example.

A brief example:

.. code-block:: xml

    <Bundle>
      <Path name='/etc/ssh/ssh_config'/>
      <Group name='rpm'>
        <Service name='sshd'/>
        <Package name='openssh-server'/>
      </Group>
      <Group name='deb'>
        <Package name='ssh'/>
        <Service name='ssh'/>
      </Group>
    </Bundle>

Note that we do not specify *how* a given entry should be managed,
only that it should be.  The concrete specification of each entry will
be provided by a different plugin such as
:ref:`server-plugins-generators-cfg`,
:ref:`server-plugins-generators-rules`, or
:ref:`server-plugins-generators-packages`.

Alternatively, you can use fully-bound entries in Bundler, which has
various uses.  For instance:

.. code-block:: xml

    <Bundle>
      <Path name='/etc/ssh/ssh_config'/>
      <Group name='rpm'>
        <BoundService name='sshd' type="chkconfig" status="on"/>
        <BoundPackage name='openssh-server' version='5.8p2' type="yum" />
      </Group>
      <Group name='deb'>
        <Package name='ssh'/>
        <BoundService name='ssh' type="chkconfig" status="on"/>
      </Group>
    </Bundle>

In this example, both Service tags and one Package tag are fully bound
-- i.e., all information required by the client to manage those
entries is provided in the bundle itself.

.. _server-plugins-structures-bundler-magic:

Bundle "Magic"
==============

Bundles are collections of *related* entries.  That point is very,
very important, because a bundle performs certain "magic" actions when
one or more entries in it are modified:

* :xml:type:`Service <ServiceType>` entries whose ``restart``
  attribute is ``true`` (the default) will be restarted.
* :xml:type:`Action <ActionType>` entries whose ``when`` attribute is
  ``modified`` will be run.

Because of these two magic actions, it's extremely important to
structure your bundles around Service and Action entries, rather than
around some loose idea of which entries are related.  For instance, in
order to manage a Bcfg2 server, a number of packages, paths, services,
etc. must be managed.  But not all of these entries would require
``bcfg2-server`` to be restarted, so to limit restarts it's wise to
split these entries into two bundles.  See
:ref:`server-plugins-structures-bundler-bcfg2-server` for an example
of this.


.. _server-plugins-structures-bundler-index-disabling-magic:

Disabling Magic
---------------

Disabling magic bundler actions can be done in one of two ways:

* On a per-entry basis.  Set ``restart="false"`` on a Service to
  prevent it from being restarted when the bundle is modified.  Set
  ``when="always"`` on an Action to cause it to run every time,
  regardless of whether or not the bundle was modified.
* On a per-bundle basis.  Set ``independent="true"`` on the top-level
  ``Bundle`` tag to signify that the bundle is a collection of
  independent (i.e., unrelated) entries, and to prevent any magic
  actions from being performed.  (This is similar to the ``Base``
  plugin in older versions of Bcfg2.)  This was added in Bcfg2 1.4.

Service entries in independent bundles are never restarted, and Action
entries in independent bundles are only executed if ``when="always"``.
(I.e., an Action entry in an independent bundle with
``when="modified"`` is useless.)


.. _server-plugins-structures-bundler-index-genshi-templates:

Genshi templates
================

Genshi XML templates allow you to use the `Genshi
<http://genshi.edgewall.org>`_ templating system to dynamically
generate a bundle.  Genshi templates can be specified one of two ways:

1. Add an XML-style genshi template to the Bundler directory with a
   ``.genshi`` and the associated namespace attribute.  *This is
   deprecated as of Bcfg2 1.4.*
2. Add the Genshi namespace to your existing XML
   bundle.

See :ref:`xml-genshi-templating` for details.

Troubleshooting
---------------

To render a bundle for a given client, you can run::

    bcfg2-info buildbundle <bundle name> <hostname>

This will render the template; it will not fully bind all of the
entries in the bundle.

See :ref:`bcfg2-info <server-bcfg2-info>` for more details.


.. _server-plugins-structures-bundler-index-dependencies:

Dependencies
============

Dependencies on other bundles can be specified by adding an empty
bundle tag that adds another bundle by name, e.g.:

.. code-block:: xml

    <Bundle>
      <Bundle name="nfs-client"/>
      ...
    </Bundle>

The dependent bundle is added to the list of bundles sent to the
client, *not* to the parent bundle itself.  In other words, if an
entry in the dependent bundle changes, Services are restarted and
Actions are run in the dependent bundle *only*.  An example:

``nfs-client.xml``:

.. code-block:: xml

    <Bundle>
      <Package name="nfs-utils"/>
      <Service name="nfslock"/>
      <Service name="rpcbind"/>
      <Service name="nfs"/>
    </Bundle>

``automount.xml``:

.. code-block:: xml

    <Bundle>
      <Bundle name="nfs-client"/>

      <Path name="/mnt/home"/>
      <Path name="/etc/auto.master"/>
      <Path name="/etc/auto.misc"/>
      <Service name="autofs"/>
      <Package name="automount"/>
    </Bundle>

If a new ``nfs-utils`` package was installed, the ``nfslock``,
``rpcbind``, and ``nfs`` services would be restarted, but *not* the
``autofs`` service.  Similarly, if a new ``/etc/auto.misc`` file was
sent out, the ``autofs`` service would be restarted, but the
``nfslock``, ``rpcbind``, and ``nfs`` services would not be restarted.

Altsrc
======

.. toctree::
   :maxdepth: 1

   ../altsrc

Examples
========

In some cases, configuration files need to include the client's hostname
in their name. The following template produces such a config file entry.

.. code-block:: xml

    <Bundle xmlns:py="http://genshi.edgewall.org/">
      <Path name='/etc/package-${metadata.hostname}'/>
    </Bundle>

Depending on the circumstance, these configuration files can either be
handled by individual entries in :ref:`server-plugins-generators-cfg`,
or can be mapped to a single entry by using the
:ref:`server-plugins-structures-altsrc` feature.

In this example, configuration file names are built using probed results
from the client. getmac is a probe that gathers client MAC addresses
and returns them in a newline delimited string.

.. code-block:: xml

    <Bundle xmlns:py="http://genshi.edgewall.org/">
        <?python
          files = metadata.Probes["getmacs"].split("\n")
        ?>
        <Path py:for="file in files"
              name="/etc/sysconfig/network/ifcfg-eth-${file}"
              altsrc="/etc/ifcfg-template"/>
    </Bundle>

.. note::
   * The use of the altsrc directive causes all ifcfg files to be
     handled by the same plugin and entry.
   * The <?python ?> blocks have only been available in genshi since
     0.4 (http://genshi.edgewall.org/ticket/84)

If you want a file to be only on a per-client basis, you can use an
if declaration.

.. code-block:: xml

    <Bundle xmlns:py="http://genshi.edgewall.org/">
         <Path name="/etc/bacula/bconsole.conf"/>
         <Path name="/etc/bacula/bacula-fd.conf"/>
         <Path name="/etc/bacula/bacula-sd.conf"/>
         <Path py:if="metadata.hostname == 'foo.bar.com'"
               name="/etc/bacula/bacula-dir.conf"/>
    </Bundle>

or alternately

.. code-block:: xml

    <Bundle xmlns:py="http://genshi.edgewall.org/">
         <Path name="/etc/bacula/bconsole.conf"/>
         <Path name="/etc/bacula/bacula-fd.conf"/>
         <Path name="/etc/bacula/bacula-sd.conf"/>
         <py:if="metadata.hostname == 'foo.bar.com'">
           <Path name="/etc/bacula/bacula-dir.conf"/>
         </py:if>
    </Bundle>

or yet another way

.. code-block:: xml

    <Bundle xmlns:py="http://genshi.edgewall.org/">
        <Path name="/etc/bacula/bconsole.conf"/>
        <Path name="/etc/bacula/bacula-fd.conf"/>
        <Path name="/etc/bacula/bacula-sd.conf"/>
        <Client name="foo.bar.com">
            <Path name="/etc/bacula/bacula-dir.conf"/>
        </Client>
    </Bundle>

The final form is preferred if there is no code inside the block that
would fail on other clients.

While these examples are simple, the test in the if block can in fact
be any python statement.

.. _server-plugins-structures-bundler-index-examples:

Other examples
==============

Some simple examples of Bundles can be found in the `Bcfg2 example repository`_.

.. _Bcfg2 example repository: https://github.com/solj/bcfg2-repo

In addition to the example repository, the following is a list of some
more complex example Bundles.

.. toctree::
   :maxdepth: 1

   bcfg2
   kernel
   moab
   nagios
   ntp
   snmpd
   torque
   yp