CFEngine reference manual


Next: , Previous: (dir), Up: (dir)

CFEngine-AutoReference

COMPLETE TABLE OF CONTENTS

Summary of contents


Next: , Previous: Top, Up: Top

1 CFEngine 3.3.0a1.r3728M – Getting started


CFEngine is a suite of programs for integrated autonomic management of either individual or networked computers. It has existed as as software suite since 1993 and this version published under the GNU Public License (GPL v3) and a Commercial Open Source License (COSL). CFEngine is Copyright by CFEngine AS, a company founded by CFEngine author Mark Burgess.

This document describes major version 3 of CFEngine, which is a significant departure from earlier versions, and represents the newest and most carefully researched technology available for configuration management. It is both simpler and more powerful. CFEngine 3 will exist in four versions, each of which adds to the following

This document is valid for all versions of CFEngine. Whenever a feature is only available in a specific version, that fact will be noted in the documentation for that feature (if there is no note, then that feature is available in all versions).

CFEngine 3 has been changed to be both a more powerful tool and a much simpler tool. CFEngine 3's language interface is not backwards compatible with the CFEngine 2 configuration language, but it interoperates with CFEngine 2 so that it is "run-time compatible". This means that you can change over to version 3 slowly, with low risk and at your own speed.

With CFEngine 3 you can install, configure and maintain computers using powerful hands-free tools. You can also integrate knowledge management and diagnosis into the processes.

CFEngine differs from most management systems in being


Next: , Previous: Getting started, Up: Getting started

1.1 Software components

CFEngine 3 consists of a number of components. The names of the programs are intentionally different from those in CFEngine 2 to help disambiguate them (and some CFEngine 2 components have been merged and/or eliminated). The starred components are new to CFEngine 3:


Next: , Previous: Software components, Up: Software components

1.1.1 cf-agent

Active agent – responsible for maintaining promises about the state of your system (in CFEngine 2 the agent was called cfagent). You can run cf-agent manually, but if you want to have it run on a regular basis, you should use cf-execd (instead of using cron).

cf-agent keeps the promises made in common and agent bundles, and is affected by common and agent control bodies.


Next: , Previous: cf-agent, Up: Software components

1.1.2 cf-execd

Scheduler – responsible for running cf-agent on a regular (and user-configurable) basis (in CFEngine 2 the scheduler was called cfexecd).

EXECUTOR cf-execd keeps the promises made in common bundles, and is affected by common and executor control bodies.


Next: , Previous: cf-execd, Up: Software components

1.1.3 cf-know*

Knowledge modelling agent – responsible for building and analysing a semantic knowledge network.

cf-know keeps the promises made in common and knowledge bundles, and is affected by common and knowledge control bodies.


Next: , Previous: cf-know, Up: Software components

1.1.4 cf-monitord

Passive monitoring agent – responsible for collecting information about the status of your system (which can be reported upon or used to enforce promises or influence when promises are enforced). In CFEngine 2 the passive monitoring agent was known as cfenvd.

cf-monitord keeps the promises made in common and monitor bundles, and is affected by common and monitor control bodies.


Next: , Previous: cf-monitord, Up: Software components

1.1.5 cf-promises

Promise validator – used to verify that the promises used by the other components of CFEngine are syntactically valid. cf-promises does not execute any promises, but can syntax-check all of them.


Next: , Previous: cf-promises, Up: Software components

1.1.6 cf-runagent

Remote run agent – used to execute cf-agent on a remote machine (in CFEngine 2 the remote run agent was called cfrun). cf-runagent does not keep any promises, but instead is used to ask another machine to do so.


Next: , Previous: cf-runagent, Up: Software components

1.1.7 cf-serverd

Server – used to distribute policy and/or data files to clients requesting them and used to respond to requests from cf-runagent (in CFEngine 2 the remote run agent was called cfservd).

cf-serverd keeps the promises made in common and server bundles, and is affected by common and server control bodies.


Next: , Previous: cf-serverd, Up: Software components

1.1.8 cf-report

Self-knowledge extractor – takes data stored in CFEngine's embedded databases and converts them to human readable form

cf-report keeps the promises made in common bundles, and is affected by common and reporter control bodies.


Next: , Previous: cf-report, Up: Software components

1.1.9 cf-key

Key generation tool – run once on every host to create public/private key pairs for secure communication (in CFEngine 2 the key generation tool was called cfkey). cf-key does not keep any promises.


Previous: cf-key, Up: Software components

1.1.10 cf-hub

A data aggregator used as part of the commercial product. This stub is not used in the community edition of CFEngine.


Next: , Previous: Software components, Up: Getting started

1.2 Core concepts

Unlike previous versions of CFEngine, which had no consistent model For its features, you can recognize everything in CFEngine 3 from just a few concepts.

Promise
A declaration about the state we desire to maintain (e.g., the permissions or contents of a file, the availability or absence of a service, the (de)installation of a package).
Promise bundles
A collection of promises.
Promise bodies
A part of a promise which details and constrains its nature.
Data types
An interpretation of a scalar value: string, integer or real number.
Variables
An association of the form "LVALUE represents RVALUE", where rval may be a scalar value or a list of scalar values.
Functions
Built-in parameterized rvalues.
Classes
CFEngine's boolean classifiers that describe context.

If you have used CFEngine before then the most visible part of CFEngine 3 will be its new language interface. Although it has been clear for a long time that the organically grown language used in CFEngine 1 and 2 developed many problems, it was not immediately clear exactly what would be better. It has taken years of research to simplify the successful features of CFEngine to a single overarching model. To understand the new CFEngine, it is best to set aside any preconceptions about what CFEngine is today. CFEngine 3 is a genuine "next generation" effort, which will be a springboard into the future of system management.


Next: , Previous: Core concepts, Up: Getting started

1.3 A renewed CFEngine

CFEngine 3 is a significant rewrite of underlying CFEngine technology which preserves the core principles and methodology of CFEngine's tried and tested approach. It comes with a new, improved language, with a consistent syntax and powerful pattern expression features that display the intent behind CFEngine code more clearly. The main goal in changing the language is to simplify and improve the robustness and functionality without sacrificing the basic freedoms and self-repairing concepts.

CFEngine 3's new language is a direct implementation of a model developed at Oslo University College over the past four years, known colloquially as "Promise Theory". Promises were originally introduced by Mark Burgess as a way to talk about CFEngine's model of autonomy and have since become a powerful way of modelling cooperative systems – not just computers, but humans too.

“The biggest challenge of implementing CFEngine in our organization
was not technical but political – getting everyone to agree.
Promise theory was a big help in understand this.”

CFEngine 3 is a generic implementation of the language of promises that allows all of the aspects of configuration and change management to be unified under a single umbrella.

Why talk about promises instead of simply talking about changes? After all, the trend in business and IT management today is to talk about Change Management (with capital letters), e.g. in the IT Infrastructure Library (ITIL) terminology. This comes from a long history of process management thinking. But we are not really interested in change – we are interested in avoiding it, i.e. being in a state where we don't need to make any changes. In other words we want to be able to promise that the system is correct, verify this and only make changes if our promises are not kept. If you want to think ITIL, think of this as a service that CFEngine provides.

To put it another way, CFEngine is not really a change management system, it is a maintenance system. Maintenance is the process of making small changes or corrections to a model. A `model' is just another word for a template or a specification of how we want the system to work. CFEngine's model is based on the idea of promises, which means that it focuses on what is stable and lasting about a system – not about what is changing.

This is an important philosophical shift. It means we are focused mainly on what is right and not on what is wrong. By saying what "right" is (the ideal state of our system) we are focused on the actual behaviour. If we focus too much on the changes, i.e. the differences between now and the future, we might forget to verify that what we assume is working now in fact works.

Models that talk about change management tend to forget that after every change there is a litany of incidents during which it is necessary to repair the system or return it to its intended state. But if we know what we have promised, it is easy to verify whether the promise is kept. This means that it is the promises about how the system should be that are most important, not the actual changes that are made in order to keep them.


Next: , Previous: A renewed CFEngine, Up: Getting started

1.4 Installation

In order to install CFEngine, you should first ensure that the following packages are installed.

OpenSSL
Open source Secure Sockets Layer for encryption.
URL: http://www.openssl.org
BerkeleyDB (version 3.2 or later)
Light-weight flat-file database system.
URL: http://www.oracle.com/technology/products/berkeley-db/index.html
PCRE
Perl Compatible Regular Expression library.
URL: http://www.pcre.org/
On Windows machines, you need to install the basic Cygwin DLL from http://www.cygwin.com in order to run CFEngine.

Additional functionality becomes available if other libraries are present, e.g. OpenLDAP, client libraries for MySQL and PostgreSQL, etc. It is possible to run CFEngine without these, but related functionality will be missing.

Unless you have purchased ready-to-run binaries, or are using a package distribution, you will need to compile CFEngine. For this you will also need a build environment tools: gcc, flex, bison.

The preferred method of installation is then

     tar zxf cfengine-x.x.x.tar.gz
     cd cfengine-x.x.x
     ./configure
     make
     make install

This results in binaries being installed in /usr/local/sbin. Since this is not necessarily a local file system on all hosts, users are encouraged to keep local copies of the binaries on each host, inside the CFEngine trusted work directory.


Next: , Previous: Installation, Up: Getting started

1.5 Syntax, identifiers and names

The CFEngine 3 language has a few simple rules:


Next: , Previous: Syntax, Up: Getting started

1.6 The work directory

In order to achieve the desired simplifications, it was decided to reserve a private work area for the CFEngine tool-set.

In CFEngine 1.x, the administrator could choose the locations of configuration files, locks, and logging data independently. In CFEngine 2.x, this diversity has been simplified to a single directory which defaults to /var/cfengine (similar to /var/cron), and in CFEngine 3.x this is preserved.

     /var/cfengine
     /var/cfengine/bin
     /var/cfengine/inputs
     /var/cfengine/outputs

The installation location /usr/local/sbin is not necessarily a local file system, and cannot therefore be trusted to a) be present, and b) be authentic on an arbitrary system.

Similarly, a trusted cache of the input files must now be maintained in the inputs subdirectory. When CFEngine is invoked by the scheduler, it reads only from this directory. It is up to the user to keep this cache updated, on each host. This simplifies and consolidates the CFEngine resources in a single place.

Unlike CFEngine 2, CFEngine 3 does not recognize the CFINPUTS environment variable.

The outputs directory is now a record of spooled run-reports. These are often mailed to the administrator by cf-execd, or can be copied to another central location and viewed in an alternative browser.


Next: , Previous: Work directory, Up: Getting started

1.7 Decisions

CFEngine decisions are made behind the scenes and the results of certain true/false propositions are cached in Booleans referred to as `classes'. There are no if-then-else statements in CFEngine; all decisions are made with classes.

Classes fall into hard (discovered) and soft (user-defined) types. A single hard class can be one of several things:


Next: , Previous: Decisions, Up: Decisions

1.7.1 CFEngine hard classes

CFEngine runs on every computer individually and each time it wakes up the underlying generic agent platform discovers and classifies properties of the environment or context in which it runs. This information is cached and may be used to make decisions about configuration1.

Classes fall into hard (discovered) and soft (defined) types. A single class can be one of several things:

To see all of the classes defined on a particular host, run

     host# cf-promises -v

as a privileged user. Note that some of the classes are set only if a trusted link can be established with cf-monitord, i.e. if both are running with privilege, and the /var/cfengine/state/env_data file is secure. More information about classes can be found in connection with allclasses.


Next: , Previous: Hard classes, Up: Decisions

1.7.2 Class combination operators and precedence

Classes may be combined with the usual boolean operators, in the usual precedence (AND binds stronger than OR). On addition the dot may be used for AND to improve readability, or imply the interpretation `subset' or `subclass'. In order of precedence:

()
The parenthesis group operator.
!
The NOT operator.
.
The AND operator.
&
The AND operator (alternative).
|
The OR operator.
||
The OR operator (alternative).

So the following expression would be only true on Mondays or Wednesdays from 2:00pm to 2:59pm on Windows XP systems:

     
     (Monday|Wednesday).Hr14.WinXP::
     


Previous: Class combination operators and precedence, Up: Decisions

1.7.3 Global and local classes

User defined classes are mostly defined in bundles, but they are used as a signalling mechanism between promises. We'll return to those in a moment.

Classes promises define new classes based on combinations of old ones. This is how to make complex decisions in CFEngine, with readable results. It is like defining aliases for class combinations. Such class `aliases' may be specified in any kind of bundle. Bundles of type common yield classes that are global in scope, whereas in all other bundle types classes are local. Classes are evaluated when the bundle is evaluated (and the bundles are evaluated in the order specified in the bundlesequence). Consider the following example.

body common control
{
bundlesequence => { "g","tryclasses_1", "tryclasses_2" };
}

#################################


bundle common g
{
classes:

  "one" expression => "any";

}

#################################


bundle agent tryclasses_1
{
classes:

  "two" expression => "any";
}

#################################


bundle agent tryclasses_2
{
classes:

  "three" expression => "any";

reports:

  one.three.!two::

    "Success";
}

Here we see that class ‘one’ is global (because it is defined inside the common bundle), while classes ‘two’ and ‘three’ are local (to their respective bundles). The report result `Success' is therefore true because only ‘one’ and ‘three’ are in scope (and ‘two’ is not in scope) inside of the third bundle.

Note that any class promise must have one - and only one - value constraint. That is, you might not leave ‘expression’ in the example above or add both ‘and’ and ‘xor’ constraints to the single promise.

Another type of class definition happens when you define classes based on the outcome of a promise, e.g. to set a class if a promise is repaired, one might write:

 "promiser..."

    ...

    classes => if_repaired("signal_class");

These classes are global in scope. Finally restart_class classes in processes are global.


Next: , Previous: Decisions, Up: Getting started

1.8 Filenames and paths

Filenames in Unix-like operating systems use the forward slash ‘/’ character for their directory separator . All references to file locations must be absolute pathnames in CFEngine, i.e. they must begin with a complete specification of which directory they are in. For example:

     /etc/passwd
     /usr/local/masterfiles/distfile

The only place where it makes sense to refer to a file without a complete directory specification is when searching through directories for different kinds of file, e.g. in pattern matching

leaf_name => { "tmp_.*", "output_file", "core" };

Here, one can write core without a path, because one is looking for any file of that name in a number of directories.

The Windows operating systems traditionally use a different filename convention. The following are all valid absolute file names under Windows:

      c:\winnt
      "c:\spaced name"
      c:/winnt
      /var/cfengine/inputs
      //fileserver/share2/dir

The `drive' name “C:” in Windows refers to a partition or device. Unlike Unix, Windows does not integrate these seamlessly into a single file-tree. This is not a valid absolute filename:

     \var\cfengine\inputs

Paths beginning with a backslash are assumed to be win32 paths. They must begin with a drive letter or double-slash server name.

Note in recent versions of Cygwin you can decide to use the /cygdrive to specify a path to windows file E.g /cygdrive/c/myfile means c:\myfile or you can do it straight away in CFEngine as c:\myfile.


Next: , Previous: Filenames and paths, Up: Getting started

1.9 Upgrading from CFEngine 2

CFEngine 3 has a completely new syntax, designed to solve the issues brought up from 15 years of experience with configuration management. Rather than clutter CFEngine 3 with buggy backward-compatability issues, it was decided to make no compromises with CFEngine 3 and instead allow CFEngine 2 and CFEngine 3 to coincide in a cooperative fashion for the foreseeable future. This means that users can upgrade at their own pace, in the classic CFEngine incremental fashion. We expect that CFEngine 2 installations will be around for years to come so this upgrade path seems the most defensible.

The daemons and support services are fully interoperable between CFEngine 2 and CFEngine 3, so it does not matter whether you run cfservd (cf2) together with cf-agent (cf3) or cf-serverd (cf3) together with cfagent (cf2). You can change the servers at your own pace.

CFEngine 3's cf-execd replaces CFEngine 2's cfexecd and it is designed to work optimally with cf-agent (cf3). Running this daemon has no consequences for access control, only for scheduling cf-agent. You can (indeed should) replace cfexecd with cf-execd immediately. You will want to alter your crontab file to run the new component instead of the old. The sample CFEngine 3 input files asks cf-agent to do this automatically, simply replacing the string.

The sample inputs files supplied with CFEngine 3 contain promises to integrate CFEngine 2 as described. What can you do to upgrade? Here is a simple recipe that assumes you have a standardized CFEngine 2 setup, running cfexecd in crontabs and possibly running cfservd and cfenvd as daemons.

  1. Install the CFEngine 3 software on a host.
  2. Go to the inputs/ directory in the source and copy these files to your master update repository, i.e. where you will publish policies for distribution.
  3. Remove any self-healing rules to reinstall CFEngine 2, especially rules to add cfexecd or cfagent to crontabs etc. CFEngine 3 will handle this from now on and encapsulate old CFEngine 2 scripts.
  4. Move to this inputs directory: cd your-path/inputs.
  5. Set the location of this master update directory in the update.cf file to the location of the master directory.
  6. Set the email options for the executor in promises.cf.
  7. Run cf-agent --bootstrap as the root or privileged user. This will install CFEngine 3 in place of CFEngine 2, integrate your old CFEngine 2 configuration, and warn you about any rules that need to be removed from your old CFEngine configuration.
  8. You should now be running CFEngine 3. You can now add new rules to the files in your own time, or convert the old CFEngine 2 rules and gradually comment them out of the CFEngine 2 files.
  9. Make sure there are no rules in your old CFEngine 2 configuration to activate CFEngine 2 components, i.e. rules that will fight against CFEngine 3. Then, when you are ready, convert cfservd.conf into a server bundle e.g. in promises.cf and remove all rules to run cfservd and replace them with rules to run cf-serverd at your own pace.


Next: , Previous: Upgrading from CFEngine 2, Up: Getting started

1.10 Testing as a non-privilieged user

One of the practical advantages of CFEngine is that you can test it without the need for root or administrator privileges. This is recommended for all new users of CFEngine 3.

CFEngine operates with the notion of a work-directory. The default work directory for the root user is /var/cfengine (except on Debian Linux and various derivatives which prefer /var/lib/cfengine). For any other user, the work directory lies in the user's home directory, named ~/.cfagent. CFEngine prefers you to keep certain files here. You should not resist this too strongly or you will make unnecessary trouble for yourself. The decision to have this `known directory' was made to simplify a lot of configuration.

To test CFEngine as an ordinary user, do the following:

You can test the software and play with configuration files by editing the basic get-started files directly in the ~/.cfagent/inputs directory. For example, try the following:

     host$ ~/.cfagent/bin/cf-promises
     host$ ~/.cfagent/bin/cf-promises --verbose

This is always the way to start checking a configuration in CFEngine 3. If a configuration does not pass this check/test, you will not be allowed to use it, and cf-agent will look for the file failsafe.cf.

Notice that the CFEngine 3 binaries have slightly different names than the CFEngine 2 binaries. They all start with the cf- prefix.

     host$ ~/.cfagent/bin/cf-agent


Next: , Previous: Testing as a non-privilieged user, Up: Getting started

1.11 The `bare necessities' of a CFEngine 3

Here is the simplest `Hello world' program in CFEngine 3:

body common control
{
bundlesequence  => { "test" };
}

bundle agent test
{
reports:

 Yr2009::
    "Hello world";
}

If you try to process this using the cf-promises command, you will see something like this:

     atlas$ ~/LapTop/CFEngine3/trunk/src/cf-promises -r -f ./unit_null_config.cf
     Summarizing promises as text to ./unit_null_config.cf.txt
     Summarizing promises as html to ./unit_null_config.cf.html

The ‘-r’ option produces a report. Examine the files produced:

     cat ./unit_null_config.cf.txt
     firefox ./unit_null_config.cf.html

You will see a summary of how CFEngine interprets the files, either in HTML or text. By default, the CFEngine components also dump a debugging file, e.g. promise_output_agent.html, promise_output_agent.txt with an expanded view.


Next: , Previous: The bare necessities of a CFEngine 3, Up: Getting started

1.12 Familiarizing yourself

To familiarize yourself with CFEngine 3, type or paste in the following example text:

########################################################
#

# Simple test execution

#

########################################################


body common control

{
bundlesequence  => { "testbundle"  };
}

########################################################


bundle agent testbundle

{
vars:

  "size" int => "46k";
  "rand" int => randomint("33","$(size)");

commands:

  "/bin/echo"
     args => "Hello world - $(size)/$(rand)",
     contain => standard,
     classes => cdefine("followup","alert");

  followup::

     "/bin/ls"
       contain => standard;

reports:

  alert::

     "What happened?";

}

######################################################################


body contain standard

{
exec_owner => "mark";
useshell => "true";
}

######################################################################


body classes cdefine(class,alert)

{
promise_repaired => { "$(class)" };
repair_failed => { "$(alert)" };
}

This example shows all of the main features of CFEngine: bundles, bodies, control, variables, and promises. To the casual eye it might look complex, but that is because it is explicit about all of the details. Fortunately it is easy to hide many of these details to make the example simpler without sacrificing any functionality.

The first thing to try with this example is to verify it – did we make any mistakes? Are there any inconsistencies? To do this we use the new CFEngine program cf-promises. Let's assume that you typed this into a file called test.cf in the current directory.

     cf-promises -f ./test.cf

If all is well, typing this command shows no output. Try now running the command with verbose output.

     cf-promises -f ./test.cf -v

Now you see a lot of information

     Reference time set to Sat Aug  2 11:26:06 2008
     
     cf3 CFEngine - 3.0.0
     Free Software Foundation 1994-
     Donated by Mark Burgess, Oslo University College, Norway
     cf3 ------------------------------------------------------------------------
     cf3 Host name is: atlas
     cf3 Operating System Type is linux
     cf3 Operating System Release is 2.6.22.18-0.2-default
     cf3 Architecture = x86_64
     cf3 Using internal soft-class linux for host linux
     cf3 The time is now Sat Aug  2 11:26:06 2008
     cf3 ------------------------------------------------------------------------
     cf3 Additional hard class defined as: 64_bit
     cf3 Additional hard class defined as: linux_2_6_22_18_0_2_default
     cf3 Additional hard class defined as: linux_x86_64
     cf3 Additional hard class defined as: linux_x86_64_2_6_22_18_0_2_default
     cf3 GNU autoconf class from compile time: compiled_on_linux_gnu
     cf3 Interface 1: lo
     cf3 Trying to locate my IPv6 address
     cf3 Looking for environment from cf-monitord...
     cf3 Unable to detect environment from cf-monitord
     ---------------------------------------------------------------------
     Loading persistent classes
     ---------------------------------------------------------------------
     
     ---------------------------------------------------------------------
     Loaded persistent memory
     ---------------------------------------------------------------------
     cf3   > Parsing file ./test.cf
     ---------------------------------------------------------------------
     Agent's basic classified context
     ---------------------------------------------------------------------
     
     
     Defined Classes = ( any Saturday Hr11 Min26 Min25_30 Q2 Hr11_Q2 Day2
     August Yr2008 linux atlas 64_bit linux_2_6_22_18_0_2_default x86_64
     linux_x86_64 linux_x86_64_2_6_22_18_0_2_default
     linux_x86_64_2_6_22_18_0_2_default__1_SMP_2008_06_09_13_53_20__0200
     compiled_on_linux_gnu net_iface_lo )
     
     Negated Classes = ( )
     
     Installable classes = ( )
     cf3 Wrote expansion summary to promise_output_common.html
     cf3 Inputs are valid

The last two lines of this are of interest. Each time a component of CFEngine 3 parses a number of promises, it summarizes the information in an HTML file called generically promise_output_component-type.html. In this case the cf-promises command represents all possible promises, by the type "common". You can view this output file in a suitable web browser to see exactly what CFEngine has understood by the configuration.

