.. -*- mode: rst -*-

.. _server-plugins-generators-tcheetah:

========
TCheetah
========

.. warning::

    TCheetah is deprecated.  You should instead use
    :ref:`server-plugins-generators-cfg-cheetah` in the Cfg plugin.

This document reflects the ``TCheetah`` plugin.

The ``TCheetah`` plugin allows you to use the `cheetah templating system
<http://www.cheetahtemplate.org/>`_ 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 Cheetah templating
engine from http://www.cheetahtemplate.org/.  Once it is installed,
you can enable it by adding ``TCheetah`` to the ``plugins`` line in
``/etc/bcfg2.conf`` on your Bcfg server.  For example::

    plugins = Base,Bundler,Cfg,...,TCheetah

The ``TCheetah`` plugin makes use of a ``Cfg``-like directory structure
located in in a ``TCheetah`` subdirectory of your repository, usually
``/var/lib/bcfg2/TCheetah``. Each file has a directory containing two
files, ``template`` and ``info``. The template is a standard Cheetah
template with two additions:

* `self.metadata` is the client's :ref:`metadata <server-plugins-grouping-metadata-clientmetadata>`
* `self.metadata.Properties.xdata` is an xml document of unstructured data

The ``info`` file is formatted like ``:info`` files from Cfg.

Mostly, people will want to use client metadata.

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

File permissions for entries handled by TCheetah 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.

self.metadata variables
=======================

self.metadata is an instance of the class ClientMetadata and documented
:ref:`here <server-plugins-grouping-metadata-clientmetadata>`.

self.metadata.Properties.xdata
==============================

.. note::

    If you want to use Properties, you will need to enable the
    :ref:`server-plugins-connectors-properties` plugin in
    ``/etc/bcfg2.conf``.

Properties.xdata is a python `ElementTree <http://codespeak.net/lxml/>`_
object, loaded from the data in ``/var/lib/bcfg2/Properties/<properties
file>.xml``. That file should have a ``Properties`` node at its root.

Example ``Properties/example.xml``:

.. code-block:: xml

    <Properties>
     <host>
       <www.example.com>
         <rootdev>/dev/sda</rootdev>
       </www.example.com>
     </host>
    </Properties>

You may use any of the ElementTree methods to access data in your
template.  Several examples follow, each producing an identical result
on the host 'www.example.com'::

    $self.metadata.Properties['example.xml'].xdata.find('host').find('www.example.com').find('rootdev').text
    $self.metadata.Properties['example.xml'].xdata.find('host').find($self.metadata.hostname).find('rootdev').text
    ${self.metadata.Properties['example.xml'].xdata.xpath('host/www.example.com/rootdev')[0].text}
    ${self.metadata.Properties['example.xml'].xdata.xpath('host/' + self.metadata.hostname + '/rootdev')[0].text}
    #set $path = 'host/' + $self.metadata.hostname + '/rootdev'
    ${self.metadata.Properties['example.xml'].xdata.xpath($path)[0].text}
    ${self.metadata.Properties['example.xml'].xdata.xpath(path)[0].text}

Other Variables
===============

* **Template.searchList(self)[1]['path']** is the Path name specified in a Bundle
* **Template.searchList(self)[1]['source_path']** is the path to the TCheetah template on the Bcfg2 server

Simple Example
==============

TCheetah works similar to Cfg in that you define all literal information
about a particular file in a directory rooted at TCheetah/path_to_file.
The actual file contents are placed in a file named `template` in that
directory. Below is a simple example a file ``/foo``.

``/var/lib/bcfg2/TCheetah/foo/template``

.. code-block:: none

    > buildfile /foo <clientname>
    Hostname is $self.metadata.hostname
    Filename is $Template.searchList(self)[1]['path']
    Template is $Template.searchList(self)[1]['source_path']
    Groups:
    #for $group in $self.metadata.groups:
     * $group
    #end for
    Categories:
    #for $category in $self.metadata.categories:
     * $category -- $self.metadata.categories[$category]
    #end for

    Probes:
    #for $probe in $self.metadata.Probes:
     * $probe -- $self.metadata.Probes[$probe]
    #end for

``/var/lib/bcfg2/TCheetah/foo/info``

.. code-block:: none

    mode: 624

Output
------

The following output can be generated with bcfg2-info. Note that probe
information is not persistent, hence, it only works when clients directly
query the server. For this reason, bcfg2-info output doesn't reflect
current client probe state.

.. code-block:: xml

    <Path type="file" name="/foo" owner="root" mode="0624" group="root">
    Hostname is topaz.mcs.anl.gov
    Filename is /foo
    Template is /var/lib/bcfg2/TCheetah/foo/template
    Groups:
     * desktop
     * mcs-base
     * ypbound
     * workstation
     * xserver
     * debian-sarge
     * debian
     * a
    Categories:
     * test -- a

    Probes:
    </Path>

Example: Replace the crontab plugin
===================================

In many cases you can use the TCheetah plugin to avoid writing custom
plugins in Python. This example randomizes the time of cron.daily
execution with a stable result. Cron.daily is run at a consistent,
randomized time between midnight and 7am.::

    #import random
    #silent random.seed($self.metadata.hostname)

    # /etc/crontab: system-wide crontab
    # Unlike any other crontab you don't have to run the `crontab`
    # command to install the new version when you edit this file.
    # This file also has a username field, that none of the other crontabs do.

    SHELL=/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin://bin

    # m h dom mon dow user  command
    17 *    * * *   root    run-parts --report /etc/cron.hourly
    $random.randrange(0,59) $random.randrange(0,6)    * * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.daily
    47 6    * * 7   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.weekly
    52 6    1 * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.monthly.

.. note:: Comments and Cheetah
    As Cheetah processes your templates it will consider hash "#" style
    comments to be actual comments in the template and will strip them
    from the final config file.  If you would like to preserve the comment
    in the final config file you need to escape the hash character '\#'
    which will tell Cheetah (and Python) that you do in fact want the
    comment to appear in the final config file.::

        # This is a comment in my template which will be stripped when it's processed through Cheetah
        \# This comment will appear in the generated config file.
