Hello World
While CFEngine typically runs automatically, it can also be invoked manually with a standalone policy. This tutorial describes how to write a standalone policy that reports the obligatory Hello World.
CFEngine policy files by convention are suffixed with the .cf
or .cf3
file
extensions. Learn more about writing CFEngine policy from the Policy Style
Guide.
Overview
This tutorial provides instructions for the following:
Create hello_world
Policies contain bundles, which are collections of promises. A promise is a declaration of intent. Bundles allow related promises to be grouped together, as illustrated in the tutorial below.
Create a policy file called hello_world.cf with the following content:
bundle agent hello_world
# @brief Say Hi to everyone and introduce yourself
{
reports:
any::
"Hello World! I am $(sys.fqhost) and it is $(sys.date)"
comment => "It's nice to introduce yourself when you say hello";
}
In the policy file above, we have defined an agent bundle named hello_world
. Agent
bundles are only evaluated by cf-agent, the agent component of CFEngine.
This bundle [promises][Promises Types and Attributes] to report on any class of hosts. In this bundle, $(sys.fqhost) and $(sys.date) are special variables that are automatically defined during an agent run and expand to the fully-qualified hostname and today's date respectively.
Take special note of the comment
attribute that is attached to the report promise.
Comments are intended to follow the promise and provide insight into the reason
a promise is used. When writing comments, it's good practice to answer why the promise exists.
Activate the bundle manually by executing the following command:
/var/cfengine/bin/cf-agent --no-lock --file ./hello_world.cf --bundlesequence hello_world
This command instructs CFEngine to ignore locks, load
the hello_world.cf
policy, and activate the hello_world
bundle. See the output below:
# /var/cfengine/bin/cf-agent --no-lock --file ./hello_world.cf --bundlesequence hello_world
2013-08-20T14:03:43-0500 notice: R: Hello World! I am thinkpad-w520 and it is Tue Aug 20 14:03:32 2013
Note the full path to the binary in the above command. CFEngine stores its binaries in /var/cfengine/bin on Linux and Unix systems. Your path might vary depending on your platform and the packages your are using. CFEngine uses /var because it is one of the Unix filesystems that resides locally. Thus, CFEngine can function even if everything else fails (your other filesystems, your network, and even system binaries) and possibly repair problems.
Make hello_world stand alone
Instead of specifying the bundlesequence on the command line (as it was above), a body common
control section can be added to
the policy file. The body common control refers to those promises that are hard-coded into
all CFEngine components and therefore affect the behavior of all components. Note that only
one body common control
is allowed per agent activation.
Add body common control to hello_world.cf
. Place it above bundle agent hello_world, as
shown in the following example:
body common control
{
bundlesequence => { "hello_world" };
}
bundle agent hello_world
# @brief Say Hi to everyone and introduce yourself
{
reports:
any::
"Hello World! I am $(sys.fqhost) and it is $(sys.date)"
comment => "It's nice to introduce yourself when you say hello";
}
Execute the following command:
/var/cfengine/bin/cf-agent --no-lock --file ./hello_world.cf
The output is shown below:
# /var/cfengine/bin/cf-agent --no-lock --file ./hello_world.cf
2013-08-20T14:25:36-0500 notice: R: Hello World! I am thinkpad-w520 and it is Tue Aug 20 14:25:25 2013
Make hello_world an executable script
Add a shebang #! to hello_world.cf
in order to invoke CFEngine policy as an executable script:
#!/var/cfengine/bin/cf-agent --no-lock
Add it before body common control, as shown below:
#!/var/cfengine/bin/cf-agent --no-lock
body common control
{
bundlesequence => { "hello_world" };
}
bundle agent hello_world
# @brief Say Hi to everyone and introduce yourself
{
reports:
any::
"Hello World! I am $(sys.fqhost) and it is $(sys.date)"
comment => "It's nice to introduce yourself when you say hello";
}
Make the policy file executable, and then run it:
chmod +x ./hello_world.cf
./hello_world.cf
See the output below:
# chmod +x ./hello_world.cf
# ./hello_world.cf
2013-08-20T14:39:34-0500 notice: R: Hello World! I am thinkpad-w520 and it is Tue Aug 20 14:39:22 2013