Now that you have verified it, you can execute it. To run this example you need to change the username `mark' to your own, or obtain root privileges to change to another user. The non-verbose output of the script when run in the CFEngine 3 directory looks something like this:

host$ ./cf-agent -f ../tests/units/unit_exec_in_sequence.cf
Q ".../bin/echo Hello": Hello world - 46k/219
 -> Last 1 QUOTEed lines were generated by "/bin/echo Hello world - 46k/219"
Q ".../bin/ls": agent.c
Q ".../bin/ls": agentdiagnostic.c
Q ".../bin/ls": agentdiagnostic.o
Q ".../bin/ls": agent.o
Q ".../bin/ls": args.c
Q ".../bin/ls": args.lo
Q ".../bin/ls": args.o
...
Q ".../bin/ls": verify_reports.o
Q ".../bin/ls": verify_storage.c
Q ".../bin/ls": verify_storage.o
 -> Last 288 QUOTEed lines were generated by "/bin/ls"
atlas$


Previous: Familiiarizing yourself, Up: Getting started

1.13 Remote access troubleshooting


Next: , Previous: Remote access troubleshooting, Up: Remote access troubleshooting

1.13.1 Server connection

When setting up cf-serverd, you might see the error message

  Unspecified server refusal

This means that cf-serverd is unable or is unwilling to authenticate the connection from your client machine. The message is generic: it is deliberately non-specific so that anyone attempting to attack or exploit the service will not be given information which might be useful to them. There is a simple checklist for curing this problem:

  1. Make sure that the domain variable is set in the configuration files read by both client and server; alternatively use skipidentify and skipverify to decouple DNS from the the authentication.
  2. Make sure that you have granted access to your client in the server body
              
              body server control
              {
              allowconnects         => { "127.0.0.1" , "::1" ...etc };
              allowallconnects      => { "127.0.0.1" , "::1" ...etc };
              trustkeysfrom         => { "127.0.0.1" , "::1" ...etc };
              }
              
    
  3. Make sure you have created valid keys for the hosts using cf-key.
  4. If you are using secure copy, make sure that you have created a key file and that you have distributed and installed it to all participating hosts in your cluster.

Always remember that you can run CFEngine in verbose or debugging modes to see how the authentication takes place:

cf-agent -v
cf-serverd -v

cf-agent reports that access is denied regardless of the nature of the error, to avoid giving away information which might be used by an attacker. To find out the real reason for a denial, use verbose ‘-v’ or even debugging mode ‘-d2’.


Next: , Previous: Server connection, Up: Remote access troubleshooting

1.13.2 Key exchange

The key exchange model used by CFEngine is based on that used by OpenSSH. It is a peer to peer exchange model, not a central certificate authority model. This means that there are no scalability bottlenecks (at least by design, though you might introduce your own if you go for an overly centralized architecture).

The problem of key distribution is the conundrum of every public key infrastructure. Key exchange is handled automatically by CFEngine and all you need to do is to decide which keys to trust.

When public keys are offered to a server, they could be accepted automatically on trust because no one is available to make a decision about them. This would lead to a race to be the first to submit a key claiming identity.

Even with DNS checks for correct name/IP address correlation (turned off with skipverify), it might be possible to submit a false key to a server.

The server cf-serverd blocks the acceptance of unknown keys by default. In order to accept such a new key, the IP address of the presumed client must be listed in the trustkeysfrom stanza of a server bundle (these bundles can be placed in any file). Once a key has been accepted, it will never be replaced with a new key, thus no more trust is offered or required.

Once you have arranged for the right to connect to the server, you must decide which hosts will have access to which files. This is done with access rules.

bundle server access_rules()

{
access:

  "/path/file"

    admit   => { "127.0.0.1", "127.0.0.2", "127.0.0.3" },
    deny    => { "192\..*" };
}

On the client side, i.e. cf-runagent and cf-agent, there are three issues:

  1. Choosing which server to connect to.
  2. Trusting the identity of any previously unknown servers, i.e. trusting the server's public key to be its and no one else's. (The issues here are the same as for the server.)
  3. Choosing whether data transfers should be encrypted (with encrypt).

Because there are two clients for connecting to cf-serverd (cf-agent and cf-runagent), there are also two ways of managing trust of server keys by a client. One is an automated option, setting the option trustkey in a copy_from stanza, e.g.

body copy_from example
     {
     # .. other settings ..

     trustkey => "true";
     }

Another way is to run cf-runagent in interactive mode. When you run cf-runagent, unknown server keys are offered to you interactively (as with ssh) for you to accept or deny manually:

     
     WARNING - You do not have a public key from host ubik.iu.hio.no = 128.39.74.25
               Do you want to accept one on trust? (yes/no)
     -->
     


Next: , Previous: Key exchange, Up: Remote access troubleshooting

1.13.3 Time windows (races)

Once public keys have been exchanged from client to server and from server to client, the issue of trust is solved according to public key authentication schemes. You only need to worry about trust when one side of a connection has never seen the other side before.

Often you will have a central server and many client satellites. Then the best way to transfer all the keys is to set the trustkey flags on server and clients sides to coincide with a time at which you know that cf-agent will be run, and when a spoofer is unlikely to be able to interfere.

This is a once-only task, and the chance of an attacker being able to spoof a key-transfer is small. It would require skill and inside-information about the exchange procedure, which would tend to imply that the trust model was already broken.

Another approach would be to run cf-runagent against all the hosts in the group from the central server and accept the keys one by one, by hand, though there is little to be gained from this.

Trusting a host for key exchange is unavoidable. There is no clever way to avoid it. Even transferring the files manually by diskette, and examining every serial number of the computers you have, the host has to trust the information you are giving it. It is all based on assertion. You can make it almost impossible for keys to be faked or attacked, but you cannot make it absolutely impossible. Security is about managing reasonable levels of risk, not about magic.

All security is based on a moment of trust, that is granted by a user at some point in time – and is assumed thereafter (once given, hard to rescind). Cryptographic key methods only remove the need for a repeat of the trust decision. After the first exchange, trust is no longer needed, because they keys allow identity to be actually verified.

Even if you leave the trust options switched on, you are not blindly trusting the hosts you know about. The only potential insecurity lies in any new keys that you have not thought about. If you use wildcards or IP prefixes in the trust rules, then other hosts might be able to spoof their way in on trust because you have left open a hole for them to exploit. That is why it is recommended to return the system to the default state of zero trust immediately after key transfer, by commenting out the trust options.

It is possible, though somewhat laborious to transfer the keys out of band, by copying /var/cfengine/ppkeys/localhost.pub to /var/cfengine/ppkeys/user-aaa.bbb.ccc.mmm (assuming IPv4) on another host. e.g.

     
     localhost.pub -> root-128.39.74.71.pub
     

This would be a silly way to transfer keys between nearby hosts that you control yourself, but if transferring to long distance, remote hosts it might be an easier way to manage trust.


Next: , Previous: Time windows, Up: Remote access troubleshooting

1.13.4 Other users than root

CFEngine normally runs as user "root" (except on Windows which does not normally have a root user), i.e. a privileged administrator. If other users are to be granted access to the system, they must also generate a key and go through the same process. In addition, the users must be added to the server configuration file.


Previous: Other users than root, Up: Remote access troubleshooting

1.13.5 Encryption

CFEngine provides encryption for keeping file contents private during transfer. It is assumed that users will use this judiciously. There is nothing to be gained by encrypting the transfer of public files – overt use of encryption just contributes to global warming, burning unnecessary CPU cycles without offering any security.

The main role for encryption in configuration management is for authentication. CFEngine always uses encryption during authentication, so none of the encryption settings affect the security of authentication.


Next: , Previous: Getting started, Up: Top

2 A simple crash course in concepts


Next: , Previous: A simple crash course, Up: A simple crash course

2.1 Rules are promises

Everything in CFEngine 3 can be interpreted as a promise. Promises can be made about all kinds of different subjects, from file attributes, to the execution of commands, to access control decisions and knowledge relationships.

This simple but powerful idea allows a very practical uniformity in CFEngine syntax. There is only one grammatical form for statements in the language that you need to know and it looks generically like this:

     
      type:
     
        classes::
     
         "promiser" -> { "promisee1", "promisee2", ... }
     
            attribute_1 => value_1,
            attribute_2 => value_2,
            ...
            attribute_n => value_n;
     

We speak of a promiser (the abstract object making the promise), the promisee is the abstract object to whom the promise is made, and them there is a list of associations that we call the `body' of the promise, which together with the promiser-type tells us what it is all about.

Not all of these elements are necessary every time. Some promises contain a lot of implicit behaviour. In other cases we might want to be much more explicit. For example, the simplest promise looks like this:

     
     commands:
     
       "/bin/echo hello world";
     

This promise has default attributes for everything except the `promiser', i.e. the command string that promises to execute. A more complex promise contains many attributes:

     
     files:
     
       "/home/mark/tmp/test_plain" -> "system blue team",
     
            comment => "This comment follows the rule for knowledge integration",
            perms   => users("@(usernames)"),
            create  => "true";
     

The list of promisees is not used by CFEngine except for documentation, just as the comment attribute (which can be added to any promise) has no actual function other than to provide more information to the user in error tracing and auditing.

You see several kinds of object in this example. All literal strings (e.g. "true") in CFEngine 3 must be quoted. This provides absolute consistency and makes type-checking easy and error-correction powerful. All function-like objects (e.g. users("..")) are either builtin special functions or parameterized templates which contain the `meat' of the right hand side.

The words commands, and files are built-in promise types. Promise types generally belong each to a particular component of CFEngine, as the components are designed to keep different kinds of promises. A few types, such as vars, classes and reports are common to all the different component bundles. You will find a full list of the promise types that can be made by the different components in the `bundles' chapters that follow.


Next: , Previous: Rules are promises, Up: A simple crash course

2.2 Best practice for writing promises

When writing promises, get into the habit of giving every promise a comment that explains its intention.

Also, give related promises handles, or labels that can be used to refer to them by.

files:

  "/var/cfengine/inputs"

    handle => "update_policy",
    comment => "Update the configuration from a master server",

    perms => system("600"),
    copy_from => mycopy("$(master_location)","$(policy_server)"),
    depth_search => recurse("inf"),
    file_select => input_files,
    action => immediate;

If a promise affects another promise in some way, you can make the affected promise one of the promisees, like this:
access:

  "/master/cfengine/inputs" -> { "update_policy", "other_promisee" },

    comment => "Grant access to policy to our clients",
    handle  => "serve_updates",

    admit   => { "217.77.34.*" };

Conversely, if a promise might depend on another in some (even indirect) way, document this too.

files:

  "/var/cfengine/inputs"

    comment => "Update the configuration from a master server",
    handle     => "update_policy",

    depends_on => "serve_updates",

    perms => system("600"),
    copy_from => mycopy("$(master_location)","$(policy_server)"),
    depth_search => recurse("inf"),
    file_select => input_files,
    action => immediate;


Get into the habit of adding the cause-effect lines of influence. Enterprise editions of CFEngine will track the dependencies between these promises and map out impact analyses.


Next: , Previous: Best practice for writing promises, Up: A simple crash course

2.3 Containers

CFEngine allows you to group multiple promise statements into containers called bundles.

     
     bundle agent identifier
     
     {
     commands:
     
       "/bin/echo These commands are a silly way to use CFEngine";
       "/bin/ls -l";
       "/bin/echo But they illustrate a point";
     
     }
     

Bundles serve two purposes: they allow us to collect related promises under a single heading, like a subroutine, and they allow us to mix configuration for different parts of CFEngine in the same file. The type of a bundle is the name of the component of CFEngine for which it is intended.

For instance, we can make a self-contained example agent-server configuration by labelling the bundles:

     
     #
     # Not a complete example
     #
     
     bundle agent testbundle
     
     {
     files:
     
       "/home/mark/tmp/testcopy"
     
         comment      => "Throwaway example...",
         copy_from    => mycopy("/home/mark/LapTop/words","127.0.0.1"),
         perms        => system,
         depth_search => recurse("inf");
     
     }
     
     #
     
     bundle server access_rules
     
     {
     access:
     
       "/home/mark/LapTop"
     
         admit   => { "127.0.0.1" };
     }
     

Another type of container in CFEngine 3 is a `body' part. Body parts exist to hide complex parameter information in reusable containers. The right hand side of some attribute assignments use body containers to reduce the amount of in-line information and preserve readability. You cannot choose where to use bodies: either they are used or they are not used for a particular kind of attribute. What you can choose, however, is the name and number of parameters for the body; and you can make as many of them as you like: For example:

     
     body copy_from mycopy(from,server)
     
     {
     source      => "$(from)";
     servers     => { "$(server)" };
     copy_backup => "true";
     
     special_class::
     
       purge       => "true";
     }
     

Notice also that classes can be used in bodies as well as parameters so that you can hide environmental adaptations in these bodies also. The classes used here are effectively ANDed with the classes under which the calling promise is defined.


Next: , Previous: Containers, Up: A simple crash course

2.4 When and where are promises made?

When you type a promise into a CFEngine bundle, the promise will be read by every cf-agent that reads the file, each time it is called into being. For some promises this is okay, but for others you only want to verify the promise once in a while, e.g. once per day or once per hour. There are two ways to say when and where a promise applies in CFEngine:

Classes
Classes are the double-colon decision syntax in CFEngine. They determine in what context a promise is made, i.e. when and where. Recall the basic syntax of a promise:
          
           promise-type:
          
              class-expression::
          
                 promiser -> promisee
          
                    attribute => body,
                         ifvarclass => other-class-expression;
          

The class expression may contain words like ‘Hr12’, meaning from 12:00 p.m - 13:00 p.m., or ‘Hr12&Min05_10’, meaning between 12:05 and 12:10. Classes may also have spatial descriptors like ‘myhost’ or ‘solaris’, which decide which hosts in the namespace, or ‘ipv4_192_168_1_101’ which decides the location in IPv4 address space.

If the class expression is true, the promise can be considered made for the duration of the current execution.

CFEngine 3 has a new class predicate ifvarclass which is ANDed with the normal class expression, and which is evaluated together with the promise. It may contain variables as long as the resulting expansion is a legal class expression.

Locks
Locks determine how often a promise is verified.

CFEngine is controlled by a series of locks which prevent it from checking promises too often, and which prevent it from spending too long trying to verify promises it already verified recently. The locks work in such a way that you can start several CFEngine processes simultaneously without them interfering with each other. You can control two things about each kind of action in the action sequence:

ifelapsed
The minimum time (in minutes) which should have passed since the last time that promise was verified. It will not be executed again until this amount of time has elapsed. (Default time is 1 minute.)
expireafter
The maximum amount (in minutes) of time cf-agent should wait for an old instantiation to finish before killing it and starting again. (Default time is 120 minutes.)

You can set these values either globally (for all actions) or for each action separately. If you set global and local values, the local values override the global ones. All times are written in units of minutes. Global setting is in the control body:

body agent control
{
ifelapsed => "60";	# one hour
}

or locally in the transaction bodies:

body action example
{
ifelapsed => "90";	# 1.5 hours
}

These locks do not prevent the whole of cf-agent from running, only atomic promise checks. Several different atoms can be run concurrently by different cf-agents. The locks ensure that atoms will never be started by two cf-agents at the same time, or too soon after a verification, causing contention and wasting CPU cycles.


Next: , Previous: When and where are promises made?, Up: A simple crash course

2.5 Types in CFEngine 3

A key difference in CFEngine 3 compared to earlier versions is the presence of data types. Data types are a mechanism for associating values and checking consistency in a language. Once again, there is a simple pattern to types in CFEngine.

The principle is very simple: types exist in order to match like a plug-socket relationship. In the examples above, you can see two places where types are used to match templates:

Check these by identifying the words ‘agent’ and ‘copy_from’ in the examples above. Types are there to make configuration more robust.


Next: , Previous: Types in CFEngine 3, Up: A simple crash course

2.6 Datatypes in CFEngine 3

CFEngine variables have two meta-types: scalars and lists. A scalar is a single value, a list is a collection of scalars. Each scalar may have one of three types: string, int or real. Typing is dynamic, so these are interchangable in many instances. However arguments to special functions check legal type for consistency.

Integer constants may use suffixes to represent large numbers.


Next: , Previous: Datatypes in CFEngine 3, Up: A simple crash course

2.7 Variable expansion in CFEngine 3

CFEngine 3 has some simple rules for variable expansion. These make a couple of restrictions that enforce discipline of clarity and allow automatic dependency tracking in enterprise versions of CFEngine.


Next: , Previous: Variable expansion in CFEngine 3, Up: Variable expansion in CFEngine 3

2.7.1 Scalar variable expansion

Scalar variables are written ‘$(name)’ and they represent a single value at a time.


Next: , Previous: Scalar variable expansion, Up: Variable expansion in CFEngine 3

2.7.2 List variable substitution and expansion

During list expansion, only local lists can be expanded, thus global list references have to be mapped into a local context if you want to use them for iteration. Instead of doing this in some arbitrary way, with possibility of name collisions, CFEngine asks you to make this explicit. There are two possible approaches.

The first uses parameterization to map a global list into a local context.

#

# Show access of external lists.

#

# - to pass lists globally, use a parameter to dereference them

#


body common control
{
bundlesequence => { hardening(@(va.tmpdirs)) };
}

#########################################################


bundle common va
{
vars:

 "tmpdirs"  slist => { "/tmp", "/var/tmp", "/usr/tmp"  };

}

##########################################################


bundle agent hardening(x)
{
classes:

  "ok" expression => "any";

vars:

 "other"    slist => { "/tmp", "/var/tmp" };

reports:

  ok::

    "Do $(x)";
    "Other: $(other)";
}

This alternative uses a direct `short-circuit' approach to map the global list into the local context.

#
# Show access of external lists.

#


body common control
{
bundlesequence => { hardening };
}

#########################################################


bundle common va
{
vars:

 "tmpdirs"  slist => { "/tmp", "/var/tmp", "/usr/tmp"  };

}

##########################################################


bundle agent hardening
{
classes:

  "ok" expression => "any";

vars:

 "other"    slist => { "/tmp", "/var/tmp" };
 "x"        slist => { @(va.tmpdirs) };

reports:

  ok::

    "Do $(x)";
    "Other: $(other)";
}


Next: , Previous: List variable substitution and expansion, Up: Variable expansion in CFEngine 3

2.7.3 Special list value cf_null

As of CFEngine core version 3.1.0, the value ‘cf_null’ may be used as a NULL value within lists. This value is ignored in list variable expansion.

vars:

  "empty_list" slist => { "cf_null" };


Previous: Special list value cf_null, Up: Variable expansion in CFEngine 3

2.7.4 Arrays in CFEngine 3

Array variables are written with ‘[’ and ‘]’ brackets, e.g.

bundle agent example

{
vars:

  "component" slist => { "cf-monitord", "cf-serverd", "cf-execd" };

  "array[cf-monitord]" string => "The monitor";
  "array[cf-serverd]" string => "The server";
  "array[cf-execd]" string => "The executor, not executioner";

commands:

   "/bin/echo $(component) is"

            args => "$(array[$(component)])";

}

Arrays are associative and may be of type scalar or list. Enumerated arrays are simply treated as a special case of associative arrays, since there are no numerical loops in CFEngine. Special functions exist to extract lists of keys from array variables for iteration purposes.

Thus one could have written the example above in the form of the following example. Note, too, that the use of getindices avoids the earlier poor practice of repeating the enumeration of key names, and instead uses the better strategy of automatically deriving them.

bundle agent example

{
vars:

  "array[cf-monitord]" string => "The monitor";
  "array[cf-serverd]" string => "The server";
  "array[cf-exced]" string => "The executor, not executioner";

  "component" slist => getindices("array");

commands:

  "/bin/echo $(component) is"

           args => "$(array[$(component)])";
}


Next: , Previous: Variable expansion in CFEngine 3, Up: A simple crash course

2.8 Normal ordering

CFEngine takes a pragmatic point of view to ordering. When promising `scalar' attributes and properties, ordering is irrelevant and need not be considered. More complex patterned data structures require ordering to be preserved, e.g. editing in files. CFEngine solves this in a two-part strategy:


Next: , Previous: Normal ordering, Up: Normal ordering

2.8.1 Agent normal ordering

  1. CFEngine tries to keep variable and class promises before starting to consider any other kind of promise. In this way, global variable and classes can be set, as well as creating classes promises, upon which later agent-bundle vars promises may depend. Place these at the start of your configuration (see next item).
  2. If you set variables based on classes that are determined by variables, in a complex dependency chain, then you introduce an order dependence to the resolution that might be non-unique. Since CFEngine starts trying to converge values as soon as possible, it is best to define variables in bundles before using them, i.e. as early as possible in your configuration. In general it is wise to avoid class-variable dependency as much as possible.
  3. CFEngine executes agent promise bundles in the strict order defined by the bundlesequence (possibly overridden by the -b or --bundlesequence command line option).
  4. Within a bundle, the promise types are executed in a round-robin fashion according to so-called `normal ordering' (essentially deletion first, followed by creation). The actual sequence continues for up to three iterations of the following, converging towards a final state:
            vars
            classes
            outputs
            interfaces
            files
            packages
            environments
            methods
            processes
            services
            commands
            storage
            databases
            reports
    

    Within edit_line bundles in files promises (See `File editing in CFEngine 3' for important details), the normal ordering is:

            vars
            classes
            delete_lines
            field_edits
            insert_lines
            replace_patterns
            reports
    
  5. The order of promises within one of the above types follows their top-down ordering within the bundle itself
  6. The order may be overridden by making a promise depend on a class that is set by another promise.


Next: , Previous: Agent normal ordering, Up: Normal ordering

2.8.2 Server normal ordering

As with the agent, common bundles are executed before any server bundles; following this all server bundles are executed (the bundlesequence is only used for cf-agent). Within a server bundle, the promise types are unamgibuous. Variables and classes are resolved in the same way as the agent. On connection, access control must be handled first, then a role request might be made once access has been granted. Thus ordering is fully constrained by process with no additional freedoms.

Within a server bundle, the normal ordering is:

   vars
   classes
   access
   roles


Next: , Previous: Server normal ordering, Up: Normal ordering

2.8.3 Monitor normal ordering

As with the agent, common bundles are executed before any monitor bundles; following this all monitor bundles are executed (the bundlesequence is only used for cf-agent). Variables and classes are resolved in the same way as the agent.

Within a monitor bundle, the normal ordering is:

   vars
   classes
   measurements
   reports


Previous: Monitor normal ordering, Up: Normal ordering

2.8.4 Knowledge normal ordering

As with the agent, common bundles are executed before any knowledge bundles; following this all knowledge bundles are executed (the bundlesequence is only used for cf-agent). Variables and classes are resolved in the same way as the agent.

Within a knowledge bundle, the normal ordering is:

   vars
   classes
   topics
   occurrences
   inferences
   reports


Next: , Previous: Normal ordering, Up: A simple crash course

2.9 Loops and lists in CFEngine 3

There are no explicit loops in CFEngine, instead there are lists. To make a loop, you simply refer to a list as a scalar and CFEngine will assume a loop over all items in the list.

For example, in the examples below the list component has three elements. The list as a whole may be referred to as @(component), in order to pass the whole list to a promise where a list is expected. However, if we write $(component), i.e. the scalar variable, then CFEngine assumes that it should substitute each scalar from the list in turn, and thus iterate over the list elements using a loop.

body common control

{
bundlesequence  => { "example" };
}

###########################################################


bundle agent example

{
vars:

  "component" slist => { "cf-monitord", "cf-serverd", "cf-execd" };

  "new_list" slist => { "cf-know", @(component) };

processes:

  "$(component)" restart_class => canonify("start_$(component)");

commands:

   "/bin/echo /var/cfengine/bin/$(component)"

       ifvarclass => canonify("start_$(component)");
}

If a variable is repeated, its value is tied throughout the expression; so the output of:

body common control

{
bundlesequence  => { "example" };
}

###########################################################


bundle agent example

{
vars:

  "component" slist => { "cf-monitord", "cf-serverd", "cf-execd" };

  "array[cf-monitord]" string => "The monitor";
  "array[cf-serverd]" string => "The server";
  "array[cf-execd]" string => "The executor, not executioner";

commands:

   "/bin/echo $(component) is"

            args => "$(array[$(component)])";
}

is as follows:

Q ".../bin/echo cf-mo": cf-monitord is The monitor
 -> Last 1 QUOTEed lines were generated by "/bin/echo cf-monitord is The monitor"
Q ".../bin/echo cf-se": cf-serverd is The server
 -> Last 1 QUOTEed lines were generated by "/bin/echo cf-serverd is The server"
Q ".../bin/echo cf-ex": cf-execd is The executor, not executioner
 -> Last 1 QUOTEed lines were generated by "/bin/echo cf-execd is The executor, not executioner"


Next: , Previous: Loops and lists in CFEngine 3, Up: A simple crash course

2.10 Pattern matching and referencing

One of the strengths of CFEngine 3 is the ability to recognize and exploit patterns. All string patterns in CFEngine 3 are matched using PCRE regular expressions.

CFEngine has the ability to extract back-references from pattern matches. This makes sense in two cases. Back references are fragments of a string that match parenethetic expressions. For instance, suppose we have the string:

     
      Mary had a little lamb ...
     

and apply the regular expression

     
      "Mary ([^l]+)little (.*)"
     

The pattern matches the entire string, and it contains two parenthesized subexpressions, which respectively match the fragments `had a ' and `lamb ...'. The regular expression libraries assign three matches to this result, labelled 0, 1 and 2.

The zeroth value is the entire string matched by the total expression. The first value is the fragment matched by the first parenthesis, and so on.

Each time CFEngine matches a string, these values are assigned to a special variable context $(match.n). The fragments can be referred to in the remainder of the promise. There are two places where this makes sense. One is in pattern replacement during file editing, and the other is in searching for files.

Consider the examples below:

bundle agent testbundle

{
files:

  # This might be a dangerous pattern - see explanation in the next section

  # on "Runaway change warning"


  "/home/mark/tmp/cf([23])?_(.*)"
       edit_line => myedit("second backref: $(match.2)");
}

There are other filenames that could match this pattern, but if, for example, there were to exist a file /home/mark/tmp/cf3_test, then we would have:
$(match.0)
equal to `/home/mark/tmp/cf3_test'
$(match.1)
equal to `3'
$(match.2)
equal to `test'

Note that because the pattern allows for an optional '2' or '3' to follow the letters 'cf', it is possible that $(match.1) would contain the empty string. For example, if there was a file named /home/mark/tmp/cf_widgets, then we would have

$(match.0)
equal to `/home/mark/tmp/cf_widgets'
$(match.1)
equal to `'
$(match.2)
equal to `widgets'

Now look at the edit bundle. This takes a parameter (which is the back-reference from the filename match), but it also uses back references to replace shell comment lines with C comment lines (the same approach is used to hash-comment lines in files). The back-reference variables $(match.n) refer to the most recent pattern match, and so in the ‘C_comment’ body, they do not refer to the filename components, but instead to the hash-commented line in the ‘replace_patterns’ promise.

bundle edit_line myedit(parameter)
  {
  vars:

   "edit_variable" string => "private edit variable is $(parameter)";

  insert_lines:

     "$(edit_variable)";

  replace_patterns:

  # replace shell comments with C comments


   "#(.*)"

      replace_with => C_comment,
     select_region => MySection("New section");

  }

########################################

# Bodies

########################################


body replace_with C_comment

{
replace_value => "/* $(match.1) */"; # backreference from replace_patterns
occurrences => "all";  # first, last, or all
}

########################################################


body select_region MySection(x)

{
select_start => "\[$(x)\]";
select_end => "\[.*\]";
}

Try this example on the file

[First section]

one
two
three

[New section]

four
#five

six

[final]

seven
eleven

The resulting file is edited like this:

[First section]

one
two
three

[New section]

four
/* five */
six

[final]

seven
eleven

private edit variable is second backref: test


Next: , Previous: Pattern matching and referencing, Up: Pattern matching and referencing

2.10.1 Runaway change warning

