In CFEngine classes are used for decision making. Classes can be defined as the result of a promise by attaching a classes body to the promise via the /classes/ attribute.

For example, here we run the command echo Hello World and define bundle scoped classes using the results classes body prefixed with Hello_World.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  bundle agent main
  {
     commands:
       "echo Hello World" 
         contain => in_shell,
         classes => results( "bundle", "Hello_World" );

     reports:  
      "Defined Classes: $(with)" with => join( ", ", classesmatching( "Hello_.*" )  );
  }

Note in the policy output, we see Hello_World_repaired and Hello_World_reached are defined.

  notice: Q: "...echo Hello Worl": Hello World
R: Defined Classes: Hello_World_repaired, Hello_World_reached

Sometimes people ask:

Can I automatically define classes for every promise?

This is possible since CFEngine 3.9.0 introduced the concept of default bodies. Default bodies allow the definition of bodies in the bodydefault namespace that will be used with a promise any time a promise does not specify a body of that type. For example, we can define body classes commands_classes that will be used for any commands promise that does not specify a specific classes body. This results in the commands_classes body being attached to any commands promise which does not use an explicit classes body.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  bundle agent main
  {

    commands:
        "echo Hello"
          handle => "command_echo_hello",
          contain => in_shell;

        "echo GoodBye"
          handle => "command_echo_GoodBye",
          contain => in_shell,
          classes => results( "namespace", "GoodBye" );

    vars:
        "c" slist => classesmatching( ".*_(reached|repaired|kept|not_kept|error)" );

    reports:
       "$(c)";
  }

  body file control
  {
          namespace => "bodydefault";
  }

  body classes commands_classes
  {
    scope => "namespace";

    promise_kept => { "$(this.handle)_reached",
                      "$(this.handle)_kept" };

    promise_repaired => { "$(this.handle)_reached",
                          "$(this.handle)_repaired" };

    repair_failed => { "$(this.handle)_reached",
                       "$(this.handle)_error",
                       "$(this.handle)_not_kept",
                       "$(this.handle)_failed" };

    repair_denied => { "$(this.handle)_reached",
                       "$(this.handle)_error",
                       "$(this.handle)_not_kept",
                       "$(this.handle)_denied" };

    repair_timeout => { "$(this.handle)_reached",
                        "$(this.handle)_error",
                        "$(this.handle)_not_kept",
                        "$(this.handle)_timeout" };
  }

Here is the policy output. We can see that the commands promise to echo Hello resulted in the definition of command_echo_hello_repaired and command_echo_hello_reached because it used body classes commands_classes (the default classes body for commands promises).

  notice: Q: "...echo Hello": Hello
  notice: Q: "...echo GoodBye": GoodBye
R: command_echo_hello_repaired
R: GoodBye_repaired
R: command_echo_hello_reached
R: GoodBye_reached