terms of goals rather than “building
projects”—thus also bringing us closer to a modern IT industry.
>10kb of complex stuff
convergence to a Desired state
Setting up a reference model for repair
sounds like a simple matter, but it requires a language with the right properties. Common languages used in software engineering are not well suited
for the task, as they describe sequential
steps from a fixed beginning rather
than end goals. Generally, we don’t
know the starting state of a machine
when it fails. Moreover, a lot of redundant computation is required to track a
model, and that would intrude on clarity. The way around this has been to construct declarative DSLs (
domain-specific languages) that hide the details and
offer predictable semantics. Although
Cfengine was the first attempt to handle indeterminism, special languages
had been proposed even earlier. 9
Many software engineers are not
convinced by the declarative DSL ar-
gument: they want to use the famil-
iar tools and methods of traditional
programming. For a mathematician
or even a carpet fitter, however, this
makes perfect sense. If you are trying
to fit a solution to a known edge state,
it is cumbersome to start at the oppo-
site end with a list of directions that as-
sume the world is fixed. When you pro-
gram a GPS, for example, you enter the
desired destination, not the start of the
journey, because you often need to re-
compute the path when the unexpected
occurs, such as a closed road. This GPS
approach was taken by Cfengine5 in the
mid-1990s. It says: work relative to the
desired end-state of your model, not an
initial baseline configuration, because
the smallest unexpected change breaks
a recipe based on an initial state. This
has been likened to Prolog. 7
>10kB of complex stuff
MODULES = JAVA OTHERS PHP
# >10kB of complex stuff
Change (arbitrary_state) → desired_state ( 1)
Change (desired_state) → desired_state ( 2)
This construction is an expression
of “dumb” stability, because if you perturb the desired state into some arbitrary state, it just gets pushed back into
the desired state again, like an automated course correction. It represents
a system that will recover from accidental or incidental error, just by repeating
a dumb mantra—without the need for
intelligent reasoning.
For example: suppose you want to
reconfigure a Web server to support
PHP and close a security hole. The server and all of its files are typically part of
a software package and is configured
by a complex file with many settings:
>10kB of complex stuff
MODULES = SECURITY _ HOLE JAVA
OTHERS
figure 1. Reconfiguring a Web server in cfengine.
bundle agent webserver_config
{
vars:
“add” slist => { “PHP”, “php5” };
“del” slist => { “SECURITY_HOLE”, “otherstuff” };
column_edits:
“APACHE_MODULES=.*”
edit_column => edit_listvar(“$(add_modules)”,”append”);
Traditionally, one replaces the
whole file with a hand-managed template or even reinstalls a new package,
forcing the end user to handle everything from the ground up. Using a desired state approach, we can simple
say: in the context of file webserv-er.config, make sure that any line
matching “MODULES = something”
is such that “something” contains
“PHP” and does not contain “
SECURITY HOLE.” Figure 1 illustrates how this
might look in Cfengine.
Thus, the code defines two internal list variables for convenience and
passes these to the specially defined
method edit_ listvar, which is constructed from convergent primitives.
For each item in the list, Cfengine will
assure the presence or absence of the
listed atoms without touching anything else. With this approach, you
don’t need to reconstruct the whole
Web server or know anything about
how it is otherwise configured (for example, what is in “complex stuff”)
or even who is managing it: a desired
end-state relative to an unknown start-state has been specified. It is a highly
compressed form of information.
I referred to this approach as
convergent maintenance (also likening
the behavior to a human immune
system2), as all changes converge on
a destination or healthy state for the
system in the frame of reference of the
policy. Later, several authors adopted
the mathematical term idempotence
(meaning invariance under repetition),
focusing on the fact that you can apply
these rules any number of times and
the system will only get better.
type_of_promise:
“Atom”
property_type => desired_end_state;
]
Guarded Policy
In the most simplistic terms, this approach amounts to something like
Dijkstra’s scheme of guarded commands. 8 Indeed, Cfengine’s language
implementation has as much in common with Guarded Command Lan-