Be careful when using patterns to search for files that are altered by CFEngine if you are not using a file repository. Each time CFEngine makes a change it saves an old file into a copy like cf3_test.cf-before-edit. These new files then get matched by the same expression above – because it ends in the generic.*), or does not specify a tail for the expression. Thus CFEngine will happily edit backups of the edit file too, and generate a recursive process, resulting in something like the following:

     cf3_test                  cf3_test.cf-before-edit
     cf3_test~                 cf3_test~.cf-before-edit.cf-before-edit
     cf3_test~.cf-before-edit  cf3_test~.cf-before-edit.cf-before-edit.cf-before-edit

Always try to be as specific as possible when specifying patterns. A lazy approach will often come back to haunt you.


Next: , Previous: Runaway change warning, Up: Pattern matching and referencing

2.10.2 Commenting lines

The following example shows how you would hash-comment lines in a file using CFEngine 3.

######################################################################
#

# HashCommentLines implemented in CFEngine 3

#

######################################################################


body common control

{
version => "1.2.3";
bundlesequence  => { "testbundle"  };
}

########################################################


bundle agent testbundle

{
files:

  "/home/mark/tmp/comment_test"

       create    => "true",
       edit_line => comment_lines_matching;
}

########################################################


bundle edit_line comment_lines_matching
  {
  vars:

    "regexes" slist => { "one.*", "two.*", "four.*" };

  replace_patterns:

   "^($(regexes))$"
      replace_with => comment("# ");
  }

########################################

# Bodies

########################################


body replace_with comment(c)

{
replace_value => "$(c) $(match.1)";
occurrences => "all";
}


Next: , Previous: Commenting lines, Up: Pattern matching and referencing

2.10.3 Regular expressions in paths

When applying regular expressions in paths, the path will first be split at the path separators, and each element matched independently. For example, this makes it possible to write expressions like "/home/.*/file" to match a single file inside a lot of directories — the .* does not eat the whole string.

Note that whenever regular expressions are used in paths, the / is always used as the path separator, even on Windows. However, on Windows, if the pathname is interpreted literally (no regular expressions), then the backslash is also recognized as the path separator. This is because the backslash has a special (and potentially ambiguous) meaning in regular expressions (a \d means the same as [0-9], but on Windows it could also be a path separator and a directory named d).

The pathtype attribute allows you to force a specific behavior when interpreting pathnames. By default, CFEngine looks at your pathname and makes an educated guess as to whether your pathname contains a regular expression. The values "literal" and "regex" explicitly force CFEngine to interpret the pathname either one way or another.

(see the pathtype attribute).

body common control
{
bundlesequence => { "wintest" };
}

########################################


bundle agent wintest
{
files:
  "c:/tmp/file/f.*"		# "best guess" interpretation
    delete => nodir;


  "c:\tmp\file"
    delete => nodir,
    pathtype => "literal";	# force literal string interpretation


  "C:/windows/tmp/f\d"
    delete => nodir,
    pathtype => "regex";	# force regular expression interpretation
}

########################################


body delete nodir
{
rmdirs => "false";
}

Note that the path ‘/tmp/gar.*’ will only match filenames like /tmp/gar, /tmp/garbage and /tmp/garden. It will not match filename like /tmp/gar/baz (because even though the ‘.*’ in a regular expression means "zero or more of any character", CFEngine restricts that to mean "zero or more of any character in a path component"). Correspondingly, CFEngine also restricts where you can use the ‘/’ character (you can't use it in a character class like ‘[^/]’ or in a parenthesized or repeated regular expression component.

This means that regular expressions which include "optional directory components" won't work. You can't have a files promise to tidy the directory ‘(/usr)?/tmp’. Instead, you need to be more verbose and specify ‘/usr/tmp|/tmp’, or even better, think declaratively and create an slist that contains both the strings ‘/tmp’ and ‘/usr/tmp’, and then allow CFEngine to iterate over the list!

This also means that the path ‘/tmp/.*/something’ will match files like /tmp/abc/something or /tmp/xyzzy/something. However, even though the pattern ‘.*’ means "zero or more of any character (except ‘/’)", CFEngine matches files bounded by directory separators. So even though the pathname /tmp//something is technically the same as the pathname /tmp/something, the regular expression ‘/tmp/.*/something’ will not match on the degenerate case of /tmp//something (or /tmp/something).


Next: , Previous: Regular expressions in paths, Up: Pattern matching and referencing

2.10.4 Anchored vs. unanchored regular expressions

CFEngine uses the full power of regular expressions, but there are two “flavors” of regex. Because they behave somewhat differently (while still utilizing the same syntax), it is important to know which one is used for a particular component of CFEngine:

For example, the comment parameter in readstringarray is an unanchored regex (see Function readstringarray). If you specify the regular expression as "#.*", then on any line which contains a pound sign, everything from there until the end of the line will be removed as a comment. However, if you specify the regular expression as "^#.*" (note the ‘^’ anchor at the start of the regex), then only lines which start with a ‘#’ will be removed as a comment! If you want to ignore C-style comment in a multi-line string, then you have to a bit more clever, and use this regex: "(?s)/\*.*?\*/"

Conversely, delete_lines promises use anchored regular expressions to delete lines. If our promise uses "bob:\d* as a line-matching regex, then only the second line of this file will be deleted (because only the second line starts with ‘bob:’ and is then followed exclusively by digits, all the way to the end of the string).

bobs:your:uncle
bob:111770
thingamabob:1234
robert:bob:xyz
i:am:not:bob

If CFEngine expects an unanchored regular expression, then finding every line that contains the letters ‘bob’ is easy. You just use the regex "bob". But if CFEngine expects an anchored regular expression, then you must use ".*bob.*".

If you want to find every line that has a field which is exactly ‘bob’ with no characters before or after, then it is only a little more complicated if CFEngine expects an unanchored regex: "(^|:)bob(:|$)". But if CFEngine expects an anchored regular expression, then it starts getting ugly, and you'd need to use "bob:.*|.*:bob:.*|.*:bob".


Previous: Anchored vs. unanchored regular expressions, Up: Pattern matching and referencing

2.10.5 Special topics on Regular Expressions

Regular expressions are a complicated subject, and really are beyond the scope of this document. However, it is worth mentioning a couple of special topics that you might want to know of when using regular expressions.

The first is how to not get a backreference. If you want to have a parenthesized expression that does not generate a back reference, there is a special PCRE syntax to use. Instead of using () to bracket the piece of a regular expression, use (?:) instead. For example, this will match the filenames foolish, foolishly, bearish, bearishly, garish, and garishly in the /tmp directory. The variable $match.0 will contain the full filename, and $match.1 will either contain the string ‘ly’ or the empty string. But the (?:expression) which matches foo, bear, or gar does not create a back-reference:

files:
    "/tmp/(?:foo|bear|gar)ish(ly)?"

Note that sometimes multi-line strings are subject to be matched by regular expressions. CFEngine internally matches all regular expressions using PCRE_DOTALL option, so . matches newlines. If you want to match any character except newline you could use \N escape sequence.

Another thing you might want to do is ignore capitalization. CFEngine is case-sensitive (in all things), so the files promise /tmp/foolish will not match the files /tmp/Foolish or /tmp/fOoLish, etc. There are two ways to acheive case-insensitivity. The first is to use character classes:

files:
    "/tmp/[Ff][Oo][Oo][Ll][Ii][Ss][Hh]"

While this is certainly correct, it can also lead to unreadability. The PCRE patterns in CFEngine have another way of introducing case-insensitvity into a pattern:

files:
    "/tmp/(?i:foolish)"

The (?i:) brackets impose case-insensitive matching on the text that it surrounds, without creating a sub-expression. You could also write the regular expression like this (but be aware that the two expressions are different, and work slightly differently, so check the documentation for the specifics):

files:
    "/tmp/(?i)foolish"

The /s, /m, and /x switches from PCRE are also available, but use them with great care!


Previous: Pattern matching and referencing, Up: A simple crash course

2.11 Distributed discovery

CFEngine's philosophy and modus operandi is to make machines as self-reliant as possible. This is the path to scalability. Sometimes we want machines to be able to detect one another and sample each others' behaviour. This can be accomplished using probes and server functions.

For example, testing whether services are up and running can be a useful probe even from a local host. CFEngine has in-built functions for generically probing the environment; these are designed to encourage decentralized monitoring.

body common control

{
bundlesequence  => { "test"  };
}

###########################################################


bundle agent test

{
vars:

 "hosts" slist => { "server1.example.org", "server2", "server3" };

 "up_servers" int =>  selectservers("@(hosts)","80","","","100","alive_servers");

classes:

  "someone_alive" expression => isgreaterthan("$(up_servers)","0");

  "i_am_a_server" expression => regarray("up_servers","$(host)|$(fqhost)");

reports:

  someone_alive::

    "Number of active servers $(up_servers)" action => always;

    "First server $(alive_servers[0]) fails over to $(alive_servers[1])";


}


Next: , Previous: A simple crash course, Up: Top

3 How to run CFEngine 3 examples

The CFEngine tests directory contains a multitude of examples of CFEngine 3 code. These instructions assume that you have all of your configuration in a single test file, such as the example in the distribution directory tests/units.

  1. Test the file as a non-privileged user first, if you can.
  2. Always verify syntax first with cf-promises. This requires no privileges. An cf-agent will not execute a configuration that has not passed this test.
              
              host$ cf-promises -f ./inputfile.cf
              
    
  3. Run the examples like this, e.g.
              
              host$ src/cf-promises -f ./tests/units/unit_server_copy_localhost.cf
              host$ src/cf-serverd -f ./tests/units/unit_server_copy_localhost.cf
              host$ src/cf-agent -f ./tests/units/unit_server_copy_localhost.cf
              
    

Running cf-agent in verbose mode provides detailed information about the state of the systems promises.

     Outcome of version 1.2.3: Promises observed to be kept 99%,
     Promises repaired 1%, Promises not repaired 0%

The log-file WORKDIR/promise.log contains the summary of these reports with timestamps. This is the simplest kind of high level audit record of the system.


Next: , Previous: How to run CFEngine 3 examples, Up: Top

4 A complete configuration

To illustrate a complete configuration for agents and daemons, consider the following example code, supplied in the inputs/ directory of the distribution. Comments indicate the thinking behind this starting point.


Next: , Previous: A complete configuration, Up: A complete configuration

4.1 promises.cf

This file is the first file that cf-agent with no arguments will try to look for. It should contain all of the basic configuration settings, including a list of other files to include. In normal operation, it must have a bundlesequence.

This file can stay fixed, except for extending the bundlesequence. The bundlesequence acts like the `genetic makeup' of the configuration. In a large configuration, you might want to have a different bundlesequence for different classes of host, so that you can build a complete system like a check-list from different combinations of building blocks. You can construct different lists by composing them from other lists, or you can use methods promises as an alternative for composing bundles for different classes.

#######################################################
#

# promises.cf

#

#######################################################


body common control

{
# List the `genes' for this system..


bundlesequence  => {
                   "update",
                   "garbage_collection",
                   "main",
                   "cfengine"
                   };


inputs          => {
                   "update.cf",
                   "site.cf",
                   "library.cf"
                   };
}

#######################################################

# Now set defaults for all components' hard-promises

#######################################################


body agent control
{
# if default runtime is 5 mins, we need more for long jobs

ifelapsed => "15";
}

#######################################################


body monitor control
{
forgetrate => "0.7";
}

###########si###########################################


body executor control

{
splaytime => "1";
mailto => "cfengine_mail@example.org";
smtpserver => "localhost";
mailmaxlines => "30";

# Instead of a separate update script, now do this


exec_command => "$(sys.workdir)/bin/cf-agent -f failsafe.cf && $(sys.workdir)/bin/cf-agent";
}

#######################################################


body reporter control

{
reports => { "performance", "last_seen", "monitor_history" };
build_directory => "/tmp/nerves";
report_output => "html";
}

#######################################################


body runagent control
{
hosts => {
          "127.0.0.1"
          # , "myhost.example.com:5308", ...

         };

}

#######################################################


body server control

{
allowconnects         => { "127.0.0.1" , "::1" };
allowallconnects      => { "127.0.0.1" , "::1" };
trustkeysfrom         => { "127.0.0.1" , "::1" };

# Make updates and runs happen in one


cfruncommand => "$(sys.workdir)/bin/cf-agent";

allowusers   => { "root" };
}


Next: , Previous: promises.cf, Up: A complete configuration

4.2 site.cf

Use this file to add your site-specific configuration. Common bundles can be used to define global variables. Otherwise, unqualified variables are local to the bundle in which they are defined – however they can be access by writing $(bundle_name.variable_name).

#######################################################
#

# site.cf

#

#######################################################


bundle common g
{
vars:

  SuSE::

   "crontab" string => "/var/spool/cron/tabs/root";

 !SuSE::

   "crontab" string => "/var/spool/cron/crontabs/root";
}

The CFEngine bundle below detects whether CFEngine 2 is already running on the host or not, and if so attempts to kill off old daemon processes and encapsulate the agent. It also looks for rules in the old CFEngine configuration that would potentially spoil CFEngine 3's control of the system: the last thing we want is for CFEngine 2 and CFEngine 3 to fight each other for control of the system. CFEngine 3 tries to edit an existing crontab entry to replace any references to cfexecd with cf-execd; if none are found it will add a 5 minute run schedule. You should never put cf-agentor cf-agent directly inside cron without the cf-execd wrapper.

#######################################################
# Start with CFEngine itself

#######################################################


bundle agent cfengine

{
classes:

  "integrate_cfengine2"

      and => {
             fileexists("$(sys.workdir)/inputs/cfagent.conf"),
             fileexists("$(sys.workdir)/bin/cfagent")
             };

vars:

   "cf2bits" slist => { "cfenvd", "cfservd", "cfexecd" };

commands:

 integrate_cfengine2::

   "$(sys.workdir)/bin/cfagent"

        action => longjob;

files:

  # Warn about rules relating to CFEngine 2 in inputs - could conflict


  "$(sys.workdir)/inputs/.*"

       comment     => "Check if there are still promises about CFEngine 2 that need removing",
       edit_line   => DeleteLinesMatching(".*$(cf2bits).*"),
       file_select => OldCf2Files,
       action      => WarnOnly;

  # Check cf-execd and schedule is in crontab


  "$(g.crontab)"
       edit_line => upgrade_cfexecd,
         classes => define("exec_fix");

processes:

  exec_fix::

    "cron" signals => { "hup" };


}

#######################################################

# General site issues can be in bundles like this one

#######################################################


bundle agent main

{
vars:

  "component" slist => { "cf-monitord", "cf-serverd" };

 # - - - - - - - - - - - - - - - - - - - - - - - -


files:

  "$(sys.resolv)"  # test on "/tmp/resolv.conf" #

     create        => "true",
     edit_line     => resolver,
     edit_defaults => def;

 # Uncomment this to perform a change-detection scan


 #  "/usr"

 #     changes      => lay_trip_wire,

 #     depth_search => recurse("inf"),

 #     action       => measure;


processes:

  "cfenvd"             signals => { "term" };

 # Uncomment this when you are ready to upgrade the server

 #

 #  "cfservd"             signals => { "term" };

 #


 # Now make sure the new parts are running, cf-serverd will fail if

 # the old server is still running


  "$(component)" restart_class => canonify("start_$(component)");

 # - - - - - - - - - - - - - - - - - - - - - - - -


commands:

   "$(sys.workdir)/bin/$(component)"

       ifvarclass => canonify("start_$(component)");

}

This section takes a backup of a user home directory. This is especially useful for a single laptop or personal workstation that does not have a regular external backup. If a user deletes a file by accident, this shadow backup might contain the file even while travelling offline.

#######################################################

# Backup

#######################################################


bundle agent backup
{
files:

  "/home/backup"

     copy_from => cp("/home/mark"),
  depth_search => recurse("inf"),
   file_select => exclude_files,
        action => longjob;

}

#######################################################

# Garbage collection issues

#######################################################


bundle agent garbage_collection
{
files:

  "$(sys.workdir)/outputs"

    delete => tidy,
    file_select => days_old("3"),
    depth_search => recurse("inf");


}

###########################################################


body file_select OldCf2Files
{
leaf_name => {
             "promises\.cf",
             "site\.cf",
             "library\.cf",
             "failsafe\.cf",
             ".*\.txt",
             ".*\.html",
             ".*~",
             "#.*"
             };

file_result => "!leaf_name";
}

###########################################################


body action measure
{
measurement_class => "Detect Changes in /usr";
ifelapsed => "240";	# 4 hours
expireafter => "240";	# 4 hours
}

Some basic anomaly detection: we respond with simple warnings if resource anomalies are detected.

#######################################################
# Anomaly monitoring

#######################################################


bundle agent anomalies
{
reports:

rootprocs_high_dev2::

   "RootProc anomaly high 2 dev on $(mon.host) at $(mon.env_time)
    measured value $(mon.value_rootprocs) av $(mon.av_rootprocs)
    pm $(mon.dev_rootprocs)"

      showstate => { "rootprocs" };

entropy_www_in_high&anomaly_hosts.www_in_high_anomaly::

   "HIGH ENTROPY Incoming www anomaly high anomaly dev!!
    on $(mon.host) at $(mon.env_time)
    - measured value $(mon.value_www_in)
    av $(mon.av_www_in) pm $(mon.dev_www_in)"

      showstate => { "incoming.www" };

 entropy_www_in_low.anomaly_hosts.www_in_high_anomaly::

   "LOW ENTROPY Incoming www anomaly high anomaly dev!!
    on $(mon.host) at $(mon.env_time)
     - measured value $(svalue_www_in)
    av $(av_www_in) pm $(dev_www_in)"

     showstate => { "incoming.www" };

entropy_tcpsyn_in_low.anomaly_hosts.tcpsyn_in_high_dev2::

   "Anomalous number of new TCP connections on $(mon.host)
    at $(mon.env_time)
    - measured value $(mon.value_tcpsyn_in)
    av $(mon.av_tcpsyn_in) pm $(mon.dev_tcpsyn_in)"

     showstate => { "incoming.tcpsyn" };

 entropy_dns_in_low.anomaly_hosts.dns_in_high_anomaly::

   "Anomalous (3dev) incoming DNS packets on $(mon.host)
    at $(mon.env_time) - measured value $(mon.value_dns_in)
    av $(av_dns_in) pm $(mon.dev_dns_in)"

     showstate => { "incoming.dns" };

 entropy_dns_in_low.anomaly_hosts.udp_in_high_dev2::

   "Anomalous (2dev) incoming (non-DNS) UDP traffic
    on $(mon.host) at $(mon.env_time) - measured value
    $(mon.value_udp_in) av $(mon.av_udp_in) pm $(mon.dev_udp_in)"

     showstate => { "incoming.udp" };

 anomaly_hosts.icmp_in_high_anomaly.!entropy_icmp_in_high::

   "Anomalous low entropy (3dev) incoming ICMP traffic
    on $(mon.host) at $(mon.env_time) - measured value $(mon.value_icmp_in)
    av $(mon.av_icmp_in) pm $(mon.dev_icmp_in)"

     showstate => { "incoming.icmp" };
}

Server access rules are a touchy business. In an enterprise setting you generally want every host to allow a monitoring host to be able to download data, and a backup host to be able to access important data on every host. On a laptop or personal workstation, there might not be any reason to run a server for external use; however you might configure it as below to allow localhost access for testing.

#######################################################

# Server configuration

#######################################################


bundle server access_rules()
{
access:

  "/home/mark/test_area"

    admit   => { "127.0.0.1" };

  # Rule for cf-runagent


  "/home/mark/.cfagent/bin/cf-agent"

    admit   => { "127.0.0.1" };

# New in cf3 - RBAC with cf-runagent


roles:

  ".*"  authorize => { "mark" };
}


Next: , Previous: site.cf, Up: A complete configuration

4.3 update.cf

This file should rarely if ever change. Should you ever change it (or when you upgrade CFEngine), take special care to ensure the old and the new CFEngine can parse and execute this file successfully. If not, you risk losing control of your system (that is, if CFEngine cannot successfully execute this set of promises, it has no mechanism for distributing new policy files).

By default, the policy defined in update.cf is executed from two sets of promise bodies. The “usual” one (defined in the bundlesequence in promises.cf) and another in the backup/failsafe bundlesequence (defined in failsafe.cf).

#########################################################
#

# update.cf

#

#########################################################


bundle agent update
{
vars:

 "master_location" string => "/your/master/cfengine-inputs";

files:

  # Update the configuration


  "/var/cfengine/inputs"

    perms => system("600"),
    copy_from => mycopy("$(master_location)","localhost"),
    depth_search => recurse("inf"),
    action => immediate;

  # Update the software cache


  "/var/cfengine/bin"

    perms => system("700"),
    copy_from => mycopy("/usr/local/sbin","localhost"),
    depth_search => recurse("inf"),
    action => immediate;
}

############################################


body perms system(p)

{
mode  => "$(p)";
}

############################################


body file_select cf3_files

{
leaf_name => { "cf-.*" };

file_result => "leaf_name";
}

#########################################################


body copy_from mycopy(from,server)

{
source      => "$(from)";
compare     => "digest";
}

#########################################################


body action immediate
{
ifelapsed => "1";
}


Next: , Previous: update.cf, Up: A complete configuration

4.4 failsafe.cf

This file should probably never change. The only job of failsafe.cf is to execute the update bundle in a “standalone” context should there be a syntax error somewhere in the main set of promises. In this way, if a client machine's policies are ever corrupted after downloading erroneous policy from a server, that client will have a failsafe method for downloading a corrected policy once it becomes available on the server. Note that by “corrupted” and “erroneous” we typically mean “broken via administrator error” - mistakes happen, and the failsafe.cf file is CFEngine's way of being prepared for that eventuality.

If you ever change failsafe.cf (or when you upgrade CFEngine), make sure the old and the new CFEngine can successfully parse and execute this file. If not, you risk losing control of your system (that is, if CFEngine cannot successfully execute this policy file, it has no failsafe/fallback mechanism for distributing new policy files).

#########################################################
#

# Failsafe file

#

#########################################################


body common control

{
bundlesequence => { "update" };

inputs => { "update.cf" };
}

############################################


body depth_search recurse(d)

{
depth => "$(d)";
}


Next: , Previous: failsafe.cf, Up: A complete configuration

4.5 What should a failsafe and update file contain?

The failsafe.cf file is to make sure that your system can upgrade gracefully to new versions even when mistakes are made.

As a general rule:

A CFEngine configuration will fail-over to the failsafe.cf configuration if it is unable to read or parse the contents successfully. That means that any syntax errors you introduce (or any new features you utilize in a configuration) will cause a fail-over, because the parser will not be able to interpret the policy. If the failover is due to the use of new features, they will not parse until the software itself has been updated (so we recommend that you always update CFEngine before updating policy to use new features). If you accidentally cause a bad (i.e., unparseable) policy to be distributed to client machines, the failsafe.cf policy on those machines will run (and will eventually download a working policy, once you fix it on the policy host).


Next: , Previous: What should a failsafe or update file contain, Up: A complete configuration

4.6 Recovery from errors in the configuration

The failsafe.cf file should be able to download the latest master configuration from source always.

#######################################################

#

# failsafe.cf

#

#######################################################


body common control

{
bundlesequence => { "update" };
}

#########################################################


bundle agent update
{
files:

  "/var/cfengine/inputs"

    perms => system,
    copy_from => mycopy("/home/mark/cfengine-inputs","localhost"),
    file_select => cf3_files,
    depth_search => recurse("inf");

  "/var/cfengine/bin"

    perms => system,
    copy_from => mycopy("/usr/local/sbin","localhost"),
    file_select => cf3_files,
    depth_search => recurse("inf");

}

#########################################################


body perms system

{
mode  => "0700";
}

#########################################################


body depth_search recurse(d)

{
depth => "$(d)";
}

############################################


body file_select cf3_files

{
leaf_name => { "cf-.*" };

file_result => "leaf_name";
}

#########################################################


body copy_from mycopy(from,server)

{
source       => "$(from)";
servers      => { "$(server)" , "failover.domain.tld" };
#copy_backup => "true";

#trustkey    => "true";

encrypt      => "true";
}

If the copy_backup option is true, CFEngine will keep a single previous version of the file before copy, if the value is ‘timestamp’ CFEngine keeps time-stamped versions either in the location of the file, or in the file repository if one is defined. The trustkey option should normally be commented out so that public keys are only exchanged under controlled conditions.


Previous: Recovery from errors in the configuration, Up: A complete configuration

4.7 Recovery from errors in the software

