Processes and Executions

In cfengine 2, we have two separate actions:
 processes
 shellcommands
In cfengine 3 we have
 processes
 executions
Cfengine 2 got this ontology about right intuitively, but not quite. It allowed "restart" in a process promise which is really a execution of a file object. This has been changed in cfengine 3 so that there is a cleaner separation. Let's see why. Executions are about jobs, services, scripts etc. They are properties of an executable file. The referring "promising agent" is a file object. On the other hand a process is a property of a "process identifier" which is a kernel instantiation, a quite different object altogether. So it makes sense to say that Neither the file nor the pid necessarily promise to respond to these activations, but they are nonetheless physically meaningful phenomena or attributes associated with these objects. Executions lead to processes for the duration of their lifetime, so these two issues are related, although the promises themselves are not.

Services

A service is an abstraction that requires processes to run and files to be configured. It makes a lot of sense to wrap services in modular bundles. Starting and stopping a service can be handled in at least two ways. Take the web service as an example. We can start the service by promising an execution of the apache daemon. Normally this execution does not terminate without intervention. We can terminate it in one of two ways: The first case makes sense if we need to qualify the termination by searching for the processes. The processes section of a cfengine 3 policy includes a control promise to search for matching processes. If matches are found, signals can be sent to precisely each specific process. Classes can also be defined, in principle triggering an execution of the stop script, but then the class refers only to the presence of matching pids, not to the individual pids concerned. So it becomes the responsibility of the execution to locate and interact with the pids necessary.

Want it running

How do we say simply that we want a service running In the agent control promises, we could check each service individually.
bundlesequence => { Update, Service("apache"), Service("nfsd") };
or
bundlesequence => { Update, @(globals.all_services)  };
bundle agent Service("$(service)")

{
processes:

  "$(service)" 

      process_count => up("$(service)");

executions:

   "$daemons[$(service)]"  

      ifvarclass => "$(service)_up",
      args       => "$args[$(service)]";

}

An alternative would be self-contained:
bundle agent Service

{
vars:

  "service" slist => { "apache", "nfsd", "bind" };

processes:

  "$(service)" 

      process_count => up("$(service)");

executions:

   "$daemons[$(service)]"  

      ifvarclass => "$(service)_up",
      args       => "$args[$(service)]";

}

######################
# Parameterized body
######################

body process_count("$(s)")

{
match_range => "[0,10]";
out_of_range_define => "$(s)_up";
}

A step backwards?

The cfengine 3 approach might seem like a step backwards from the simple:
processes:

  "httpd" restart "/etc/init.d/apache restart"
However, it allows several improvements. You can do other things in between stopping and starting the service, like file editing, or security sweeps. You can use templates to simplify the syntax in bulk for several process checks or restarts. processes: "$(service.list)" If you don't want any delay in stopping and starting the service, then place these promises in a private bundle with nothing in between them.
Mark Burgess
Last modified: Thu May 1 17:06:38 CEST 2008