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 Group and Client tags for details and a longer example.

A brief example:

<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 Cfg, Rules, or Packages.

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

<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.

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:

  • Service entries whose restart attribute is true (the default) will be restarted.
  • Action 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 Bcfg2 Server for an example of this.

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.)

Genshi templates

Genshi XML templates allow you to use the Genshi 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 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 bcfg2-info for more details.

Dependencies

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

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

The dependent bundle is added to the list of bundles sent to the client, not to the parent bundle itself. If you want to propagate the modification flag from the required bundle, you can add inherit_modification="true" to the RequiredBundle tag. An example:

nfs-client.xml:

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

automount.xml:

<Bundle>
  <RequiredBundle 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. If you would add inherit_modification="true" to the RequiredBundle tag, you would ensure the propagation of the modification flag and the autofs service would be restarted, too. But if a new /etc/auto.misc file was sent out, only the autofs service would be restarted, but the nfslock, rpcbind, and nfs services would not be restarted (independent of the inherit_modification flag).

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.

<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 Cfg, or can be mapped to a single entry by using the 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.

<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.

<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

<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 test="metadata.hostname == 'foo.bar.com'">
       <Path name="/etc/bacula/bacula-dir.conf"/>
     </py:if>
</Bundle>

or yet another way

<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.

Other examples

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

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