The update should optionally include an update of software so that a single failover from a configuration that is `too new' for the software will still correct itself once the new software is available.

#######################################################

#

# update.cf

#

#######################################################


bundle agent update

{
files:

  "/var/cfengine/inputs"

    perms => system("600"),
    copy_from => mycopy("/home/mark/cfengine-inputs","localhost"),
    depth_search => recurse("inf");

  "/var/cfengine/bin"

    perms => system("700"),
    copy_from => mycopy("/usr/local/sbin","localhost"),
    file_select => cf3_files,
    depth_search => recurse("inf");

}

############################################


body perms system(p)

{
mode  => "$(p)";
}

############################################


body file_select cf3_files

{
leaf_name => { "cf-.*" };

file_result => "leaf_name";
}

#########################################################


body copy_from mycopy(from,server)

{
source      => "$(from)";
compare     => "digest";
}


Next: , Previous: A complete configuration, Up: Top

5 Control promises


While promises to configure your system are entirley user-defined, the details of the operational behaviour of the CFEngine software is of course hard-coded. You can still configure the details of this behaviour using the control promise bodies. Control behaviour is defined in bodies because the actual promises are fixed and you only change their details within sensible limits.

Note that in CFEngine's previous versions, the control part of the configuration contained a mixture of internal control parameters and user definitions. There is now a cleaner separation in CFEngine 3. User defined behaviour requires a promise, and must therefore be defined in a bundle.

Below is a list of the control parameters for the different components (Agents and Daemons2) of the CFEngine software.


Next: , Previous: Control Promises, Up: Control Promises

5.1 common control promises


     
     body common control
     
     {
     inputs  => {
                "update.cf",
                "library.cf"
                };
     
     bundlesequence  => {
                        update("policy_host.domain.tld"),
                        "main",
                        "cfengine2"
                        };
     
     output_prefix => "cfengine>";
     version => "1.2.3";
     }
     


The common control body refers to those promises that are hard-coded into all the components of CFEngine, and therefore affect the behaviour of all the components.


Next: , Previous: control common, Up: control common

5.1.1 bundlesequence

Type: slist

Allowed input range: .*

Synopsis: List of promise bundles to verify in order

Example:

body common control

{
bundlesequence  => {
                   update("policy_host.domain.tld"),
                   "main",
                   "cfengine2"
                   };
}

Notes:

The bundlesequence determines which of the compiled bundles will be executed and in what order they will be executed. The list refers to the names of bundles (which might be parameterized function-like objects).

The order in which you execute bundles can affect the outcome of your promises. In general you should always define variables before you use them.

The bundlesequence is like a genetic makeup of a machine. The bundles act like characteristics of the systems. If you want different systems to have different bundlesequences, distinguish them with classes:

webservers::

  bundlesequence => { "main", "web" };

others::

  bundlesequence => { "main", "otherstuff" };

If you want to add a basic common sequence to all sequences, then use global variable lists to do this:

body common control
{
webservers::

  bundlesequence => { @(g.bs), "web" };

others::

  bundlesequence => { @(g.bs), "otherstuff" };

}

bundle common g
{
vars:

  "bs" slist => { "main", "basic_stuff" }; 
}

Default value:

There is no default value for bundlesequence, and the absence of a bundlesequence will cause a compilation error. A bundlesequence may also be specified using the -b or --bundlesequence command line option.


Next: , Previous: bundlesequence in common, Up: control common

5.1.2 goal_categories

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of context names that represent parent categories for goals (goal patterns)

Example:

body common control
{
goal_categories => { "goals", "targets", "milestones" };
}

Notes:

History: Was introduced in version 3.1.5, Nova 2.1 Constellation 1.0 (2011)

Goal categories are the parent classes used when searching for goals in the knowledge map. This is mostly for internal use in the Knowledge Map, but is a generic part of policy so it appears in the common body.


Next: , Previous: goal_categories in common, Up: control common

5.1.3 goal_patterns

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of regular expressions that match promisees/topics considered to be organizational goals

Example:

body common control
{
goal_patterns => { "goal_.*", "target.*" };
}

Notes:

History: Was introduced in version 3.1.5, Nova 2.1.0, Constellation 1.0 (2011)

Used as identifier to mark business and organizational goals in commercial versions of CFEngine. CFEngine uses this to match promisees that represent business goals in promises.


Next: , Previous: goal_patterns in common, Up: control common

5.1.4 ignore_missing_bundles

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: If any bundles in the bundlesequence do not exist, ignore and continue

Example:

ignore_missing_bundles => "true";

Notes:

This authorizes the bundlesequence to contain possibly existent pluggable modules. It defaults to false, whereupon undefined bundles cause a fatal error in parsing, and a transition to failsafe mode.


Next: , Previous: ignore_missing_bundles in common, Up: control common

5.1.5 ignore_missing_inputs

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: If any input files do not exist, ignore and continue

Example:

ignore_missing_inputs => "true";

Notes:

The inputs lists determines which files are parsed by CFEngine. Normally stringent security checks are made on input files to prevent abuse of the system by unauthorized users. Sometimes however, it is appropriate to consider the automatic plug-in of modules that might or might not exist. This option permits CFEngine to list possible files that might not exist and continue `best effort' with those that do exist. The default of all Booleans is false, so the normal behaviour is to signal an error if an input is not found.


Next: , Previous: ignore_missing_inputs in common, Up: control common

5.1.6 inputs

Type: slist

Allowed input range: .*

Synopsis: List of additional filenames to parse for promises

Example:

body common control
{
inputs  => {
           "update.cf",
           "library.cf"
           };
}

Notes:

The filenames specified are all assumed to be in the same directory as the file which references them (this is usually $(sys.workdir)/inputs, but may be overridden by the -f or --file command line option.

Default value:

There is no default value. If no filenames are specified, no other filenames will be included in the compilation process.


Next: , Previous: inputs in common, Up: control common

5.1.7 version

Type: string

Allowed input range: (arbitrary string)

Synopsis: Scalar version string for this configuration

Example:

body common control
{
version => "1.2.3";
}

Notes:

The version string is used in error messages and reports.

This string should not contain the colon ‘:’ character, as this has a special meaning in the context of knowledge management. This restriction might be lifted later.


Next: , Previous: version in common, Up: control common

5.1.8 lastseenexpireafter

Type: int

Allowed input range: 0,99999999999

Default value: One week

Synopsis: Number of minutes after which last-seen entries are purged

Example:

body common control
{
lastseenexpireafter => "72";
}

Notes:

Default time is one week.


Next: , Previous: lastseenexpireafter in common, Up: control common

5.1.9 output_prefix

Type: string

Allowed input range: (arbitrary string)

Synopsis: The string prefix for standard output

Example:

body common control
{
output_prefix => "my_cf3";
}

Notes:

On native Windows versions of CFEngine (Nova and above), this string is also prefixed messages in the event log.


Next: , Previous: output_prefix in common, Up: control common

5.1.10 domain

Type: string

Allowed input range: .*

Synopsis: Specify the domain name for this host

Example:

body common control
{
domain => "example.org";
}

Notes:

There is no standard, universal or reliable way of determining the DNS domain name of a host, so it can be set explicitly to simplify discovery and name-lookup.


Next: , Previous: domain in common, Up: control common

5.1.11 require_comments

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: Warn about promises that do not have comment documentation

Example:

body common control

{
common::

require_comments => "true";
}

Notes:

This may be used as a policy Quality Assurance measure, to remind policy makers to properly document their promises. When true, cf-promises will report loudly on promises that do not have comments. Variables promises are exempted from this rule, since they may be considered self-documenting.


Next: , Previous: require_comments in common, Up: control common

5.1.12 host_licenses_paid

Type: int

Allowed input range: 0,99999999999

Default value: 0

Synopsis: The number of licenses that you promise to have paid for by setting this value (legally binding for commercial license)

Example:

body common control
{
host_licenses_paid => "1000";
}

Notes:

Licensees of the commercial CFEngine releases have to make a promise in acceptance of contract terms by setting this value to the number of licenses they have paid for. This is tallied with the number of licenses granted. This declaration should be placed in all separate configuration files, e.g. failsafe.cf, promises.cf.


Next: , Previous: host_licenses_paid in common, Up: control common

5.1.13 site_classes

Type: clist

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: A list of classes that will represent geographical site locations for hosts. These should be defined elsewhere in the configuration in a classes promise.

Example:

body common control
{
site_classes => { "datacenters","datacentres"  }; # locations is by default
}

Notes:

History: Was introduced in version 3.2.0, Nova 2.1.0, Constellation 1.0.0 (2011)

This list is used to match against topics when connecting inferences about host locations in the knowledge map. Normally any CFEngine classes promise whose name is defined as a thing or topic under class locations:: will be assumed to be a location defining classifier. This list will add alternative class contexts for interpreting location.


Next: , Previous: site_classes in common, Up: control common

5.1.14 syslog_host

Type: string

Allowed input range: [a-zA-Z0-9_$(){}.:-]+

Default value: 514

Synopsis: The name or address of a host to which syslog messages should be sent directly by UDP

Example:

body common control
{
syslog_host => "syslog.example.org";
syslog_port => "514";
}

Notes:

The hostname or IP address of a local syslog service to which all CFEngine's components may promise to send data. This feature is provided in CFEngine Nova and above.


Next: , Previous: syslog_host in common, Up: control common

5.1.15 syslog_port

Type: int

Allowed input range: 0,99999999999

Synopsis: The port number of a UDP syslog service

Example:

body common control
{
syslog_host => "syslog.example.org";
syslog_port => "514";
}

Notes:

The UDP port of a local syslog service to which all CFEngine's components may promise to send data. This feature is provided in CFEngine Nova and above.


Previous: syslog_port in common, Up: control common

5.1.16 fips_mode

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: Activate full FIPS mode restrictions

Example:

body common control
{
fips_mode => "true";
}

Notes:

Appears as of Nova 2.0. If CFEngine commercial editions this value may be set to avoid the use of old deprecated algorithms that are no longer FIPS 140-2 compliant. If not set, there is some degree of compatibility with older versions and algorithms. During an upgrade, setting this parameter can cause a lot of recomputation of checksums etc. Government bodies starting with Nova 2.0 or higher should set this to ‘true’ from the start.


Next: , Previous: control common, Up: Control Promises

5.2 agent control promises


     
     body agent control
     {
     123_456_789::
     
       domain => "mydomain.com";
     
     123_456_789_111::
     
       auditing => "true";
     
     any::
     
       fullencryption => "true";
     
     }
     


Settings describing the details of the fixed behavioural promises made by cf-agent.


Next: , Previous: control agent, Up: control agent

5.2.1 abortclasses

Type: slist

Allowed input range: .*

Synopsis: A list of classes which if defined lead to termination of cf-agent

Example:

body agent control

  {
  abortclasses => { "danger.*", "should_not_continue" };
  }

Notes:

A list of class regular expressions that cf-agent will watch out for. If any matching class becomes defined, it will cause the current execution of cf-agent to be aborted. This may be used for validation, for example. To handle class expressions, simply create an alias for the expression with a single name.


Next: , Previous: abortclasses in agent, Up: control agent

5.2.2 abortbundleclasses

Type: slist

Allowed input range: .*

Synopsis: A list of classes which if defined lead to termination of current bundle

Example:

This example shows how to use the feature to validate input to a method bundle.

body common control

{
bundlesequence  => { "testbundle"  };
version => "1.2.3";
}

###########################################


body agent control

{
abortbundleclasses => { "invalid.*" };
}

###########################################


bundle agent testbundle
{
vars:

 "userlist" slist => { "xyz", "mark", "jeang", "jonhenrik", "thomas", "eben" };

methods:

 "any" usebundle => subtest("$(userlist)");

}

###########################################


bundle agent subtest(user)

{
classes:

  "invalid" not => regcmp("[a-z]{4}","$(user)");

reports:

 !invalid::

  "User name $(user) is valid at exactly 4 letters";

 # abortbundleclasses will prevent this from being evaluated

 invalid::

  "User name $(user) is invalid";
}

Notes:

A list of regular expressions for classes, or class expressions that cf-agent will watch out for. If any of these classes becomes defined, it will cause the current bundle to be aborted. This may be used for validation, for example.


Next: , Previous: abortbundleclasses in agent, Up: control agent

5.2.3 addclasses

Type: slist

Allowed input range: .*

Synopsis: A list of classes to be defined always in the current context

Example:

Add classes adds global, literal classes. The only predicates available during the control section are hard-classes.

any::

  addclasses => { "My_Organization" }

solaris::

  addclasses => { "some_solaris_alive", "running_on_sunshine" };


Notes:

Another place to make global aliases for system hardclasses. Classes here are added unqeuivocally to the system. If classes are used to predicate definition, then they must be defined in terms of global hard classes.


Next: , Previous: addclasses in agent, Up: control agent

5.2.4 agentaccess

Type: slist

Allowed input range: .*

Synopsis: A list of user names allowed to execute cf-agent

Example:

 agentaccess => { "mark", "root", "sudo" };

Notes:

A list of user names that will be allowed to attempt execution of the current configuration. This is mainly a sanity check rather than a security measure.


Next: , Previous: agentaccess in agent, Up: control agent

5.2.5 agentfacility

Type: (menu option)

Allowed input range:

               LOG_USER
               LOG_DAEMON
               LOG_LOCAL0
               LOG_LOCAL1
               LOG_LOCAL2
               LOG_LOCAL3
               LOG_LOCAL4
               LOG_LOCAL5
               LOG_LOCAL6
               LOG_LOCAL7

Default value: LOG_USER

Synopsis: The syslog facility for cf-agent

Example:

agentfacility => "LOG_USER";

Notes:

Sets the agent's syslog facility level. See the manual pages for syslog. This is ignored on Windows, as CFEngine Nova creates event logs.


Next: , Previous: agentfacility in agent, Up: control agent

5.2.6 allclassesreport

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Synopsis: Generate allclasses.txt report

Example:

body common control
{
allclassesreport => "true";
}

Notes:

This option determines whether state/allclasses.txt file is written to disk during agent execution. This functionality is retained only for CFEngine 2 compatibility as more convenient facilities exist in CFEngine 3 language to achieve similar results.

This option is turned off by default.

History: Was introduced in 3.2.0, Nova 2.1.0, Constellation 1.0.0 (2011)


Next: , Previous: allclassesreport in agent, Up: control agent

5.2.7 alwaysvalidate

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Synopsis: true/false flag to determine whether configurations will always be checked before executing, or only after updates

Example:

body agent control
{
Min00_05::

  # revalidate once per hour, regardless of change in configuration


  alwaysvalidate => "true";
}

Notes:

History: Was introduced in version 3.1.2,Nova 2.0.1 (2010)

The agents cf-agent, and cfserverd etc can run cf-promises to validate inputs before attempting to execute a configuration. As of version 3.1.2 core, this only happens if the configuration file has changed to save CPU cycles. When this attribute is set, cf-agent will force a revalidation of the input.


Next: , Previous: alwaysvalidate in agent, Up: control agent

5.2.8 auditing

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false flag to activate the cf-agent audit log

Example:

body agent control
{
auditing  => "true";
}

Notes:

If this is set, CFEngine will perform auditing on promises in the current configuration. This means that all details surrounding the verification of the current promise will be recorded in the audit database. The database may be inspected with cf-report, or cfshow in CFEngine 2.


Next: , Previous: auditing in agent, Up: control agent

5.2.9 binarypaddingchar

Type: string

Allowed input range: (arbitrary string)

Default value: space (ASC=32)

Synopsis: Character used to pad unequal replacements in binary editing

Example:

body agent control
{
binarypaddingchar => "#";
}

Notes:

When editing binary files, it can be dangerous to replace a text string with one that is longer or shorter as byte references and jumps would be destroyed. CFEngine will therefore not allow replacements that are larger in size than the original, but shorter strings can be padded out to the same length.

Default value:

The binarypaddingchar defaults to the empty string (i.e., no padding)


Next: , Previous: binarypaddingchar in agent, Up: control agent

5.2.10 bindtointerface

Type: string

Allowed input range: .*

Synopsis: Use this interface for outgoing connections

Example:

bindtointerface => "192.168.1.1";

Notes:

On multi-homed hosts, the server and client can bind to a specific interface for server traffic. The IP address of the interface must be given as the argument, not the device name.


Next: , Previous: bindtointerface in agent, Up: control agent

5.2.11 hashupdates

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false whether stored hashes are updated when change is detected in source

Example:

body agent control
{
hashupdates => "true";
}

Notes:

If ‘true’ the stored reference value is updated as soon as a warning message has been given. As most changes are benign (package updates etc) this is a common setting.


Next: , Previous: hashupdates in agent, Up: control agent

5.2.12 childlibpath

Type: string

Allowed input range: .*

Synopsis: LD_LIBRARY_PATH for child processes

Example:

body agent control
{
childlibpath => "/usr/lcoal/lib:/usr/local/gnu/lib";
}

Notes:

This string may be used to set the internal LD_LIBRARY_PATH environment of the agent.


Next: , Previous: childlibpath in agent, Up: control agent

5.2.13 checksum_alert_time

Type: int

Allowed input range: 0,60

Default value: 10 mins

Synopsis: The persistence time for the checksum_alert class

Example:

body agent control
{
checksum_alert_time => "30";
}

Notes:

When checksum changes trigger an alert, this is registered as a persistent class. This value determines the longevity of that class.


Next: , Previous: checksum_alert_time in agent, Up: control agent

5.2.14 defaultcopytype

Type: (menu option)

Allowed input range:

               mtime
               atime
               ctime
               digest
               hash
               binary

Synopsis: ctime or mtime differ

Example:

body agent control
{
#...

defaultcopytype => "digest";
}

Notes:

Sets the global default policy for comparing source and image in copy transactions.


Next: , Previous: defaultcopytype in agent, Up: control agent

5.2.15 dryrun

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: All talk and no action mode

Example:

body agent control
{
dryrun => "true";
}

Notes:

If set in the configuration, CFEngine makes no changes to a system, only reports what it needs to do.


Next: , Previous: dryrun in agent, Up: control agent

5.2.16 editbinaryfilesize

Type: int

Allowed input range: 0,99999999999

Default value: 100000

Synopsis: Integer limit on maximum binary file size to be edited

Example:

body agent control
{
edibinaryfilesize => "10M";
}

Notes:

The global setting for the file-editing safety-net for binary files (this value may be overridden on a per-promise basis with max_file_size, See edit_defaults in files. The default value for editbinaryfilesize is 100k. Note the use of special units is allowed, See Datatypes in CFEngine 3, for a list of permissible suffixes.

When setting limits, the limit on editing binary files should generally be set higher than for text files.


Next: , Previous: editbinaryfilesize in agent, Up: control agent

5.2.17 editfilesize

Type: int

Allowed input range: 0,99999999999

Default value: 100000

Synopsis: Integer limit on maximum text file size to be edited

Example:

body agent control
{
editfilesize => "120k";
}

Notes:

The global setting for the file-editing safety-net (this value may be overridden on a per-promise basis with max_file_size, See edit_defaults in files. Note the use of special units is allowed, See Datatypes in CFEngine 3, for a list of permissible suffixes.


Next: , Previous: editfilesize in agent, Up: control agent

5.2.18 environment

Type: slist

Allowed input range: [A-Za-z0-9_]+=.*

Synopsis: List of environment variables to be inherited by children

Example:

body common control
{
bundlesequence => { "one" };
}

body agent control
{
environment => { "A=123", "B=456", "PGK_PATH=/tmp"};
}

bundle agent one
{
commands:

  "/usr/bin/env";
}

Notes:

This may be used to set the runtime environment of the agent process. The values of environment variables are inherited by child commands. Some interactive programs insist on values being set, e.g.

# Required by apt-cache, debian


environment => { "LANG=C"};


Next: , Previous: environment in agent, Up: control agent

5.2.19 exclamation

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: true

Synopsis: true/false print exclamation marks during security warnings

Example:

body agent control
{
exclamation => "false";
}

Notes:

This affects only the output format of warnings.


Next: , Previous: exclamation in agent, Up: control agent

5.2.20 expireafter

Type: int

Allowed input range: 0,99999999999

Default value: 1 min

Synopsis: Global default for time before on-going promise repairs are interrupted

Example:

body action example
{
ifelapsed   => "120";	# 2 hours
expireafter => "240";	# 4 hours
}

Notes:

The locking time after which CFEngine will attempt to kill and restart its attempt to keep a promise.


Next: , Previous: expireafter in agent, Up: control agent

5.2.21 files_single_copy

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of filenames to be watched for multiple-source conflicts

Example:

body agent control
{
single_copy => { "/etc/.*", "/special/file" };
}

Notes:

This list of regular expressions will ensure that files matching the patterns of the list are never copied from more than one source during a single run of cf-agent. This may be considered a protection against accidential overlap of copies from diverse remote sources, or as a first-come-first-served disambiguation tool for lazy-evaluation of overlapping file-copy promises.


Next: , Previous: files_single_copy in agent, Up: control agent

5.2.22 files_auto_define

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of filenames to define classes if copied

Example:

body agent control
{
files_auto_define => { "/etc/syslog\.c.*", "/etc/passwd" };
}

Notes:

Classes are automatically defined by the files that are copied. The file is named according to the prefixed `canonization' of the file name. Canonization means that non-identifier characters are converted into underscores. Thus /etc/passwd would canonize to ‘_etc_passwd’. The prefix ‘auto_’ is added to clarify the origin of the class. Thus in the example the copying of /etc/passwd would lead to the class ‘auto__etc_passwd’ being defined automatically.


Next: , Previous: files_auto_define in agent, Up: control agent

5.2.23 hostnamekeys

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false label ppkeys by hostname not IP address

Example:

body server control
{
hostnamekeys => "true";
}

Notes:

Client side choice to base key associations on host names rather than IP address. This is useful for hosts with dynamic addresses.

This feature has been deprecated since 3.1.0. Host identification is now handled transparently.


Next: , Previous: hostnamekeys in agent, Up: control agent

5.2.24 ifelapsed

Type: int

Allowed input range: 0,99999999999

Default value: 1

Synopsis: Global default for time that must elapse before promise will be rechecked

Example:

#local


body action example
{
ifelapsed   => "120";	# 2 hours
expireafter => "240";	# 4 hours
}

# global


body agent control
{
ifelapsed   => "180";	# 3 hours
}

Notes:

This overrides the global settings. Promises which take a long time to verify should usually be protected with a long value for this parameter. This serves as a resource `spam' protection. A CFEngine check could easily run every 5 minutes provided resource intensive operations are not performed on every run. Using time classes like Hr12 etc., is one part of this strategy; using ifelapsed is another which is not tied to a specific time.


Next: , Previous: ifelapsed in agent, Up: control agent

5.2.25 inform

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false set inform level default

Example:

body agent control
{
inform => "true";
}

Notes:

Equivalent to (and when present, overrides) the command line option ‘-I’. Sets the default output level `permanently' within the class context indicated.

Every promiser makes an implicit default promise to use output settings declared using outputs promises.


Next: , Previous: inform in agent, Up: control agent

5.2.26 intermittency

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false store detailed recordings of last observed time for all client-server connections for reliability assessment

Example:

reports:

  "Comment"

    intermittency => "0.5";

Notes:

Report on CFEngine peers in the neighbourhood watch whose observed irregularity of connection exceeds 0.5 scaled entropy units, meaning that they show an erratic pattern of connection.


Next: , Previous: intermittency in agent, Up: control agent

5.2.27 max_children

Type: int

Allowed input range: 0,99999999999

Default value: 1 concurrent agent promise

Synopsis: Maximum number of background tasks that should be allowed concurrently

Example:

body runagent control
{
max_children => "10";
}

# or


body agent control
{
max_children => "10";
}

Notes:

For the run-agent this represents the maximum number of forked background processes allowed when parallelizing connections to servers. For the agent it represents the number of background jobs allowed concurrently. Background jobs often lead to contention of the disk resources slowing down tasks considerably; there is thus a law of diminishing returns.


Next: , Previous: max_children in agent, Up: control agent

5.2.28 maxconnections

Type: int

Allowed input range: 0,99999999999

Default value: 30 remote queries

Synopsis: Maximum number of outgoing connections to cf-serverd

Example:

# client side 


body agent control
{
maxconnections => "1000";
}

# server side


body server control
{
maxconnections => "1000";
}

Notes:

Watch out for kernel limitations for maximum numbers of open file descriptors which can limit this.


Next: , Previous: maxconnections in agent, Up: control agent

5.2.29 mountfilesystems

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false mount any filesystems promised

Example:

body agent control
{
mountfilesystems => "true";
}

Notes:

Issues the generic command to mount file systems defined in the file system table.


Next: , Previous: mountfilesystems in agent, Up: control agent

5.2.30 nonalphanumfiles

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false warn about filenames with no alphanumeric content

Example:

body agent control
{
nonalphanumfiles => "true";
}

Notes:

This test is applied in all recursive/depth searches.


Next: , Previous: nonalphanumfiles in agent, Up: control agent

5.2.31 repchar

Type: string

Allowed input range: .

Default value: _

Synopsis: The character used to canonize pathnames in the file repository

Example:

body agent control
{
repchar => "_";
}

Notes:


Next: , Previous: repchar in agent, Up: control agent

5.2.32 refresh_processes

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: Reload the process table before verifying the bundles named in this list (lazy evaluation)

Example:

body agent control
{
refresh_processes => { "mybundle" };
#refresh_processes => { "none" };

}

Notes:

History: Was introduced in version 3.1.3,Nova 2.0.2 (2010)

If this list of regular expressions is non-null and an existing bundle is mentioned or matched in this list, CFEngine will reload the process table at the start of the named bundle, each time is is scheduled. If the list is null, the process list will be reloaded at the start of every scheduled bundle.

In the example above we use a non-empty list with the name `none'. This is not a reserved word, but as long as there are no bundles with the name `none' this has the effect of never reloading the process table. This keeps improves the efficiency of the agent.


Next: , Previous: refresh_processes in agent, Up: control agent

5.2.33 default_repository

Type: string

Allowed input range: "?(/.*)

Default value: in situ

Synopsis: Path to the default file repository

Example:

body agent control
{
default_repository => "/var/cfengine/repository";
}

Notes:

If defined the default repository is the location where versions of files altered by CFEngine are stored. This should be understood in relation to the policy for ‘backup’ in copying, editing etc. If the backups are time-stamped, this becomes effective a version control repository. See also repository for a way to locally override the global repository.

Note that when a repository is specified, the files are stored using the canonified directory name of the original file, concatenated with the name of the file. So, for example, /usr/local/etc/postfix.conf would ordinarily be stored in an alternative repository as _usr_local_etc_postfix.conf.cfsaved.


Next: , Previous: default_repository in agent, Up: control agent

5.2.34 secureinput

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false check whether input files are writable by unauthorized users

Example:

body agent control
{
secureinput => "true";
}

Notes:

If this is set, the agent will not accept an input file that is not owned by a privileged user.


Next: , Previous: secureinput in agent, Up: control agent

5.2.35 sensiblecount

Type: int

Allowed input range: 0,99999999999

Default value: 2 files

Synopsis: Minimum number of files a mounted filesystem is expected to have

Example:

body agent control
{
sensiblecount => "20";
}

Notes:


Next: , Previous: sensiblecount in agent, Up: control agent

5.2.36 sensiblesize

Type: int

Allowed input range: 0,99999999999

Default value: 1000 bytes

Synopsis: Minimum number of bytes a mounted filesystem is expected to have

Example:

body agent control
{
sensiblesize => "20K";
}

Notes:


Next: , Previous: sensiblesize in agent, Up: control agent

5.2.37 skipidentify

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: Do not send IP/name during server connection because address resolution is broken

Example:

body agent control
{
skipidentify => "true";
}

Notes:

Hosts that are not registered in DNS cannot supply reasonable credentials for a secondary confirmation of their identity to a CFEngine server. This causes the agent to ignore its missing DNS credentials.


Next: , Previous: skipidentify in agent, Up: control agent

5.2.38 suspiciousnames

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of names to warn about if found during any file search

Example:

body agent control
{
suspiciousnames => { ".mo", "lrk3", "rootkit" };
}

Notes:

If CFEngine sees these names during recursive (depth) file searches it will warn about them.


Next: , Previous: suspiciousnames in agent, Up: control agent

5.2.39 syslog

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false switches on output to syslog at the inform level

Example:

body agent control
{
syslog => "true";
}

Notes:


Next: , Previous: syslog in agent, Up: control agent

5.2.40 track_value

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false switches on tracking of promise valuation

Example:

body agent control
{
track_value => "true";
}

Notes:

If this is true, CFEngine generates a log in WORKDIR/state/cf_value.log of the estmated `business value' of the system automation as a running log, value_kept, etc. The format of the file is

date,sum value kept,sum value repaired,sum value notkept


Next: , Previous: track_value in agent, Up: control agent

5.2.41 timezone

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of allowed timezones this machine must comply with

Example:

body agent control
{
timezone => { "MET", "CET", "GMT+1" };
}

Notes:


Next: , Previous: timezone in agent, Up: control agent

5.2.42 default_timeout

Type: int

Allowed input range: 0,99999999999

Default value: 10 seconds

Synopsis: Maximum time a network connection should attempt to connect

Example:

body agent control
{
default_timeout => "10";
}

Notes:

The time is in seconds. It is not a guaranteed number, since it depends on system behaviour. under Linux, the kernel version plays a role, since not all system calls seem to respect the signals.


Previous: default_timeout in agent, Up: control agent

5.2.43 verbose

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false switches on verbose standard output

Example:

body agent control
{
verbose => "true";
}

Notes:

Equivalent to (and when present, overrides) the command line option ‘-v’. Sets the default output level `permanently' for this promise.

Every promiser makes an implicit default promise to use output settings declared using outputs promises.


Next: , Previous: control agent, Up: Control Promises

5.3 server control promises


     
     body server control
     
     {
     allowconnects         => { "127.0.0.1" , "::1" ,  ".*\.example\.org" };
     allowallconnects      => { "127.0.0.1" , "::1" ,  ".*\.example\.org" };
     
     # Uncomment me under controlled circumstances
     #trustkeysfrom         => { "127.0.0.1" , "::1" ,  ".*\.example\.org" };
     }
     


Settings describing the details of the fixed behavioural promises made by cf-serverd. Server controls are mainly about determining access policy for the connection protocol: i.e. access to the server itself. Access to specific files must be granted in addition.


Next: , Previous: control server, Up: control server

5.3.1 allowallconnects

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs or hostnames that may have more than one connection to the server port

Example:

allowallconnects      => { 
                         "127.0.0.1", 
                         "::1", 
                         "200\.1\.10\..*", 
                         "host\.domain\.tld", 
                         "host[0-9]+\.domain\.com" 
                         };

Notes:

This list of regular expressions matches hosts that are allowed to connect an umlimited number of times up to the maximum connection limit. Without this, a host may only connect once (which is a very strong constraint, as the host must wait for the TCP FIN_WAIT to expire before reconnection can be attempted).

In CFEngine 2 this corresponds to AllowMultipleConnectionsFrom.

Note that 127.0.0.1 is a regular expression (i.e., “127 any character 0 any character 0 any character 1”), but this will only match the IP address 127.0.0.1. Take care with IP addresses and domain names, as the hostname regular expression www.domain.com will potentially match more than one hostname (e.g., wwwxdomain.com, in addition to the desired hostname www.domain.com).


Next: , Previous: allowallconnects in server, Up: control server

5.3.2 allowconnects

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs or hostnames that may connect to the server port

Example:

allowconnects         => { 
                         "127.0.0.1", 
                         "::1", 
                         "200\.1\.10\..*", 
                         "host\.domain\.tld", 
                         "host[0-9]+\.domain\.com" 
                         };

Notes:

If a client's identity matches an entry in this list it is granted to permission to send data to the server port. Clients who are not in this list may not connect or send data to the server.

See also the warning about regular expressions in allowallconnects.


Next: , Previous: allowconnects in server, Up: control server

5.3.3 allowusers

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of usernames who may execute requests from this server

Example:

allowusers => { "cfengine", "root" };

Notes:

The usernames listed in this list are those asserted as public key identities during client-server connections. These may or may not correspond to system identities on the server-side system.


Next: , Previous: allowusers in server, Up: control server

5.3.4 auditing

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false activate auditing of server connections

Example:

body agent control
{
auditing  => "true";
}

Notes:

If this is set, CFEngine will perform auditing on promises in the current configuration. This means that all details surrounding the verification of the current promise will be recorded in the audit database. The database may be inspected with cf-report, or cfshow in CFEngine 2.


Next: , Previous: auditing in server, Up: control server

5.3.5 bindtointerface

Type: string

Allowed input range: (arbitrary string)

Synopsis: IP of the interface to which the server should bind on multi-homed hosts

Example:

bindtointerface => "192.168.1.1";

Notes:

On multi-homed hosts, the server and client can bind to a specific interface for server traffic. The IP address of the interface must be given as the argument, not the device name.


Next: , Previous: bindtointerface in server, Up: control server

5.3.6 cfruncommand

Type: string

Allowed input range: "?(/.*)

Synopsis: Path to the cf-agent command or cf-execd wrapper for remote execution

Example:

body server control

{
cfruncommand => "/var/cfengine/bin/cf-agent";
}


Notes:

It is normal for this to point to the location of cf-agent but it could also point to the cf-execd, or even another program or shell command at your own risk.


Next: , Previous: cfruncommand in server, Up: control server

5.3.7 denybadclocks

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: true

Synopsis: true/false accept connections from hosts with clocks that are out of sync

Example:

body server control
{
#..

denybadclocks => "true";
}

Notes:

A possible form of attack on the fileserver is to request files based on time by setting the clocks incorrectly. This option prevents connections from clients whose clocks are drifting too far from the server clock (where "too far" is currently defined as "more than an hour off"). This serves as a warning about clock asynchronization and also a protection against Denial of Service attempts based on clock corruption.


Next: , Previous: denybadclocks in server, Up: control server

5.3.8 denyconnects

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs or hostnames that may NOT connect to the server port

Example:

body server control
{
denyconnects => { "badhost\.domain\.evil", "host3\.domain\.com" };
}

Notes:

Hosts or IP addresses that are explicitly denied access. This should only be used in special circumstances. One should never grant generic access to everything and then deny special cases. Since the default server behaviour is to grant no access to anything, this list is unnecessary unless you have already granted access to some set of hosts using a generic pattern, to which you intend to make an exception.

See also the warning about regular expressions in allowallconnects.


Next: , Previous: denyconnects in server, Up: control server

5.3.9 dynamicaddresses

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs or hostnames for which the IP/name binding is expected to change

Example:

body server control
{
dynamicaddresses => { "dhcp_.*" };
}

Notes:

The addresses or hostnames here are expected to have non-permanent address-name bindings, we must therefor work harder to determine whether hosts credentials are trusted by looking for existing public keys in files that do not match the current hostname or IP.

This feature has been deprecated since 3.1.0. This is now handled transparently.


Next: , Previous: dynamicaddresses in server, Up: control server

5.3.10 hostnamekeys

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false store keys using hostname lookup instead of IP addresses

Example:

body server control
{
hostnamekeys => "true";
}

Notes:

Client side choice to base key associations on host names rather than IP address. This is useful for hosts with dynamic addresses.

This feature has been deprecated since 3.1.0. Host identification is now handled transparently.


Next: , Previous: hostnamekeys in server, Up: control server

5.3.11 keycacheTTL

Type: int

Allowed input range: 0,99999999999

Default value: 24

Synopsis: Maximum number of hours to hold public keys in the cache

Example:

History: Was introduced in version 3.1.0b1,Nova 2.0.0b1 (2010)

body server control
{
keycacheTTL => "24";
}

Notes:

History: Was introduced in version 3.1.0b1,Nova 2.0.0b1 (2010)


Next: , Previous: keycacheTTL in server, Up: control server

5.3.12 logallconnections

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false causes the server to log all new connections to syslog

Example:

body server control
{
logallconnections => "true";
}

Notes:

If set, the server will record connection attempts in syslog.


Next: , Previous: logallconnections in server, Up: control server

5.3.13 logencryptedtransfers

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false log all successful transfers required to be encrypted

Example:

body server control
{
logencryptedtransfers => "true";
}

Notes:

If true the server will log all transfers of files which the server requires to encrypted in order to grant access (see ifencrypted) to syslog. These files are deemed to be particularly sensitive.


Next: , Previous: logencryptedtransfers in server, Up: control server

5.3.14 maxconnections

Type: int

Allowed input range: 0,99999999999

Default value: 30 remote queries

Synopsis: Maximum number of connections that will be accepted by cf-serverd

Example:

# client side 


body agent control
{
maxconnections => "1000";
}

# server side


body server control
{
maxconnections => "1000";
}

Notes:

Watch out for kernel limitations for maximum numbers of open file descriptors which can limit this.


Next: , Previous: maxconnections in server, Up: control server

5.3.15 port

Type: int

Allowed input range: 1024,99999

Default value: 5308

Synopsis: Default port for cfengine server

Example:

body hub control
{
port => "5308";
}

body server control
{
specialhost::
 port => "5308";

!specialhost::
 port => "5308";
}

Notes:

The standard or registered port number is tcp/5308. CFEngine does not presently use its registered udp port with the same number, but this could change in the future.

Changing the standard port number is not recommended practice. You should not do it without a good reason.


Next: , Previous: port in server, Up: control server

5.3.16 serverfacility

Type: (menu option)

Allowed input range:

               LOG_USER
               LOG_DAEMON
               LOG_LOCAL0
               LOG_LOCAL1
               LOG_LOCAL2
               LOG_LOCAL3
               LOG_LOCAL4
               LOG_LOCAL5
               LOG_LOCAL6
               LOG_LOCAL7

Default value: LOG_USER

Synopsis: Menu option for syslog facility level

Example:

body server control
{
serverfacility => "LOG_USER";
}

Notes:

See syslog notes.


Next: , Previous: serverfacility in server, Up: control server

5.3.17 skipverify

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs or hostnames for which we expect no DNS binding and cannot verify

Example:

body server control
{
skipverify => { "special_host.*", "192.168\..*" };
}

Notes:

Server side decision to ignore requirements of DNS identity confirmation.

See also the warning about regular expressions in allowallconnects.


Previous: skipverify in server, Up: control server

5.3.18 trustkeysfrom

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of IPs from whom we accept public keys on trust

Example:

body server control
{
trustkeysfrom => { "10\.0\.1\.1", "192\.168\..*"};
}

Notes:

If connecting clients' public keys have not already been trusted, this allows us to say `yes' to accepting the keys on trust. Normally this should be an empty list except in controlled circumstances.

See also the warning about regular expressions in allowallconnects.


Next: , Previous: control server, Up: Control Promises

5.4 monitor control promises


     
     body monitor control()
        {
        #version => "1.2.3.4";
     
        threshold => "0.3";
        forgetrate => "0.7";
        tcpdump => "false";
        tcpdumpcommand => "/usr/sbin/tcpdump -i eth1 -n -t -v";
     
        }
     


Settings describing the details of the fixed behavioural promises made by cf-monitord. The system defaults will be sufficient for most users. This configurability potential, however, will be a key to developing the integrated monitoring capabilities of CFEngine.


Next: , Previous: control monitor, Up: control monitor

5.4.1 forgetrate

Type: real

Allowed input range: 0,1

Default value: 0.6

Synopsis: Decimal fraction [0,1] weighting of new values over old in 2d-average computation

Example:

body monitor control
{
threshold => "0.3";
forgetrate => "0.7";
}

Notes:

Configurable settings for the machine-learning algorithm that tracks system behaviour. This is only for expert users. This parameter effectively determines (together with the monitoring rate) how quickly CFEngine forgets its previous history.


Next: , Previous: forgetrate in monitor, Up: control monitor

5.4.2 monitorfacility

Type: (menu option)

Allowed input range:

               LOG_USER
               LOG_DAEMON
               LOG_LOCAL0
               LOG_LOCAL1
               LOG_LOCAL2
               LOG_LOCAL3
               LOG_LOCAL4
               LOG_LOCAL5
               LOG_LOCAL6
               LOG_LOCAL7

Default value: LOG_USER

Synopsis: Menu option for syslog facility

Example:

body monitor control
{
monitorfacility => "LOG_USER";
}

Notes:

See notes for syslog.


Next: , Previous: monitorfacility in monitor, Up: control monitor

5.4.3 histograms

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: true

Synopsis: Ignored, kept for backward compatibility

Example:

body monitor control
{
histograms => "true";
}

Notes:

cf-monitord now always keeps histograms information, so this option is a no-op kept for backward compatibility. It used to cause CFEngine to learn the conformally transformed distributions of fluctuations about the mean.


Next: , Previous: histograms in monitor, Up: control monitor

5.4.4 tcpdump

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false use tcpdump if found

Example:

body monitor control
{
tcpdump => "true";
}

Notes:

Interface with TCP stream if possible.


Previous: tcpdump in monitor, Up: control monitor

5.4.5 tcpdumpcommand

Type: string

Allowed input range: "?(/.*)

Synopsis: Path to the tcpdump command on this system

Example:

body monitor control
{
tcpdumpcommand => "/usr/sbin/tcpdump -i eth1";
}

Notes:

If this is defined, the monitor will try to interface with the TCP stream and monitor generic package categories for anomalies.


Next: , Previous: control monitor, Up: Control Promises

5.5 runagent control promises


     
     body runagent control
     {
     # default port is 5308
     
     hosts => { "127.0.0.1:5308", "eternity.iu.hio.no:80", "slogans.iu.hio.no" };
     
     #output_to_file => "true";
     }
     


Settings describing the details of the fixed behavioural promises made by cf-runagent. The most important parameter here is the list of hosts that the agent will poll for connections. This is easily read in from a file list, however when doing so always have a stable input source that does not depend on the network (including a database or directory service) in any way: introducing such dependencies makes configuration brittle.


Next: , Previous: control runagent, Up: control runagent

5.5.1 hosts

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of host or IP addresses to attempt connection with

Example:

body runagent control
{
network1::
  hosts => { "host1.example.org", "host2", "host3" };

network2::
  hosts => { "host1.example.com", "host2", "host3" };
}

Notes:

The complete list of contactable hosts. The values may be either numerical IP addresses or DNS names, optionally suffixed by a ‘:’ and a port number. If no port number is given, the default CFEngine port 5308 is assumed.


Next: , Previous: hosts in runagent, Up: control runagent

5.5.2 port

Type: int

Allowed input range: 1024,99999

Default value: 5308

Synopsis: Default port for cfengine server

Example:

body hub control
{
port => "5308";
}

body server control
{
specialhost::
 port => "5308";

!specialhost::
 port => "5308";
}

Notes:

The standard or registered port number is tcp/5308. CFEngine does not presently use its registered udp port with the same number, but this could change in the future.

Changing the standard port number is not recommended practice. You should not do it without a good reason.


Next: , Previous: port in runagent, Up: control runagent

5.5.3 force_ipv4

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false force use of ipv4 in connection

Example:

body copy_from example
{
force_ipv4 => "true";
}

Notes:

IPv6 should be harmless to most users unless you have a partially or misconfigured setup.


Next: , Previous: force_ipv4 in runagent, Up: control runagent

5.5.4 trustkey

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false automatically accept all keys on trust from servers

Example:

body copy_from example
{
trustkey => "true";
}

Notes:

If the server's public key has not already been trusted, this allows us to accept the key in automated key-exchange.

Note that, as a simple security precaution, trustkey should normally be set to ‘false’, to avoid key exchange with a server one is not one hundred percent sure about, though the risks for a client are rather low. On the server-side however, trust is often granted to many clients or to a whole network in which possibly unauthorized parties might be able to obtain an IP address, thus the trust issue is most important on the server side.

As soon as a public key has been exchanged, the trust option has no effect. A machine that has been trusted remains trusted until its key is manually revoked by a system administrator. Keys are stored in WORKDIR/ppkeys.


Next: , Previous: trustkey in runagent, Up: control runagent

5.5.5 encrypt

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false encrypt connections with servers

Example:

body copy_from example
{
servers  => { "remote-host.example.org" };
encrypt => "true";
}

Notes:

Client connections are encrypted with using a Blowfish randomly generated session key. The intial connection is encrypted using the public/private keys for the client and server hosts.


Next: , Previous: encrypt in runagent, Up: control runagent

5.5.6 background_children

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false parallelize connections to servers

Example:

body runagent control
{
background_children => "true";
}

Notes:

Causes the runagent to attempt parallelized connections to the servers.


Next: , Previous: background_children in runagent, Up: control runagent

5.5.7 max_children

Type: int

Allowed input range: 0,99999999999

Default value: 50 runagents

Synopsis: Maximum number of simultaneous connections to attempt

Example:

body runagent control
{
max_children => "10";
}

# or


body agent control
{
max_children => "10";
}

Notes:

For the run-agent this represents the maximum number of forked background processes allowed when parallelizing connections to servers. For the agent it represents the number of background jobs allowed concurrently. Background jobs often lead to contention of the disk resources slowing down tasks considerably; there is thus a law of diminishing returns.


Next: , Previous: max_children in runagent, Up: control runagent

5.5.8 output_to_file

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false whether to send collected output to file(s)

Example:

body runagent control
{
output_to_file => "true";
}

Notes:

Filenames are chosen automatically and placed in the WORKDIR/outputs/hostname_runagent.out.


Next: , Previous: output_to_file in runagent, Up: control runagent

5.5.9 output_directory

Type: string

Allowed input range: "?(/.*)

Synopsis: Directory where the output is stored

Example:

body runagent control
{
output_directory => "/tmp/run_output";
}

Notes:

History: Was introduced in version 3.2.0, Nova 2.1.0, Constellation 1.0.0 (2011)

Defines the location for parallelized output to be saved when running cf-runagent in parallel mode.


Previous: output_directory in runagent, Up: control runagent

5.5.10 timeout

Type: int

Allowed input range: 1,9999

Synopsis: Connection timeout, sec

Example:

body agent control
{
timeout => "10";
}

Notes:

Timeout in seconds.


Next: , Previous: control runagent, Up: Control Promises

5.6 executor control promises


     
     body executor control
     
     {
     splaytime  => "5";
     mailto     => "cfengine@example.org";
     mailfrom   => "cfengine@$(host).example.org";
     smtpserver => "localhost";
     schedule   => { "Min00_05", "Min30_35" }
     }
     


These body settings determine the behaviour of cf-execd, including scheduling times and output capture to WORKDIR/outputs and relay via email. Note that the splaytime and schedule parameters are now coded here rather than (as previously) in the agent.


Next: , Previous: control executor, Up: control executor

5.6.1 splaytime

Type: int

Allowed input range: 0,99999999999

Default value: 0

Synopsis: Time in minutes to splay this host based on its name hash

Example:

body executor control
{
splaytime => "2";
}

Notes:

Whenever any class listed in the schedule attribute is present, cf-execd can schedule an execution of cf-agent. The actual execution will be delayed an integer number of seconds between 0-splaytime minutes. The specific amount of delay for “this” host is based on a hash of the hostname. Thus a collection of hosts will all execute at different times, and surges in network traffic can be avoided.

A rough rule of thumb for scaling of small updates is set the splay time between 1-5 minutes for up a few thousand hosts. The splaytime should not be set to a value larger than the cf-execd scheduling interval, else multiple clients might contend for data.

Default value:

The default value is 0 minutes.

See also: The splayclass() function for a task-specific means for setting splay times.


Next: , Previous: splaytime in executor, Up: control executor

5.6.2 mailfrom

Type: string

Allowed input range: .*@.*

Synopsis: Email-address cfengine mail appears to come from

Example:

body executor control
{
mailfrom => "mrcfengine@example.org";
}

Notes:


Next: , Previous: mailfrom in executor, Up: control executor

5.6.3 mailto

Type: string

Allowed input range: .*@.*

Synopsis: Email-address cfengine mail is sent to

Example:

body executor control
{
mailto => "cfengine_alias@example.org";
}

Notes:

The address to whom email is sent if an smtp host is configured.


Next: , Previous: mailto in executor, Up: control executor

5.6.4 smtpserver

Type: string

Allowed input range: .*

Synopsis: Name or IP of a willing smtp server for sending email

Example:

body executor control
{
smtpserver => "smtp.example.org";
}

Notes:

This should point to a standard port 25 server without encyption. If you are running secured or encrypted email then you should run a mail relay on localhost and point this to localhost.


Next: , Previous: smtpserver in executor, Up: control executor

5.6.5 mailmaxlines

Type: int

Allowed input range: 0,1000

Default value: 30

Synopsis: Maximum number of lines of output to send by email

Example:

body executor control
{
mailmaxlines => "100";
}

Notes:

This limit prevents anomalously large outputs from clogging up a system administrator's mailbox. The output is truncated in the email report, but the complete original transcript is stored in WORKDIR/outputs/* where it can be viewed on demand. A reference to the appropriate file is given.


Next: , Previous: mailmaxlines in executor, Up: control executor

5.6.6 schedule

Type: slist

Allowed input range: (arbitrary string)

Synopsis: The class schedule used by cf-execd for activating cf-agent

Example:

body executor control
{
schedule => { "Min00", "(Evening|Night).Min15_20", "Min30", "(Evening|Night).Min45_50" };
}

Notes:

The list should contain class expressions comprised of classes which are visible to the cf-execd daemon. In principle, any defined class expression will cause the daemon to wake up and schedule the execution of the cf-agent. In practice, the classes listed in the list are usually date- and time-based.

The actual execution of cf-agent may be delayed by splaytime, and may be deferred by promise caching and the value of ifelapsed. Note also that the effectiveness of the splayclass function may be affected by changing the schedule.

Default value:

schedule => { "Min00", "Min05", "Min10", "Min15", "Min20", "Min25",
	      "Min30", "Min35", "Min40", "Min45", "Min50", "Min55" };


Next: , Previous: schedule in executor, Up: control executor

5.6.7 executorfacility

Type: (menu option)

Allowed input range:

               LOG_USER
               LOG_DAEMON
               LOG_LOCAL0
               LOG_LOCAL1
               LOG_LOCAL2
               LOG_LOCAL3
               LOG_LOCAL4
               LOG_LOCAL5
               LOG_LOCAL6
               LOG_LOCAL7

Default value: LOG_USER

Synopsis: Menu option for syslog facility level

Example:

body executor control
{
executorfacility => "LOG_USER";
}

Notes:

See the syslog manual pages.


Previous: executorfacility in executor, Up: control executor

5.6.8 exec_command

Type: string

Allowed input range: "?(/.*)

Synopsis: The full path and command to the executable run by default (overriding builtin)

Example:

exec_command => "$(sys.workdir)/bin/cf-agent -f failsafe.cf && $(sys.workdir)/bin/cf-agent";

Notes:

The command is run in a shell encapsulation so pipes and shell symbols may be used if desired. Unlike, CFEngine 2, CFEngine 3 does not automatically run a separate update sequence before its normal run. This can be handled using the approach in the example above.


Next: , Previous: control executor, Up: Control Promises

5.7 knowledge control promises


     
     body knowledge control
     
     {
     query_output    => "html";
     goal_categories => { "goals", "targets", "milestones" };
     goal_patterns   => { "goal_.*", "target.*" };
     }
     


Settings describing the details of the fixed behavioural promises made by cf-know. These parameters control the way in which knowledge data are stored and retrieved from a relational database and the output format of the queries.


Next: , Previous: control knowledge, Up: control knowledge

5.7.1 build_directory

Type: string

Allowed input range: .*

Default value: Current working directory

Synopsis: The directory in which to generate output files

Example:

body knowledge control

{
#..

build_directory => "/tmp/builddir";
}

body reporter control

{
#..

build_directory => "/tmp/builddir";
}

Notes:

The directory where all auto-generated textual output is placed by cf-report. This includes manual generation, ontology and topic map data.


Next: , Previous: build_directory in knowledge, Up: control knowledge

5.7.2 document_root

Type: string

Allowed input range: .*

Synopsis: The directory in which the web root resides

Example:

body knowledge control

{
document_root => "/srv/www/htdocs";
}

Notes:

The local file path of the system's web document root.


Next: , Previous: document_root in knowledge, Up: control knowledge

5.7.3 generate_manual

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false generate texinfo manual page skeleton for this version

Example:

body knowledge control
{
generate_manual => "true";
}

Notes:

Auto-creates a manual based on the self-documented code. As the promise syntax is extended the manual self-heals. The resulting manual is generated in Texinfo format, from which all other formats can be generated.


Next: , Previous: generate_manual in knowledge, Up: control knowledge

5.7.4 graph_directory

Type: string

Allowed input range: "?(/.*)

Synopsis: Path to directory where rendered .png files will be created

Example:

body knowledge control
{
graph_directory => "/tmp/output";
}

Notes:

A separate location where the potentially large number of .png visualizations of a knowledge representation are pre-compiled. This feature only works if the necessary graphics libraries are present.


Next: , Previous: graph_directory in knowledge, Up: control knowledge

5.7.5 graph_output

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Synopsis: true/false generate png visualization of topic map if possible (requires lib)

Example:

body knowledge control

{
# fix/override -g option

graph_output => "true"; 
}

Notes:

Equivalent to the use of the ‘-g’ option for cf-know.


Next: , Previous: graph_output in knowledge, Up: control knowledge

5.7.6 html_banner

Type: string

Allowed input range: (arbitrary string)

Synopsis: HTML code for a banner to be added to rendered in html after the header

Example:

body knowledge control
{
html_banner => "<img src=\"http://www.example.org/img/banner.png\">";
}

body reporter control
{
html_banner => "<img src=\"http://www.example.org/img/banner.png\">";
}

Notes:

This content is cited when generating HTML output from the knowledge agent.


Next: , Previous: html_banner in knowledge, Up: control knowledge

5.7.7 html_footer

Type: string

Allowed input range: (arbitrary string)

Synopsis: HTML code for a page footer to be added to rendered in html before the end body tag

Example:

body reporter control
{
html_footer => "
               <div id=\"footer\">Bottom of the page</div>
               ";
}

body knowledge control
{
html_footer => "
               <div id=\"footer\">Bottom of the page</div>
               ";
}

Notes:

This allows us to cite HTML code for formatting reports generated by the reporting and knowledge agents.


Next: , Previous: html_footer in knowledge, Up: control knowledge

5.7.8 id_prefix

Type: string

Allowed input range: .*

Synopsis: The LTM identifier prefix used to label topic maps (used for disambiguation in merging)

Example:

body knowledge control
{
id_prefix => "unique_prefix";
}

Notes:

Use to disambiguate indentifiers for a successful merging of topic maps, especially in Linear Topic Map (LTM) format using third party tools such as Ontopia's Omnigator.


Next: , Previous: id_prefix in knowledge, Up: control knowledge

5.7.9 manual_source_directory

Type: string

Allowed input range: "?(/.*)

Synopsis: Path to directory where raw text about manual topics is found (defaults to build_directory)

Example:

body knowledge control
{
manual_source => "/path/cfengine_manual_commentary";
}

Notes:

This is used in the self-healing documentation. The directory points to a location where the Texinfo sources for per-section commentary is maintained.


Next: , Previous: manual_source_directory in knowledge, Up: control knowledge

5.7.10 query_engine

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name of a dynamic web-page used to accept and drive queries in a browser

Example:

body knowledge control
{
query_engine => "http://www.example.org/script.php";
}

body reporter control
{
query_engine => "http://www.example.org/script.pl";
}

Notes:

When displaying topic maps in HTML format, cf-know will render each topic as a link to this URL with the new topic as an argument. Thus it is possible to make a dynamic web query by embedding CFEngine in the web page as system call and passing the argument to it.


Next: , Previous: query_engine in knowledge, Up: control knowledge

5.7.11 query_output

Type: (menu option)

Allowed input range:

               html
               text

Synopsis: Menu option for generated output format

Example:

body knowledge control
{
query_output => "html";
}

Notes:


Next: , Previous: query_output in knowledge, Up: control knowledge

5.7.12 sql_type

Type: (menu option)

Allowed input range:

               mysql
               postgres

Synopsis: Menu option for supported database type

Example:

body knowledge control
{
sql_type => "mysql";
}

Notes:


Next: , Previous: sql_type in knowledge, Up: control knowledge

5.7.13 sql_database

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name of database used for the topic map

Example:

body knowledge control
{
sql_database => "cfengine_knowledge_db";
}

Notes:

The name of an SQL database for caching knowledge.


Next: , Previous: sql_database in knowledge, Up: control knowledge

5.7.14 sql_owner

Type: string

Allowed input range: (arbitrary string)

Synopsis: User id of sql database user

Example:

body knowledge control
{
sql_owner => "db_owner";
}

Notes:

Part of the credentials for opening the database. This depends on the type of database.


Next: , Previous: sql_owner in knowledge, Up: control knowledge

5.7.15 sql_passwd

Type: string

Allowed input range: (arbitrary string)

Synopsis: Embedded password for accessing sql database

Example:

body knowledge control
{
sql_passwd => "";
}

Notes:

Part of the credentials for connecting to the database server. This is system dependent. If the server host is localhost a password might not be required.


Next: , Previous: sql_passwd in knowledge, Up: control knowledge

5.7.16 sql_server

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name or IP of database server (or localhost)

Example:

body knowledge control
{
sql_server => "localhost";
}

Notes:

The host name of IP address of the server. The default is to look on the localhost.


Next: , Previous: sql_server in knowledge, Up: control knowledge

5.7.17 sql_connection_db

Type: string

Allowed input range: (arbitrary string)

Synopsis: The name of an existing database to connect to in order to create/manage other databases

Example:

body knowledge control
{
sql_connection_db => "mysql";
}

Notes:

In order to create a database on a database server (all of which practice voluntary cooperation), one has to be able to connect to the server, however, without an existing database this is not allowed. Thus, database servers provide a default database that can be connected to in order to thereafter create new databases. These are called postgres and mysql for their respective database servers.

For the knowledge agent, this setting is made in the control body, for database verification promises, it is made in the database_server body.


Next: , Previous: sql_connection_db in knowledge, Up: control knowledge

5.7.18 style_sheet

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name of a style-sheet to be used in rendering html output (added to headers)

Example:

body knowledge control
{
style_sheet => "http://www.example.org/css/sheet.css";
}

body reporter control
{
style_sheet => "http://www.example.org/css/sheet.css";
}

Notes:

For formatting the HTML generated output of cf-know.


Previous: style_sheet in knowledge, Up: control knowledge

5.7.19 view_projections

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: Perform view-projection analytics in graph generation

Example:

body knowledge control
{
view_projections => "true";
}

Notes:

If this is set to true, CFEngine Nova computes additional graphical representations in its knowledge map, representing causal dependencies between CFEngine promises.


Next: , Previous: control knowledge, Up: Control Promises

5.8 reporter control promises


body reporter control
{
reports => { "performance", "last_seen", "monitor_history" };
build_directory => "/tmp/nerves";
report_output => "html";
}


Determines a list of reports to write into the build directory. The format may be in text, html or xml format. The reporter agent cf-report replaces both cfshow and cfenvgraph. It no longer produces output to the console.

Some reports are only available in enterprise level versions of CFEngine.


Next: , Previous: control reporter, Up: control reporter

5.8.1 aggregation_point

Type: string

Allowed input range: "?(/.*)

Synopsis: The root directory of the data cache for CMDB aggregation

Example:

body reporter control
{
aggregation_point => "/srv/www/htdocs/reports";
}

Notes:

This feature is only used in enterprise level versions of CFEngine. It specifies the directory where reports from multiple hosts are to be aggregated in sub-directories. This should be somewhere under the document root of the web server for the CFEngine knowledge base in order to make the reports browsable.


Next: , Previous: aggregation_point in reporter, Up: control reporter

5.8.2 auto_scaling

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: true

Synopsis: true/false whether to auto-scale graph output to optimize use of space

Example:

body reporter control
{
auto_scaling => "true";
}

Notes:

Automatic scaling is the default.


Next: , Previous: auto_scaling in reporter, Up: control reporter

5.8.3 build_directory

Type: string

Allowed input range: .*

Default value: Current working directory

Synopsis: The directory in which to generate output files

Example:

body knowledge control

{
#..

build_directory => "/tmp/builddir";
}

body reporter control

{
#..

build_directory => "/tmp/builddir";
}

Notes:

The directory where all auto-generated textual output is placed by cf-report. This includes manual generation, ontology and topic map data.


Next: , Previous: build_directory in reporter, Up: control reporter

5.8.4 csv2xml

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of csv formatted files in the build directory to convert to simple xml

Example:

body reporter control
{
csv2xml => { "myreport.csv", "custom_report.csv"  };
}

Notes:

CSV files are easy to generate in CFEngine from individual promise logging functions. XML is not easily generated due to its hierarchical structure. This function allows cf-report to convert a CSV file into pidgin XML for convenience. The schema has the general form:

<output>
 <line> <one>...</one> <two>...</two> ... </line>
 <line> <one>...</one> <two>...</two> ... </line>
</output>


Next: , Previous: csv2xml in reporter, Up: control reporter

5.8.5 error_bars

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: true

Synopsis: true/false whether to generate error bars on graph output

Example:

body reporter control
{
error_bars => "true";
}

Notes:

The default is to produce error bars. Without error bars from CFEngine's machine learning data there is no way to assess the significance of an observation about the system, i.e. whether it is normal or anomalous.


Next: , Previous: error_bars in reporter, Up: control reporter

5.8.6 html_banner

Type: string

Allowed input range: (arbitrary string)

Synopsis: HTML code for a banner to be added to rendered in html after the header

Example:

body knowledge control
{
html_banner => "<img src=\"http://www.example.org/img/banner.png\">";
}

body reporter control
{
html_banner => "<img src=\"http://www.example.org/img/banner.png\">";
}

Notes:

This content is cited when generating HTML output from the knowledge agent.


Next: , Previous: html_banner in reporter, Up: control reporter

5.8.7 html_embed

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Synopsis: If true, no header and footer tags will be added to html output

Example:

body reporter control
{
html_embed => "true";
}

Notes:

Embedded HTML means something that could be put into a frame or table, without html or body tags, headers footers etc.


Next: , Previous: html_embed in reporter, Up: control reporter

5.8.8 html_footer

Type: string

Allowed input range: (arbitrary string)

Synopsis: HTML code for a page footer to be added to rendered in html before the end body tag

Example:

body reporter control
{
html_footer => "
               <div id=\"footer\">Bottom of the page</div>
               ";
}

body knowledge control
{
html_footer => "
               <div id=\"footer\">Bottom of the page</div>
               ";
}

Notes:

This allows us to cite HTML code for formatting reports generated by the reporting and knowledge agents.


Next: , Previous: html_footer in reporter, Up: control reporter

5.8.9 query_engine

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name of a dynamic web-page used to accept and drive queries in a browser

Example:

body knowledge control
{
query_engine => "http://www.example.org/script.php";
}

body reporter control
{
query_engine => "http://www.example.org/script.pl";
}

Notes:

When displaying topic maps in HTML format, cf-know will render each topic as a link to this URL with the new topic as an argument. Thus it is possible to make a dynamic web query by embedding CFEngine in the web page as system call and passing the argument to it.


Next: , Previous: query_engine in reporter, Up: control reporter

5.8.10 reports

Type: (option list)

Allowed input range:

               all
               audit
               performance
               all_locks
               active_locks
               hashes
               classes
               last_seen
               monitor_now
               monitor_history
               monitor_summary
               compliance
               setuid
               file_changes
               installed_software
               software_patches
               value
               variables

Default value: none

Synopsis: A list of reports that may be generated

Example:

body reporter control
{
reports => { "performance", "classes"  };
}

Notes:

A list of report types that can be generated by this agent. The listed items from compliance onward are available only Enterprise editions of CFEngine.

The keyword ‘all’ can be used to get all reports except the audit and locking reports. The latter are large and unwieldy and need specific confirmation.


Next: , Previous: reports in reporter, Up: control reporter

5.8.11 report_output

Type: (menu option)

Allowed input range:

               csv
               html
               text
               xml

Default value: none

Synopsis: Menu option for generated output format. Applies only to text reports, graph data remain in xydy format.

Example:

body reporter control
{
report_output => "html";
}

Notes:

Sets the output format of embedded database reports.


Next: , Previous: report_output in reporter, Up: control reporter

5.8.12 style_sheet

Type: string

Allowed input range: (arbitrary string)

Synopsis: Name of a style-sheet to be used in rendering html output (added to headers)

Example:

body knowledge control
{
style_sheet => "http://www.example.org/css/sheet.css";
}

body reporter control
{
style_sheet => "http://www.example.org/css/sheet.css";
}

Notes:

For formatting the HTML generated output of cf-know.


Previous: style_sheet in reporter, Up: control reporter

5.8.13 time_stamps

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false whether to generate timestamps in the output directory name

Example:

body reporter control
{
time_stamps => "true";
}

Notes:

This option is only necessary with the default build directory. This can be used to keep snapshots of the system but it will result in a lot of storage be consumed. For most purposes CFEngine is programmed to forget the past at a predictable rate and there is no need to override this.


Previous: control reporter, Up: Control Promises

5.9 hub control promises


body hub control
{
export_zenoss => "true";
}



Next: , Previous: control hub, Up: control hub

5.9.1 export_zenoss

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Synopsis: Make data available for Zenoss integration in docroot/reports/summary.z

Example:

body hub control
{
am_policy_hub::

  export_zenoss => "true";
}

Notes:

History: Was introduced in version 3.1.0b1,Nova 2.0.0b1 (2010)

For integration with the Zenoss monitoring software.


Next: , Previous: export_zenoss in hub, Up: control hub

5.9.2 federation

Type: slist

Allowed input range: (arbitrary string)

Synopsis: The list of CFEngine servers supporting constellation integration with this hub

Example:

federation => { "host1", "host2" };

Notes:

History: Was introduced in Constellation 1.0 (2011)


Next: , Previous: federation in hub, Up: control hub

5.9.3 exclude_hosts

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of IP addresses of hosts to exclude from report collection

Example:

body hub control
{
exclude_hosts => { "192.168.12.21", "10.10", "10.12.*" };
}

Notes:

History: Was introduced in 3.3.0, Nova 2.1.1, Constellation 1.0.0 (2011)

In commercial CFEngine editions, this list of IP addresses will not be queried for reports by cf-hub, even though they are in the last-seen database.

The lists may contain network addresses in CIDR notation or regular expressions to match the IP address. However, host names are currently not supported.


Next: , Previous: exclude_hosts in hub, Up: control hub

5.9.4 hub_schedule

Type: slist

Allowed input range: (arbitrary string)

Synopsis: The class schedule used by cf-hub for report collation

Example:

body hub control
{
hub_schedule => { "Min00", "Min30", "(Evening|Night).Min45_50" };
}

Notes:

History: Was introduced in version 3.1.0b1,Nova 2.0.0b1 (2010)


Previous: hub_schedule in hub, Up: control hub

5.9.5 port

Type: int

Allowed input range: 1024,99999

Default value: 5308

Synopsis: Default port for contacting hub nodes

Example:

body hub control
{
port => "5308";
}

body server control
{
specialhost::
 port => "5308";

!specialhost::
 port => "5308";
}

Notes:

The standard or registered port number is tcp/5308. CFEngine does not presently use its registered udp port with the same number, but this could change in the future.

Changing the standard port number is not recommended practice. You should not do it without a good reason.


Next: , Previous: Control Promises, Up: Top

6 Bundles of common


     
     bundle common globals
     {
     vars:
     
       "global_var" string => "value";
     
     classes:
     
       "global_class" expression => "value";
     }
     


Common bundles may only contain the promise types that are common to all bodies. Their main function is to define cross-component global definitions. Common bundles are observed by every agent, whereas the agent specific bundle types are ignored by components other than the intended recipient.


Next: , Previous: Bundles for common, Up: Bundles for common

6.1 vars promises


Whereas most promise types are specific to a particular kind of interpretation that requires a typed interpreter (the bundle type), a number of promises can be made in any kind of bundle since they are of a generic input/output nature. These are vars, classes, and reports promises. The specific promise attributes are listed below.


Next: , Previous: vars in common promises, Up: vars in common promises

6.1.1 string

Type: string

Allowed input range: (arbitrary string)

Synopsis: A scalar string

Example:

vars:

 "xxx"    string => "Some literal string...";

 "yyy"    string => readfile( "/home/mark/tmp/testfile" , "33" );

Notes:

In CFEngine previously lists were represented (as in the shell) using separted scalars, e.g. like the PATH variable. This design feature turned out to be an error of judgement which has resulted in much trouble. This is no longer supported in CFEngine 3. By keeping lists an independent type many limitations have been removed.


Next: , Previous: string in vars, Up: vars in common promises

6.1.2 int

Type: int

Allowed input range: -99999999999,9999999999

Synopsis: A scalar integer

Example:

vars:

 "scalar" int    => "16k";

 "ran"    int    => randomint(4,88);

 "dim_array" int =>  readstringarray("array_name","/etc/passwd","#[^\n]*",":",10,4000);

Notes:

Int variables are strings that are expected to be used as integer numbers. The typing in CFEngine is dynamic, so the variable types are interchangable, but when you declare a variable to be type int, CFEngine verifies that the value you assign to it looks like an integer (e.g., ‘3’, ‘-17’, ‘16K’, etc).

Integer values may use suffices ‘k’, ‘K’, ‘m’, ‘M’, etc., but must only have an integer numeric part (so ‘1.5M’ is not allowed).

k
The value multipled by 1000.
K
The value multipled by 1024.
m
The value multipled by 1000 * 1000.
M
The value multipled by 1024 * 1024.
g
The value multipled by 1000 * 1000 * 1000.
G
The value multipled by 1024 * 1024 * 1024.
%
A percentage between 1 and 100 - mainly for use in a storage context.

The value ‘inf’ may also be used to represent an unlimited positive value.


Next: , Previous: int in vars, Up: vars in common promises

6.1.3 real

Type: real

Allowed input range: -9.99999E100,9.99999E100

Synopsis: A scalar real number

Example:

vars:
   
 "scalar" real   => "0.5";

Notes:

Real variables are strings that are expected to be used as real numbers. The typing in CFEngine is dynamic, so the variable types are interchangable, but when you declare a variable to be type real, CFEngine verifies that the value you assign to it looks like a real number (e.g., ‘3’, ‘3.1415’, ‘.17’, ‘6.02e23’, ‘-9.21e-17’, etc).

Real numbers are not used in many places in CFEngine, but they are useful for representing probabilties and performance data.


Next: , Previous: real in vars, Up: vars in common promises

6.1.4 slist

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of scalar strings

Example:

vars:

 "xxx"    slist  => {  "literal1",  "literal2" };

 "yyy"    slist  => { 
                    readstringlist(
                                  "/home/mark/tmp/testlist",
                                  "#[a-zA-Z0-9 ]*",
                                  "[^a-zA-Z0-9]",
                                  15,
                                  4000
                                  ) 
                    };

 "zzz"    slist  => { readstringlist("/home/mark/tmp/testlist2","#[^\n]*",",",5,4000) };


Notes:

Some functions return slists (see Introduction to functions), and an slist may contain the values copied from another slist, rlist, or ilist (see List variable substitution and expansion, see policy in vars).


Next: , Previous: slist in vars, Up: vars in common promises

6.1.5 ilist

Type: ilist

Allowed input range: -99999999999,9999999999

Synopsis: A list of integers

Example:

vars:

  "variable_id"

       ilist => { "10", "11", "12" };

Notes:

Integer lists are lists of strings that are expected to be treated as integers. The typing in CFEngine is dynamic, so the variable types are interchangable, but when you declare a variable to be type ilist, CFEngine verifies that each value you assign to it looks like an integer (e.g., ‘3’, ‘-17’, ‘16K’, etc).

Some functions return ilists (see Introduction to functions), and an ilist may contain the values copied from another slist, rlist, or ilist (see List variable substitution and expansion, see policy in vars).


Next: , Previous: ilist in vars, Up: vars in common promises

6.1.6 rlist

Type: rlist

Allowed input range: -9.99999E100,9.99999E100

Synopsis: A list of real numbers

Example:

vars:

  "varid" rlist => { "0.1", "0.2", "0.3" };

Notes:

Real lists are lists of strings that are expected to be used as real numbers. The typing in CFEngine is dynamic, so the variable types are interchangable, but when you declare a variable to be type rlist, CFEngine verifies that each value you assign to it looks like a real number (e.g., ‘3’, ‘3.1415’, ‘.17’, ‘6.02e23’, ‘-9.21e-17’, etc).

Some functions return rlists (see Introduction to functions), and an rlist may contain the values copied from another slist, rlist, or ilist (see List variable substitution and expansion, see policy in vars).


Previous: rlist in vars, Up: vars in common promises

6.1.7 policy

Type: (menu option)

Allowed input range:

               free
               overridable
               constant
               ifdefined

Synopsis: The policy for (dis)allowing (re)definition of variables

Example:

vars:

  "varid" string => "value...",
          policy => "constant";

Notes:

Variables can either be allowed to change their value dynamically (be redefined) or they can be constant. The use of private variable spaces in CFEngine 3 makes it unlikely that variable redefinition would be necessary in CFEngine 3.

The value constant indicates that the variable value may not be changed. The values free and overridable are synonymous, and indicated the the variable's value may be changed.

The value ifdefined applies only to lists and implies that unexpanded or undefined lists are dropped. The default behaviour is otherwise to retain this value as an indicator of the failure to quench the variable reference, e.g.

   
    "one" slist => { "1", "2", "3" };

   "list" slist => { "@(one)", @(two) },

            policy => "ifdefined";

would result in ‘@(list)’ being the same as ‘@(one)’, and the reference to ‘@(two)’ would disappear. This is useful for combining lists, `inheritance-style' where one can extend a base with special cases if they are defined.

Default value:

policy => constant


Next: , Previous: vars in common promises, Up: Bundles for common

6.2 classes promises


Whereas most promise types are specific to a particular kind of interpretation that requires a typed interpreter (the bundle type), a number of promises can be made in any kind of bundle since they are of a generic input/output nature. These are vars, classes, and reports promises. The specific promise attributes are listed below.


Next: , Previous: classes in common promises, Up: classes in common promises

6.2.1 or

Type: clist

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: Combine class sources with inclusive OR

Example:

classes:

    "compound_test" 

      or => { classmatch("linux_x86_64_2_6_22.*"), "suse_10_3" };

Notes:

A useful construction for writing expressions that contain special functions. The class in the LHS will be defined if any one (or more) of the class expressions in the RHS are true.


Next: , Previous: or in classes, Up: classes in common promises

6.2.2 and

Type: clist

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: Combine class sources with AND

Example:

classes:

  "compound_class" and => { classmatch("host[0-9].*"), "Monday", "Hr02" };

Notes:

If an expression contains a mixture of different object types that need to be ANDed together, this list form is more convenient than providing an expression. If all of the class expressions listed in the RHS match, then the class on the LHS is defined.


Next: , Previous: and in classes, Up: classes in common promises

6.2.3 xor

Type: clist

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: Combine class sources with XOR

Example:

classes:

 "another_global" xor => { "any", "linux", "solaris"};

Notes:

Behaves as the XOR operation on class expressions. It can be used to define a class if exactly one of the class expressions on the RHS matches.


Next: , Previous: xor in classes, Up: classes in common promises

6.2.4 dist

Type: rlist

Allowed input range: -9.99999E100,9.99999E100

Synopsis: Generate a probabilistic class distribution (from strategies in cfengine 2)

Example:

classes:

  "my_dist"  

    dist => { "10", "20", "40", "50" };

Notes:

Assign one generic class (always) and one additional class, randomly weighted on a probability distribution. The sum of 10+20+40+50 = 120 in the example above, so in generating a distribution, CFEngine picks a number between 1-120. This will generate the following classes:

     my_dist    (always)
     my_dist_10 (10/120 of the time)
     my_dist_20 (20/120 of the time)
     my_dist_40 (40/120 of the time)
     my_dist_50 (50/120 of the time)

This was previous called a ‘strategy’ in CFEngine 2.


Next: , Previous: dist in classes, Up: classes in common promises

6.2.5 expression

Type: class

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: Evaluate string expression of classes in normal form

Example:

classes:

  "class_name" expression => "solaris|(linux.specialclass)";
  "has_toor"   expression => userexists("toor");

Notes:

A way of aliasing class combinations.


Next: , Previous: expression in classes, Up: classes in common promises

6.2.6 not

Type: class

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Synopsis: Evaluate the negation of string expression in normal form

Example:

classes:

   "others"  not => "linux|solaris";
   "no_toor" not => userexists("toor");

Notes:

This negates the effect of the promiser-pattern regular expression. The class in the LHS will only be defined if the class expression in the RHS is false.


Previous: not in classes, Up: classes in common promises

6.2.7 select_class

Type: clist

Allowed input range: [a-zA-Z0-9_!&@@$|.()\[\]{}]+

Default value: random_selection

Synopsis: Select one of the named list of classes to define based on host identity

Example:

bundle common g
{
classes:
  "selection" select_class => { "one", "two" };

reports:
  one::
    "One was selected";
  two::
    "Two was selected";
  selection::
     "A selection was made";
}

Notes:

History: Was introduced in version 3.1.5, Nova 2.1.0 Constellation 1.0 (2011)

This feature is somewhat like the splayclass function, but instead of selecting a class for a moment in time, it always chooses one class in the list – the same class each time for a given host. This allows hosts to be distributed across a controlled list of classes, e.g for load balancing purposes.

The class is chosen deterministically (not randomly) but it is not possible to say which host will end up in which class in advance – only that hosts will always end up in the same class every time.


Next: , Previous: classes in common promises, Up: Bundles for common

6.3 reports promises


Whereas most promise types are specific to a particular kind of interpretation that requires a typed interpreter (the bundle type), a number of promises can be made in any kind of bundle since they are of a generic input/output nature. These are vars, classes, and reports promises. The specific promise attributes are listed below.


Next: , Previous: reports in common promises, Up: reports in common promises

6.3.1 friend_pattern

Type: string

Allowed input range: (arbitrary string)

Synopsis: Regular expression to keep selected hosts from the friends report list

Example:

reports:

  linux::

   "Friend status report"

          lastseen => "0"
     friend_pattern => "host1|host2|.*\.domain\.tld";

Notes:

This regular expression should match hosts we want to exclude from friend reports.


Next: , Previous: friend_pattern in reports, Up: reports in common promises

6.3.2 intermittency

Type: real

Allowed input range: 0,1

Default value: false

Synopsis: Real number threshold [0,1] of intermittency about current peers, report above

Example:

reports:

  "Comment"

    intermittency => "0.5";

Notes:

Report on CFEngine peers in the neighbourhood watch whose observed irregularity of connection exceeds 0.5 scaled entropy units, meaning that they show an erratic pattern of connection.


Next: , Previous: intermittency in reports, Up: reports in common promises

6.3.3 lastseen

Type: int

Allowed input range: 0,99999999999

Synopsis: Integer time threshold in hours since current peers were last seen, report absence

Example:

In control:

body agent control
{
lastseen => "false";
}

See also in reports:

reports:

  "Comment"

    lastseen => "10";

Notes:

In reports: after this time (hours) has passed, CFEngine will begin to warn about the host being overdue. After the lastseenexpireafter expiry time, hosts will be purged from this host's database (default is a week).

In control: determines whether CFEngine will records last seen intermittency profiles (reliability diagnostics) in WORKDIR/lastseen. This generates a separate file for each each host that connects to the current host. For central hubs this can result is a huge number of files.


Next: , Previous: lastseen in reports, Up: reports in common promises

6.3.4 printfile (body template)

Type: (ext body)

file_to_print
Type: string

Allowed input range: "?(/.*)

Synopsis: Path name to the file that is to be sent to standard output

Example:

     
body printfile example
     {
     file_to_print   => "/etc/motd";
     number_of_lines => "10";
     }
     

Notes:

Include part of a file in a report.

number_of_lines
Type: int

Allowed input range: 0,99999999999

Synopsis: Integer maximum number of lines to print from selected file

Example:

     
body printfile example
     {
     number_of_lines => "10";
     }
     

Notes:


Next: , Previous: printfile in reports, Up: reports in common promises

6.3.5 report_to_file

Type: string

Allowed input range: "?(/.*)

Synopsis: The path and filename to which output should be appended

Example:

bundle agent test
{
reports:

  linux::

   "$(sys.date),This is a report from $(sys.host)"

       report_to_file => "/tmp/test_log";
}

Notes:

Append the output of the report to the named file instead of standard output. If the file cannot be opened for writing then the report defaults to the standard output.


Previous: report_to_file in reports, Up: reports in common promises

6.3.6 showstate

Type: slist

Allowed input range: (arbitrary string)

Synopsis: List of services about which status reports should be reported to standard output

Example:

reports:

  "Comment"

    showstate => {"www_in", "ssh_out", "otherprocs" };

Notes:

The basic list of services is:

users
Users logged in
rootprocs
Privileged system processes
otherprocs
Non-privileged process
diskfree
Free disk on / partition
loadavg
% kernel load utilization
netbiosns_in
netbios name lookups (in)
netbiosns_out
netbios name lookups (out)
netbiosdgm_in
netbios name datagrams (in)
netbiosdgm_out
netbios name datagrams (out)
netbiosssn_in
netbios name sessions (in)
netbiosssn_out
netbios name sessions (out)
irc_in
IRC connections (in)
irc_out
IRC connections (out)
cfengine_in
CFEngine connections (in)
cfengine_out
CFEngine connections (out)
nfsd_in
nfs connections (in)
nfsd_out
nfs connections (out)
smtp_in
smtp connections (in)
smtp_out
smtp connections (out)
www_in
www connections (in)
www_out
www connections (out)
ftp_in
ftp connections (in)
ftp_out
ftp connections (out)
ssh_in
ssh connections (in)
ssh_out
ssh connections (out)
wwws_in
wwws connections (in)
wwws_out
wwws connections (out)
icmp_in
ICMP packets (in)
icmp_out
ICMP packets (out)
udp_in
UDP dgrams (in)
udp_out
UDP dgrams (out)
dns_in
DNS requests (in)
dns_out
DNS requests (out)
tcpsyn_in
TCP sessions (in)
tcpsyn_out
TCP sessions (out)
tcpack_in
TCP acks (in)
tcpack_out
TCP acks (out)
tcpfin_in
TCP finish (in)
tcpfin_out
TCP finish (out)
tcpmisc_in
TCP misc (in)
tcpmisc_out
TCP misc (out)
webaccess
Webserver hits
weberrors
Webserver errors
syslog
New log entries (Syslog)
messages
New log entries (messages)
temp0
CPU Temperature 0
temp1
CPU Temperature 1
temp2
CPU Temperature 2
temp3
CPU Temperature 3
cpu
%CPU utilization (all)
cpu0
%CPU utilization 0
cpu1
%CPU utilization 1
cpu2
%CPU utilization 2
cpu3
%CPU utilization 3


Previous: reports in common promises, Up: Bundles for common

6.4 * promises


Whereas most promise types are specific to a particular kind of interpretation that requires a typed interpreter (the bundle type), a number of promises can be made in any kind of bundle since they are of a generic input/output nature. These are vars, classes, and reports promises. The specific promise attributes are listed below.


Next: , Previous: * in common promises, Up: * in common promises

6.4.1 action (body template)

Type: (ext body)

action_policy
Type: (menu option)

Allowed input range:

                    fix
                    warn
                    nop

Synopsis: Whether to repair or report about non-kept promises

Example:

The following example shows a simple use of transaction control, causing the promise to be verified as a separate background process.

     
body action background
     
     {
     action_policy => "warn";
     }
     

Notes:

The action settings allow general transaction control to be implemented on promise verification. Action bodies place limits on how often to verify the promise and what classes to raise in the case that the promise can or cannot be kept.

Note that actions can be added to sub-bundles like methods and editing bundles, and that promises within these do not inherit action settings at higher levels. Thus, in the following example there are two levels of action setting:

     ########################################################
     #

     # Warn if line matched

     #

     ########################################################

     
     body common control
     
     {
     bundlesequence  => { "testbundle" };
     }
     
     ########################################################

     
bundle agent testbundle
     
     {
     files:
     
       "/var/cfengine/inputs/.*"
     
            edit_line => DeleteLinesMatching(".*cfenvd.*"),
            action => WarnOnly;
     }
     
     ########################################################

     
bundle edit_line DeleteLinesMatching(regex)
       {
       delete_lines:
     
         "$(regex)" action => WarnOnly;
     
       }
     
     ########################################################

     
body action WarnOnly
     {
     action_policy => "warn";
     }

The action setting for the files promise means that file edits will not be committed to disk, only warned about. This is a master-level promise that overrides anything that happens during the editing. The action setting for the edit bundle means that the internal memory modelling of the file will only warn about changes rather than committing them to the memory model. This makes little difference to the end result, but it means that CFEngine will report

          Need to delete line - ... - but only a warning was promised

Instead of

          Deleting the prpomised line ...
          Need to save file - but only a warning was promised

In either case, no changes will be made to the disk, but the messages given by cf-agent will differ.

ifelapsed
Type: int

Allowed input range: 0,99999999999

Synopsis: Number of minutes before next allowed assessment of promise

Default value: control body value

Example:

     
     #local

     
body action example
     {
     ifelapsed   => "120";	# 2 hours
     expireafter => "240";	# 4 hours
     }
     
     # global

     
body agent control
     {
     ifelapsed   => "180";	# 3 hours
     }
     

Notes:

This overrides the global settings. Promises which take a long time to verify should usually be protected with a long value for this parameter. This serves as a resource `spam' protection. A CFEngine check could easily run every 5 minutes provided resource intensive operations are not performed on every run. Using time classes like Hr12 etc., is one part of this strategy; using ifelapsed is another which is not tied to a specific time.

expireafter
Type: int

Allowed input range: 0,99999999999

Synopsis: Number of minutes before a repair action is interrupted and retried

Default value: control body value

Example:

     body action example
     {
     ifelapsed   => "120";	# 2 hours
     expireafter => "240";	# 4 hours
     }

Notes:

The locking time after which CFEngine will attempt to kill and restart its attempt to keep a promise.

log_string
Type: string

Allowed input range: (arbitrary string)

Synopsis: A message to be written to the log when a promise verification leads to a repair

Example:

          
          promise-type:
          
           "promiser"
          
             attr => "value",
             action => log_me("checked $(this.promiser) in promise $(this.handle)");
          
          # ..
          
          body action log_me(s)
          {
          log_string => "$(s)";
          }
          

Notes:

The log_string works together with log_repair, log_kept etc, to define a string for logging to one of the named files depending on promise outcome, or to standard output of the log file is stipulared as ‘stdout’. Log strings on standard output are denoted by an ‘L:’ prefix.

Note that log_string does not interact with log_level, which is about regular system output messages.

Hint: the promise handle ‘$(this.handle)’ can be a useful referent in a log message, indicating the origin of the message. In CFEngine Nova and above, every promise has a default handle (which is based o the filename and line number - specifying your own handle will probably be more mnemonic)..

log_level
Type: (menu option)

Allowed input range:

                    inform
                    verbose
                    error
                    log

Synopsis: The reporting level sent to syslog

Example:

     
body action example
     {
     log_level => "inform";
     }
     

Notes:

Use this as an alternative to auditing to use the syslog mechanism to centralize or manage messaging from CFEngine. A backup of these messages will still be kept in WORKDIR/outputs if you are using cf-execd.

On native Windows version of CFEngine (Nova or above), using ‘verbose’ will include a message when the promise is kept or repaired in the event log.

log_kept
Type: string

Allowed input range: stdout|udp_syslog|("?[a-zA-Z]:\\.*)|(/.*)

Synopsis: This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger

Example:

     
body action logme(x)
     {
     log_kept => "/tmp/private_keptlog.log";
     log_failed => "/tmp/private_faillog.log";
     log_repaired => "/tmp/private_replog.log";
     log_string => "$(sys.date) $(x) promise status";
     }
     

Notes:

If this option is specified together with log_string, the current promise will log promise-kept status using the log string to this named file. If these log names are absent, the default logging destination for the log string is syslog, but only for non-kept promises. Only the log_string is affected by this setting. Other messages destined for logging are sent to syslog.

It is intended that named file logs should be different for the three cases: promise kept, promise not kept and promise repaired.

This string should be the full path to a text file which will contain the log, of one of the following special values:

stdout
Send the log message to the standard output, prefixed with an ‘L:’ to indicate a log message.
udp_syslog
Attempt to connect to the syslog_server defined in ‘body common control’ and log the message there, assuming the server is configured to receive the request.

log_priority
Type: (menu option)

Allowed input range:

                    emergency
                    alert
                    critical
                    error
                    warning
                    notice
                    info
                    debug

Synopsis: The priority level of the log message, as interpreted by a syslog server

Example:

     body action low_priority
     {
     log_priority => "info";
     }

Notes:

This determines the importance of messages from CFEngine.

log_repaired
Type: string

Allowed input range: stdout|udp_syslog|("?[a-zA-Z]:\\.*)|(/.*)

Synopsis: This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger

Example:

     
bundle agent test
     {
     vars:
     
       "software" slist => { "/root/xyz", "/tmp/xyz" };
     
     files:
     
       "$(software)"
     
         create => "true",
          action => logme("$(software)");
     
     }
     
body action logme(x)
     {
     log_kept => "/tmp/private_keptlog.log";
     log_failed => "/tmp/private_faillog.log";
     log_repaired => "/tmp/private_replog.log";
     log_string => "$(sys.date) $(x) promise status";
     }
     
body action immediate_syslog(x)
     {
     log_repaired => "udp_syslog"; # Nova and above 
     log_string => "CFEngine repaired promise $(this.handle) - $(x)";
     }

Notes:

This may be the name of a log to which the log_string is written if a promise is repaired. It should be the full path to a text file which will contain the log, of one of the following special values:

stdout
Send the log message to the standard output, prefixed with an ‘L:’ to indicate a log message.
udp_syslog
Attempt to connect to the syslog_server defined in ‘body common control’ and log the message there, assuming the server is configured to receive the request.

log_failed
Type: string

Allowed input range: stdout|udp_syslog|("?[a-zA-Z]:\\.*)|(/.*)

Synopsis: This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger

Example:

     
bundle agent test
     {
     vars:
     
       "software" slist => { "/root/xyz", "/tmp/xyz" };
     
     files:
     
       "$(software)"
     
         create => "true",
          action => logme("$(software)");
     
     }
     
     
body action logme(x)
     {
     log_kept => "/tmp/private_keptlog.log";
     log_failed => "/tmp/private_faillog.log";
     log_repaired => "/tmp/private_replog.log";
     log_string => "$(sys.date) $(x) promise status";
     }
     

Notes:

If this option is specified together with log_string, the current promise will log promise-kept status using the log string to this named file. If these log names are absent, the default logging destination for the log string is syslog, but only for non-kept promises. Only the log_string is affected by this setting. Other messages destined for logging are sent to syslog.

It is intended that named file logs should be different for the three cases: promise kept, promise not kept and promise repaired. This string should be the full path to a text file which will contain the log, of one of the following special values:

stdout
Send the log message to the standard output, prefixed with an ‘L:’ to indicate a log message.
udp_syslog
Attempt to connect to the syslog_server defined in ‘body common control’ and log the message there, assuming the server is configured to receive the request.

value_kept
Type: real

Allowed input range: -9.99999E100,9.99999E100

Synopsis: A real number value attributed to keeping this promise

Example:

     
body action mydef
     {
     value_kept     => "4.5";   # this promise is worth 4.5 dollars per hour
     value_repaired => "2.5";   # fixing this promise is worth 2.5 dollars per hour
     value_notkept  => "-10.0"; # not keeping this promise costs is 10 dollars per hour
     ifelapsed       => "60";   # one hour
     }
     

Notes:

If nothing is specified, the default value is +1.0. However, nothing is logged unless the agent control body switched on ‘track_value => "true"’.

value_repaired
Type: real

Allowed input range: -9.99999E100,9.99999E100

Synopsis: A real number value attributed to reparing this promise

Example:

     
body action mydef
     {
     value_kept     => "4.5";   # this promise is worth 4.5 dollars per hour
     value_repaired => "2.5";   # fixing this promise is worth 2.5 dollars per hour
     value_notkept  => "-10.0"; # not keeping this promise costs is 10 dollars per hour
     ifelapsed       => "60";   # one hour
     }
     

Notes:

If nothing is specified, the default value is 0.5. However, nothing is logged unless the agent control body switched on ‘track_value => "true"’.

value_notkept
Type: real

Allowed input range: -9.99999E100,9.99999E100

Synopsis: A real number value (possibly negative) attributed to not keeping this promise

Example:

     
body action mydef
     {
     value_kept     => "4.5";   # this promise is worth 4.5 dollars per hour
     value_repaired => "2.5";   # fixing this promise is worth 2.5 dollars per hour
     value_notkept  => "-10.0"; # not keeping this promise costs is 10 dollars per hour
     ifelapsed       => "60";   # one hour
     }
     

Notes:

If nothing is specified, the default value is -1.0. However, nothing is logged unless the agent control body switched on ‘track_value => "true"’.

audit
Type: (menu option)

Allowed input range:

                    true
                    false
                    yes
                    no
                    on
                    off

Synopsis: true/false switch for detailed audit records of this promise

Default value: false

Example:

     
body action example
     {
     # ...

     
     audit => "true";
     }
     

Notes:

If this is set, CFEngine will perform auditing on this specific promise. This means that all details surrounding the verification of the current promise will be recorded in the audit database. The database may be inspected with cf-report, or cfshow in CFEngine 2.

background
Type: (menu option)

Allowed input range:

                    true
                    false
                    yes
                    no
                    on
                    off

Synopsis: true/false switch for parallelizing the promise repair

Default value: false

Example:

     
body action example
     {
     background => "true";
     }
     

Notes:

If possible, perform the verification of the current promise in the background. This is advantageous only if the verification might take a significant amount of time, e.g. in remote copying of filesystem/disk scans.

On the windows version of CFEngine Nova, this can be useful if we don't want to wait for a particular command to finish execution before checking the next promise. This is particular for the windows platform because there is no way that a program can start itself in the background here (i.e. fork off a child process). However, file operations can not be performed in the background on windows.

report_level
Type: (menu option)

Allowed input range:

                    inform
                    verbose
                    error
                    log

Synopsis: The reporting level for standard output for this promise

Default value: none

Example:

     
body action example
     {
     report_level => "verbose";
     }
     

Notes:

cf-agent can be run in verbose mode (-v), inform mode (-I) and just print errors (no arguments). This attribute allows to set these three output levels on a per promise basis, allowing the promise to be more verbose than the global setting (but not less).

In CFEngine 2 one would say ‘inform=true’ or ‘syslog=true’, etc. This replaces these levels since they act as encapsulating super-sets.

measurement_class
Type: string

Allowed input range: (arbitrary string)

Synopsis: If set performance will be measured and recorded under this identifier

Example:

     
     
body action measure
     {
     measurement_class => "$(this.promiser) long job scan of /usr";
     }
     

Notes:

By setting this string you switch on performance measurement for the current promise, and also give the measurement a name. The identifier forms a partial identity for optional performance scanning of promises of the form:

          ID:promise-type:promiser.

These can be seen identifying using cf-reports, e.g. in the generated file performance.html.


Next: , Previous: action in *, Up: * in common promises

6.4.2 classes (body template)

Type: (ext body)

promise_repaired
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be defined globally

Example:

     
body classes example
     {
     promise_repaired => { "change_happened" };
     }
     

Notes:

If a promise is `repaired' it means that a corrective action had to be taken to keep the promise.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

Important: complex promises, e.g. files promises that set multiple parameters on a file simultaneously can report misleadingly. The classes for different parts of a promise are not separable. Thus, if you promise to create and file and change its permissions, when the file exists with incorrect permissions, cf-agent will report that the ‘promise_kept’ for the file existence, but ‘promise_repaired’ for the permissions. If you need separate reports, you should code two separate promises rather than `overloading' a single one.

repair_failed
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be defined globally

Example:

     
body classes example
     {
     repair_failed => { "unknown_error" };
     }
     

Notes:

A promise could not be repaired because the corrective action failed for some reason.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

repair_denied
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be defined globally

Example:

     
body classes example
     {
     repair_denied => { "permission_failure" };
     }
     

Notes:

A promise could not be kept because access to a key resource was denied.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

repair_timeout
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be defined globally

Example:

     
body classes example
     {
     repair_timeout => { "too_slow", "did_not_wait" };
     }
     

Notes:

A promise maintenance repair timed-out waiting for some dependent resource.

promise_kept
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be defined globally

Example:

     
body classes example
     {
     promise_kept => { "success", "kaplah" };
     }
     

Notes:

This class is set if no action was necessary by cf-agent because the promise concerned was already kept without further action required.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

Important: complex promises, e.g. files promises that set multiple parameters on a file simultaneously can report misleadingly. The classes for different parts of a promise are not separable. Thus, if you promise to create and file and change its permissions, when the file exists with incorrect permissions, cf-agent will report that the ‘promise_kept’ for the file existence, but ‘promise_repaired’ for the permissions. If you need separate reports, you should code two separate promises rather than `overloading' a single one.

cancel_kept
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be cancelled if the promise is kept

Example:

     
body classes example
     {
     cancel_kept => { "success", "kaplah" };
     }
     

Notes:

If the promise was already kept and nothing was done, cancel (undefine) any of the listed classes so that they are no longer defined.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

cancel_repaired
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be cancelled if the promise is repaired

Example:

     
body classes example
     {
     cancel_repaired => { "change_happened" };
     }
     

Notes:

If the promise was repaired and changes were made to the system, cancel (undefine) any of the listed classes so that they are no longer defined.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

cancel_notkept
Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A list of classes to be cancelled if the promise is not kept for any reason

Example:

     
body classes example
     {
     cancel_notkept => { "failure" };
     }
     

Notes:

If the promise was not kept but nothing could be done, cancel (undefine) any of the listed classes so that they are no longer defined.

Note that any strings passed to this list are automatically canonified, so it is unecessary to call a canonify function on such inputs.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

kept_returncodes
Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Synopsis: A list of return codes indicating a kept command-related promise

Example:

     bundle agent cmdtest
     {
     commands:
       "/bin/false"
        classes => example;
     
     reports:
     waskept::
       "The command-promise was kept!";
     }
     
body classes example
     {
     kept_returncodes => { "0", "1" };
     promise_kept => { "waskept" };
     }

Notes:

A list of integer return codes indicating that a command-related promise has been kept. This can in turn be used to define classes using the promise_kept attribute, or merely alter the total compliance statistics.

Currently, the attribute has impact on the following command-related promises.

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

repaired_returncodes
Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Synopsis: A list of return codes indicating a repaired command-related promise

Example:

     bundle agent cmdtest
     {
     commands:
       "/bin/false"
        classes => example;
     
     reports:
     wasrepaired::
       "The command-promise got repaired!";
     }
     
body classes example
     {
     repaired_returncodes => { "0", "1" };
     promise_repaired => { "wasrepaired" };
     }

Notes:

A list of integer return codes indicating that a command-related promise has been repaired. This can in turn be used to define classes using the promise_repaired attribute, or merely alter the total compliance statistics.

Currently, the attribute has impact on the following command-related promises.

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

failed_returncodes
Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Synopsis: A list of return codes indicating a failed command-related promise

Example:

     body common control
     {
     bundlesequence => { "cmdtest" };
     }
     
bundle agent cmdtest
     {
     files:
     "/tmp/test"
       copy_from => copy("/etc/passwd");
     
     
     "/tmp/test"
       classes => example,
       transformer => "/bin/grep -q lkajfo999999 $(this.promiser)";
     
     reports:
     wasfailed::
       "The files-promise failed!";
     }
     
body classes example
     {
     failed_returncodes => { "1" };
     repair_failed => { "wasfailed" };
     }
     
body copy_from copy(file)
     {
     source => "$(file)";
     } 

Notes:

A list of integer return codes indicating that a command-related promise has failed. This can in turn be used to define classes using the promise_repaired attribute, or merely alter the total compliance statistics.

Currently, the attribute has impact on the following command-related promises.

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

persist_time
Type: int

Allowed input range: 0,99999999999

Synopsis: A number of minutes the specified classes should remain active

Example:

     
body classes example
     {
     persist_time => "10";
     }
     

Notes:

By default classes are ephemeral entities that disappear when cf-agent terminates. By setting a persistence time, they can last even when the agent is not running.

timer_policy
Type: (menu option)

Allowed input range:

                    absolute
                    reset

Synopsis: Whether a persistent class restarts its counter when rediscovered

Default value: reset

Example:

     
body classes example
     {
     timer_policy => "reset";
     }
     

Notes:

The in most cases resetting a timer will give a more honest appraisal of which classes are currently important, but if we want to activate a response of limited duration as a rare event then an asbolute time limit is useful.


Next: , Previous: classes in *, Up: * in common promises

6.4.3 ifvarclass

Type: string

Allowed input range: (arbitrary string)

Synopsis: Extended classes ANDed with context

Example:

The generic example has the form:

     
     promise-type:
     
       "promiser"
     
         ifvarclass => "$(program)_running|($(program)_notfound&Hr12)";
     

A specific example would be:

bundle agent example

{     
commands:

 any::

    "/bin/echo This is linux"

       ifvarclass => "linux";


    "/bin/echo This is solaris"

       ifvarclass => "solaris";

}

Notes:

This is an additional class expression that will be evaluated after the ‘class::’ classes have selected promises. It is provided in order to enable a channel between variables and classes. The result is thus the logical AND of the ordinary classes and the variable classes.

This function is provided so that one can form expressions that link variables and classes, e.g.

# Check that all components are running

vars:

  "component" slist => { "cf-monitord", "cf-serverd" };

processes:

  "$(component)" restart_class => canonify("start_$(component)");

commands:

   "/var/cfengine/bin/$(component)"

       ifvarclass => canonify("start_$(component)");

Notice that the function canonify() is provided to convert a general variable input into a string composed only of legal characters, using the same algorithm that CFEngine uses.


Next: , Previous: ifvarclass in *, Up: * in common promises

6.4.4 handle

Type: string

Allowed input range: [a-zA-Z0-9_$(){}\[\].]+

Synopsis: A unique id-tag string for referring to this as a promisee elsewhere

Example:

access:

  "/source"

    handle  => "update_rule",
    admit   => { "127.0.0.1" };

Notes:

A promise handle is like a `goto' label. It allows you to refer to a promise as the promisee of depends_on client of another promise. Handles are essential for mapping dependencies and performing impact analyses. In Enterprise versions of CFEngine, promise handles can also be used in outputs promises, See outputs in agent promises.


Next: , Previous: handle in *, Up: * in common promises

6.4.5 depends_on

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of promise handles that this promise builds on or depends on somehow (for knowledge management)

Example:

files:

  "/home/mark/tmp/testcopy" 

    depends_on    => { "server_promise_1" },
    copy_from     => mycopy("/source");

Notes:

This is a list of promise handles for whom this promise is a promisee. In other words, we acknowledge that this promise will be affected by the list of promises whose handles are specified.

This option is only used only for documentation currently. In commercial versions of CFEngine, using this attribute leads to automatic documentation about policy relationships for the purpose of Knowledge Management.


Previous: depends_on in *, Up: * in common promises

6.4.6 comment

Type: string

Allowed input range: (arbitrary string)

Synopsis: A comment about this promise's real intention that follows through the program

Example:

comment => "This comment follows the data for reference ...",

Notes:

Comments written in code follow the program, they are not merely discarded. They appear in reports and error messages.


Next: , Previous: Bundles for common, Up: Top

7 Bundles of agent


     
     bundle agent main(parameter)
     
     {
     vars:
     
       "sys_files"    slist        => {
                                      "/etc/passwd",
                                      "/etc/services"
                                      };
     files:
     
       "$(sys_files)" perms        => p("root","0644"),
                      changes      => trip_wire;
     
       "/etc/shadow"  perms        => p("root","0600"),
                      changes      => trip_wire;
     
       "/usr"         changes      => trip_wire,
                      depth_search => recurse("inf");
     
       "/tmp"         delete       => tidy,
                      file_select  => days("2"),
                      depth_search => recurse("inf");
     
     }
     


Agent bundles contain user-defined promises for cf-agent. The types of promises and their corresponding bodies are detailed below.


Next: , Previous: Bundles for agent, Up: Bundles for agent

7.1 commands promises in ‘agent


     
     commands:
     
       "/path/to/command args"
     
                  args => "more args",
                  contain => contain_body,
                  module => true/false;
     

Command containment allows you to make a `sandbox' around a command, to run it as a non-privileged user inside an isolated directory tree. CFEngine modules are commands that support a simple protocol (see below) in order to set additional variables and classes on execution from user defined code. Modules are intended for use as system probes rather than additional configuration promises.

In CFEngine 3 commands and processes have been separated cleanly. Restarting of processes must be coded as a separate command. This stricter type separation will allow more careful conflict analysis to be carried out.

Output from commands executed here is quoted inline, but prefixed with the letter ‘Q’ to distinguish it from other output, e.g. from reports (which is prefixed with the letter ‘R’).

It is possible to set classes based on the return code of a commands-promise in a very flexible way. See the kept_returncodes, repaired_returncodes and failed_returncodes attributes.

Commands were called shellcommands in CFEngine 2.

NOTE: a common mistake in using CFEngine is to embed many shell commands instead of using the built-in functionality. Use of CFEngine internals is preferred as it assures convergence and proper integrated checking. Extensive use of shell commands will make a CFEngine execution very heavy-weight like other management systems. To minimize the system cost of execution, always use CFEngine internals.


bundle agent example

{
commands:

  "/bin/sleep 10"
     action  => background;

  "/bin/sleep"
     args => "20",
     action  => background;

}


NOTE: when referring to executables whose paths contain spaces, you should quote the entire program string separately so that CFEngine knows the name of the executable file. e.g.

     
      commands:
     
       windows::
     
        "\"c:\Program Files\my name with space\" arg1 arg2";
     
       linux::
     
        "\"/usr/bin/funny command name\" -a -b -c";
     


Next: , Previous: commands in agent promises, Up: commands in agent promises

7.1.1 args

Type: string

Allowed input range: (arbitrary string)

Synopsis: Alternative string of arguments for the command (concatenated with promiser string)

Example:

commands:

  "/bin/echo one"

   args => "two three";

Notes:

Sometimes it is convenient to separate the arguments to a command from the command itself. The final arguments are the concatenation with one space. So in the example above the command would be

 /bin/echo one two three


Next: , Previous: args in commands, Up: commands in agent promises

7.1.2 contain (body template)

Type: (ext body)

useshell
Type: (menu option)

Allowed input range:

                    true
                    false
                    yes
                    no
                    on
                    off

Synopsis: true/false embed the command in a shell environment

Default value: false

Example:

     
body contain example
     {
     useshell => "true";
     }
     

Notes:

The default is to not use a shell when executing commands. Use of a shell has both resource and security consequences. A shell consumes an extra process and inherits environment variables, reads commands from files and performs other actions beyond the control of CFEngine. If one does not need shell functionality such as piping through multiple commands then it is best to manage without it. In the windows version of CFEngine Nova, the command is run in the the “Command Prompt” if useshell is true.

umask
Type: (menu option)

Allowed input range:

                    0
                    77
                    22
                    27
                    72
                    077
                    022
                    027
                    072

Synopsis: The umask value for the child process

Example:

     
body contain example
     {
     umask => "077";
     }
     

Notes:

Sets the internal umask for the process. Default value for the mask is ‘077’. On windows, umask is not supported and is thus ignored by windows versions of CFEngine.

exec_owner
Type: string

Allowed input range: (arbitrary string)

Synopsis: The user name or id under which to run the process

Example:

     
body contain example
     {
     exec_owner => "mysql_user";
     }
     

Notes:

This is part of the restriction of privilege for child processes when running cf-agent as the root user, or a user with privileges.

Windows requires the clear text password for the user account to run under. Keeping this in CFEngine policies could be a security hazard. Therefore, this option is not yet implemented on windows versions of CFEngine.

exec_group
Type: string

Allowed input range: (arbitrary string)

Synopsis: The group name or id under which to run the process

Example:

     
body contain example
     {
     exec_group => "nogroup";
     }
     

Notes:

This is part of the restriction of privilege for child processes when running cf-agent as the root group, or a group with privileges. It is ignored on windows, as processes do not have any groups associated with them.

exec_timeout
Type: int

Allowed input range: 1,3600

Synopsis: Timeout in seconds for command completion

Example:

     
body contain example
     {
     exec_timeout => "30";
     }
     

Notes:

Attempt to time-out after this number of seconds. This cannot be guaranteed as not all commands are willing to be interrupted in case of failure.

chdir
Type: string

Allowed input range: "?(/.*)

Synopsis: Directory for setting current/base directory for the process

Example:

     
body contain example
     
     {
     chdir => "/containment/directory";
     }
     

Notes:

This command has the effect of placing the running command into a current working directory equal to the parameter given, i.e. it works like the ‘cd’ shell command.

chroot
Type: string

Allowed input range: "?(/.*)

Synopsis: Directory of root sandbox for process

Example:

     
body contain example
     
     {
     chroot => "/private/path";
     }
     

Notes:

Sets the path of the directory that will be experienced as the top-most root directory for the process. In security parlance, this creates a `sandbox' for the process. Windows does not support this feature.

preview
Type: (menu option)

Allowed input range:

                    true
                    false
                    yes
                    no
                    on
                    off

Synopsis: true/false preview command when running in dry-run mode (with -n)

Default value: false

Example:

     
body contain example
     {
     preview => "true";
     }
     

Notes:

Previewing shell scripts during a dry-run is a potentially misleading activity. It should only be used on scripts that make no changes to the system. It is CFEngine best practice to never write change-functionality into user-written scripts except as a last resort: CFEngine can apply its safety checks to user defined scripts.

no_output
Type: (menu option)

Allowed input range:

                    true
                    false
                    yes
                    no
                    on
                    off

Synopsis: true/false discard all output from the command

Default value: false

Example:

     
body contain example
     {
     no_output => "true";
     }
     

Notes:

This is equivalent to piping standard output and error to /dev/null.


Previous: contain in commands, Up: commands in agent promises

7.1.3 module

Type: (menu option)

Allowed input range:

               true
               false
               yes
               no
               on
               off

Default value: false

Synopsis: true/false whether to expect the cfengine module protocol

Example:

commands:

   "/masterfiles/user_script"

     module => "true";

Notes:

If true, the module protocol is supported for this script, i.e. it is treated as a user module. A plug-in module may be written in any language, it can return any output you like, but lines which begin with a ‘+’ sign are treated as classes to be defined (like -D), while lines which begin with a ‘-’ sign are treated as classes to be undefined (like -N). Lines starting with ‘=’ are scalar variables to be defined, and lines beginning with ‘@’ are lists. Any other lines of output are cited by cf-agent as being erroneous, so you should normally make your module completely silent. Here is an example written in shell:

     #!/bin/sh
     /bin/echo "@mylist= { \"one\", \"two\", \"three\" }"
     /bin/echo "=myscalar= scalar val"
     /bin/echo "+module_class"

And here is an example using it:

body common control
   {
   any::

      bundlesequence  => { 
                         def,
                         modtest
                         };
   }

###################################################################


bundle agent def

{
commands:

  "$(sys.workdir)/modules/module_name" module => "true";

reports:

  #

  # Each module forms a private context with its name as id

  #


 module_class::

  "Module set variable $(module_name.myscalar)";

}

###################################################################


bundle agent modtest

{
vars:

 "mylist" slist => { @(module_name.mylist) };

reports:

 module_class::

  "Module set variable $(mylist)";

}

Here is an example module written in perl.
     #!/usr/bin/perl
     #
     # module:myplugin
     #
     
       # lots of computation....
     
     if (special-condition)
        {
        print "+specialclass";
        }
     

If your module is “simple” and is best expressed as a shell command, then we suggest that you expose the class being defined in the command being executed (making it easier to see what classes are used when reading the promises file). For example, the promises could read as follows (the two echo commands are to ensure that the shell always exits with a successful execution of a command):

bundle agent sendmail
{
commands:
    # This next module checks a specific failure mode of dcc, namely

    # more than 3 error states since the last time we ran cf-agent

    is_mailhost::
        "/bin/test `/usr/bin/tail -100 /var/log/maillog | /usr/bin/grep 'Milter (dcc): to error state' | /usr/bin/wc -l` -gt 3 && echo '+start_dccm' || echo
''"
            contain => shell_command,
            module => true;

    start_dccm::
        "/var/dcc/libexec/start-dccm"
            contain => not_paranoid;
}

body contain shell_command
{
    useshell    => "yes";
}

body contain not_paranoid
{
    useshell    => "no";
    exec_owner  => "root";
    umask       => "22";
}

Modules inherit the environment variables from cfagent and accept arguments, just as a regular command does.

     #!/bin/sh
     #
     # module:myplugin
     #
     
     /bin/echo $*
     

Modules define variables in cf-agent by outputting strings of the form

     
     =variablename=value
     

These variables end up in a context which has the same name as the module. When the $(allclasses) variable becomes too large to manipulate conveniently, you can access the complete list of currently defined classes in the file /var/cfengine/state/allclasses.


Next: , Previous: commands in agent promises, Up: Bundles for agent

7.2 databases promises in ‘agent


These features apply to Enterprise versions of CFEngine only.

CFEngine Nova can interact with commonly used database servers to keep promises about the structure and content of data within them.

There are two main cases of database management to address: small embedded databases and large centralized databases.

CFEngine is a tool whose strength lies distributed management of computers. Databases are often centralized entities that have single point of management, so a large monolithic database is more easily managed with other tools. However, CFEngine can still monitor changes and discrepancies, and it can manage smaller embedded databases that are distributed in nature, whether they are SQL, registry or future types.

So creating 100 new databases for test purposes is a task for CFEngine, but adding a new item to an important production database is not a task that we recommend using CFEngine for.

There are three kinds of database supported by Nova:

LDAP - The Lightweight Directory Access Protocol
A hierarchical network database primarily for reading simple schema.
SQL - Structured Query Language
A number of relational databases (currently supported: MySQL, Postgres) for reading and writing complex data.
Registry - Microsoft Registry
An embedded database for interfacing with system values in Microsoft Windows.
In addition, CFEngine uses a variety of embedded databases for its own internals.

CFEngine's ability to make promises about databases depends on the good grace of the database server. Embedded databases are directly part of the system and promises can be made directly. However, databases running through a server process (either on the same host or on a different host) are independent agents and CFEngine cannot make promises on their behalf, unless they promise (grant) permission for CFEngine to make the changes. Thus the pre-requisite for making SQL database promises is to grant a point of access on the server.

     
      databases:
     
       "database/subkey or table"
     
         database_operation => "create/delete/drop",
         database_type => "sql/ms_registry",
         database_columns => {
                             "name,type,size",
                             "name,type",
                             },
     
         database_server => body;
     
     
      body database_server name
       {
       db_server_owner => "account name";
       db_server_password => "password";
       db_server_host => "hostname or omit for localhost";
       db_server_type => "mysql/posgres";
       db_server_connection_db => "database we can connect to";
       }
     


body common control
{
bundlesequence => { "databases" };
}

bundle agent databases

{
#commands:


#  "/usr/bin/createdb cf_topic_maps",


#        contain => as_user("mysql");


databases:

  "cf_topic_maps/topics"

    database_operation => "create",
    database_type => "sql",
    database_columns => { 
                        "topic_name,varchar,256",
                        "topic_comment,varchar,1024",
                        "topic_id,varchar,256",
                        "topic_type,varchar,256",
                        "topic_extra,varchar,26" 
                        },

    database_server => myserver;



}

################################################


body database_server myserver
{
any::
 db_server_owner => "postgres";
 db_server_password => "";
 db_server_host => "localhost";
 db_server_type => "postgres";
 db_server_connection_db => "postgres";
none::
 db_server_owner => "root";
 db_server_password => "";
 db_server_host => "localhost";
 db_server_type => "mysql";
 db_server_connection_db => "mysql";
}

body contain as_user(x)
{
exec_owner => "$(x)";
}


The promiser in database promises is a concatenation of the database name and underlying tables. This presents a simple hierarchical model that looks like a file-system. This is the normal structure within the Windows registry for instance. Entity-Relation databases do not normally present tables in this way, but no harm is done in representing them as a hierarchy of depth 1.


Next: , Previous: databases in agent promises, Up: databases in agent promises

7.2.1 database_server (body template)

Type: (ext body)

db_server_owner
Type: string

Allowed input range: (arbitrary string)

Synopsis: User name for database connection

Example:

     
     db_server_owner => "mark";
     

Notes:


db_server_password
Type: string

Allowed input range: (arbitrary string)

Synopsis: Clear text password for database connection

Example:

     
     db_server_password => "xyz.1234";
     

Notes:


db_server_host
Type: string

Allowed input range: (arbitrary string)

Synopsis: Hostname or address for connection to database, blank means localhost

Example:

     
     db_server_host => "sqlserv.example.org";
     

Notes:

Hostname or IP address of the server.

db_server_type
Type: (menu option)

Allowed input range:

                    postgres
                    mysql

Synopsis: The dialect of the database server

Default value: none

Example:

     
     db_server_type => "postgres";
     

Notes:


db_server_connection_db
Type: string

Allowed input range: (arbitrary string)

Synopsis: The name of an existing database to connect to in order to create/manage other databases

Example:

     
body database_server myserver(x)
     {
     db_server_owner => "$(x)";
     db_server_password => "";
     db_server_host => "localhost";
     db_server_type => "$(mysql)";
     db_server_connection_db => "$(x)";
     }
     

where ‘x’ is currently mysql or postgres.

Notes:

In order to create a database on a database server (all of which practice voluntary cooperation), one has to be able to connect to the server, however, without an existing database this is not allowed. Thus, database servers provide a default database that can be connected to in order to thereafter create new databases. These are called postgres and mysql for their respective database servers.

For the knowledge agent, this setting is made in the control body, for database verification promises, it is made in the database_server body.


Next: , Previous: database_server in databases, Up: databases in agent promises

7.2.2 database_type

Type: (menu option)

Allowed input range:

               sql
               ms_registry

Default value: none

Synopsis: The type of database that is to be manipulated

Example:

database_type => "ms_registry";

Notes:


Next: , Previous: database_type in databases, Up: databases in agent promises

7.2.3 database_operation

Type: (menu option)

Allowed input range:

               create
               delete
               drop
               cache
               verify
               restore

Synopsis: The nature of the promise - to be or not to be

Example:

database_operation => "create";

Notes:


Next: , Previous: database_operation in databases, Up: databases in agent promises

7.2.4 database_columns

Type: slist

Allowed input range: .*

Synopsis: A list of column definitions to be promised by SQL databases

Example:

  "cf_topic_maps/topics"

    database_operation => "create",
    database_type => "sql",
    database_columns => { 
                        "topic_name,varchar,256",
                        "topic_comment,varchar,1024",
                        "topic_id,varchar,256",
                        "topic_type,varchar,256",
                        "topic_extra,varchar,26" 
                        },

    database_server => myserver;

Notes:

Columns are a list of tuplets (Name,type,size). Array items are triplets, and fixed size data elements are doublets.


Next: , Previous: database_columns in databases, Up: databases in agent promises

7.2.5 database_rows

Type: slist

Allowed input range: .*,.*

Synopsis: An ordered list of row values to be promised by SQL databases

Example:

bundle agent databases

{
databases:

 windows::

  # Regsitry has (value,data) pairs in "keys" which are directories


  "HKEY_LOCAL_MACHINE\SOFTWARE\CFEngine AS\CFEngine"

    database_operation => "create",
    database_rows => { "value1,REG_SZ,new value 1", "value2,REG_DWORD,12345"} ,
    database_type     => "ms_registry";
}

Notes:

This constraint is used only in adding data to database columns. Rows are considered to be instances of individual columns.

In the case of the system registry on Windows, the rows represent data on data-value pairs. The currently supported types (the middle field) for the Windows registry are REG_SZ (string), REG_EXPAND_SZ (expandable string) and REG_DWORD (double word).


Previous: database_rows in databases, Up: databases in agent promises

7.2.6 registry_exclude

Type: slist

Allowed input range: (arbitrary string)

Synopsis: A list of regular expressions to ignore in key/value verification

Example:

databases:

 "HKEY_LOCAL_MACHINE\SOFTWARE"

    database_operation => "cache",

    registry_exclude => { ".*Windows.*CurrentVersion.*", 
                          ".*Touchpad.*",
                          ".*Capabilities.FileAssociations.*", 
                          ".*Rfc1766.*" , 
                          ".*Synaptics.SynTP.*", 
                          ".*SupportedDevices.*8086", 
                          ".*Microsoft.*ErrorThresholds" 
                        },

    database_type     => "ms_registry";

Notes:

During recursive Windows registry scanning, this option allows us to ignore keys of values matching a list of regular expressions. Some values in the registry are ephemeral and some should not be considered. This provdes a convenient way of avoiding names. It is analogous to exclude_dirs for files.


Next: , Previous: databases in agent promises, Up: Bundles for agent

7.3 environments promises in ‘agent


Environment promises are available in the CFEngine Nova Edition and above. Environment promises describe enclosed computing environments that can host physical and virtual machines, solaris zones, grids, clouds or other enclosures, including embedded systems. CFEngine will support the convergent maintenance of such inner environments in a fixed location, with interfaces to an external environment.

CFEngine currently seeks to add convergence properties to existing interfaces for automatic self-healing of virtualized environments. The current implementation integrates with libvirt, supporting host virtualization for Xen, KVM, VMWare, etc. Thus CFEngine, running on a virtual host, can maintain the state and deployment of virtual guest machines defined within the libvirt framework. Environment promises are not meant to manage what goes on within the virtual guests: for that purpose, you should run CFEngine directly on the virtual machine, as if it were any other machine.


 site1::

  "unique_name1"

       environment_resources => myresources("2GB","512MB"),
       environment_interface => mymachine("hostname"),
            environment_type => "xen",
            environment_state => "running",
            environment_host => "atlas";

  "unique_name2"

            environment_type => "xen_network",
           environment_state => "create",
            environment_host => "atlas";


CFEngine currently provides a convergent interface to libvirt.


Next: , Previous: environments in agent promises, Up: environments in agent promises

7.3.1 environment_host

Type: string

Allowed input range: [a-zA-Z0-9_$(){}.:-]+

Synopsis: A host for the virtual environment uniquely indicating which physical node will execute this machine

Example:

environments:

 linux::

 "host1"
                 comment => "Keep this vm suspended",
   environment_resources => myresources,
        environment_type => "kvm",
       environment_state => "suspended",
        environment_host => "ubuntu";

Notes:

History: this feature was introduced in Nova 2.0.0 (2010)


Next: , Previous: environment_host in environments, Up: environments in agent promises

7.3.2 environment_interface (body template)

Type: (ext body)

env_addresses
Type: slist

Allowed input range: (arbitrary string)

Synopsis: The IP addresses of the environment's network interfaces

Example:

     
body environment_interface vnet(primary)
     {
     env_name      => "$(this.promiser)";
     env_addresses => { "$(primary)" };
     
     host1::
     
       env_network => "default_vnet1";
     
     host2::
     
       env_network => "default_vnet2";
     
     }

Notes:

The IP addresses of the virtual machine can be overridden here at run time.

env_name
Type: string

Allowed input range: (arbitrary string)

Synopsis: The hostname of the virtual environment

Example:

     body environment_interface vnet(primary)
     {
     env_name      => "$(this.promiser)";
     env_addresses => { "$(primary)" };
     
     host1::
       env_network => "default_vnet1";
     
     host2::
       env_network => "default_vnet2";
     }

Notes:

The `hostname' of a virtual guest may or may not be the same as the identifier used as `promiser' by the virtualization manager.

env_network
Type: string

Allowed input range: (arbitrary string)

Synopsis: The hostname of the virtual network

Example:

     
body environment_interface vnet(primary)
          {
          env_name      => "$(this.promiser)";
          env_addresses => { "$(primary)" };
     
          host1::
            env_network => "default_vnet1";
     
          host2::
            env_network => "default_vnet2";
          }
     

Notes:


Next: , Previous: environment_interface in environments, Up: environments in agent promises

7.3.3 environment_resources (body template)

Type: (ext body)

env_cpus
Type: int

Allowed input range: 0,99999999999

Synopsis: Number of virtual CPUs in the environment

Example:

     
body environment_resources my_environment
     {
     env_cpus => "2";
     env_memory => "512"; # in KB
     env_disk => "1024";  # in MB
     }
     

Notes:

The maximum number of cores or processors in the physical environment will set a natural limit on this value. If the number is already set in a specification file, this value will attempt to override it at run time.

env_memory
Type: int

Allowed input range: 0,99999999999

Synopsis: Amount of primary storage (RAM) in the virtual environment (KB)

Example:

     
body environment_resources my_environment
     {
     env_cpus => "2";
     env_memory => "512"; # in KB
     env_disk => "1024";  # in MB
     }
     

Notes:

The maximum amount of memory in the physical environment will set a natural limit on this value. If the number is already set in a specification file, this value will attempt to override it at run time.

env_disk
Type: int

Allowed input range: 0,99999999999

Synopsis: Amount of secondary storage (DISK) in the virtual environment (MB)

Example:

     
body environment_resources my_environment
     {
     env_cpus => "2";
     env_memory => "512"; # in KB
     env_disk => "1024";  # in MB
     }
     

Notes:

This parameter is currently unsupported, for future extension.

env_baseline
Type: string

Allowed input range: "?(/.*)

Synopsis: The path to an image with which to baseline the virtual environment

Example:

     
     env_baseline => "/path/to/image";
     

Notes:

This function is for future development.

env_spec_file
Type: string

Allowed input range: "?(/.*)

Synopsis: The path to a file containing a technology specific set of promises for the virtual instance

Example:

     
body environment_resources virt_xml
     {
     env_spec_file => "/srv/xen/centos5-libvirt-create.xml";
     }
     
You may also quote the file as XML:
     body environment_resources virt_xml(host)
     {
     env_spec_file => 
     
     "<domain type='xen'>
       <name>$(host)</name>
       <os>
         <type>linux</type>
         <kernel>/var/lib/xen/install/vmlinuz-ubuntu10.4-x86_64</kernel>
         <initrd>/var/lib/xen/install/initrd-vmlinuz-ubuntu10.4-x86_64</initrd>
         <cmdline> kickstart=http://example.com/myguest.ks </cmdline>
       </os>
       <memory>131072</memory>
       <vcpu>1</vcpu>
       <devices>
         <disk type='file'>
           <source file='/var/lib/xen/images/$(host).img'/>
           <target dev='sda1'/>
         </disk>
         <interface type='bridge'>
           <source bridge='xenbr0'/>
           <mac address='aa:00:00:00:00:11'/>
           <script path='/etc/xen/scripts/vif-bridge'/>
         </interface>
         <graphics type='vnc' port='-1'/>
         <console tty='/dev/pts/5'/>
       </devices>
     </domain>
     ";
     }
     

Notes:

History: Was introduced in version 3.1.0b1,Nova 2.0.0b1 (2010)


Next: , Previous: environment_resources in environments, Up: environments in agent promises

7.3.4 environment_state

Type: (menu option)

Allowed input range:

               create
               delete
               running
               suspended
               down

Synopsis: The desired dynamical state of the specified environment

Example:

environments:

 linux::

 "bishwa-kvm1"
                 comment => "Keep this vm suspended",
   environment_resources => myresources,
        environment_type => "kvm",
       environment_state => "suspended",
        environment_host => "ubuntu";


Notes:

The allowed states have the following convergent semantics.

create
The guest machine is allocated, installed and left in a running state.
delete
The guest machine is shut down and de-allocated but no files are removed.
running
The guest machine is in a running state, if it previously exists.
suspended
The guest exists in a suspended state or a shutdown state. If the guest is running, it is suspended, else it is ignored.
down
The guest machine is shut down, but not de-allocated.


Previous: environment_state in environments, Up: environments in agent promises

7.3.5 environment_type

Type: (menu option)

Allowed input range:

               xen
               kvm
               esx
               test
               xen_net
               kvm_net
               esx_net
               test_net
               zone
               ec2
               eucalyptus

Synopsis: Virtual environment type

Example:

bundle agent my_vm_cloud
{
environments:

 scope::

   "vguest1"

       environment_resources => my_environment_template,
       environment_interface => vnet("eth0,192.168.1.100/24"),
       environment_type      => "test",
       environment_state     => "create",
       environment_host      => "atlas";

   "vguest2"

       environment_resources => my_environment_template,
       environment_interface => vnet("eth0,192.168.1.101/24"),
       environment_type      => "test",
       environment_state     => "delete",
       environment_host      => "atlas";
}

Notes:

The currently supported types are those supported by libvirt. More will be added as time goes on.


Next: , Previous: environments in agent promises, Up: Bundles for agent

7.4 files promises in ‘agent


Files promises are an umbrella concept for all attributes of files. Operations fall basically into three categories: create, delete and edit.

     
      files:
     
        "/path/file_object"
     
            perms => perms_body,
            ... ;
     

Prior to version 3, file promises were scattered into many different types such as files, tidy, copy, links, etc. File handling in CFEngine 3 uses regular expressions everywhere for pattern matching. The old `wildcard/globbing' expressions ‘*’ and ‘?’ are deprecated, and everything is based consistently on Perl Compatible Regular Expressions.

There is a natural ordering in file processing that obviates the need for the actionsequence. The trick of using multiple actionsequence items with different classes, e.g.

 actionsequence = ( ... files.one  ..  files.two )

can now be handled more elegantly using bundles. The natural ordering uses that fact that some operations are mutually exclusive and that some operations do not make sense in reverse order. For example, editing a file and then copying onto it would be nonsense. Similarly, you cannot both remove a file and rename it.

File copying

One of the first things users of CFEngine 2 will notice is that copying is now `backwards'. Instead of the default object being source and the option being the destination, in CFEngine 3 the destination is paramount and the source is an option. This is because the model of voluntary cooperation tells us that it is the object that is changed which is the agent making the promise. One cannot force change onto a destination with CFEngine, one can only invite change from a source.

Normal ordering of promise attributes

CFEngine 3 no longer has an `action sequence'. Ordering of operations has, in most cases, a natural ordering which is assumed by the agent. For instance: `delete then create' (normal ordering) makes sense, but `create then delete' does not. This sort of principle can be extended to deal with all aspects of file promises.

The diagram below shows the ordering. Notice that the same ordering applies regardless of file type (plain-file or directory). Note also that file editing is done "atomically" (see `File editing in CFEngine 3' for important details).