> How do I know if vars or classes come first during cfengine evaluation?

Read the documentation on Normal Order

There is a wealth of information on docs.cfengine.com. Find documentation about the order of agent promise evaluation (Normal Order) in the Language Concepts section of the Reference manual.

Run the agent with --verbose or -v and grep for pass 1.

Write a test policy that has both vars and classes promises.

1
2
3
4
5
6
7
8
  bundle agent main
  {
   vars:
      "question" string => "What comes first, vars or classes?";

   classes:
      "grep_verbose_output_for_pass_1" expression => "any";
  }

Grep the verbose output.

1
2
  chmod 600 /tmp/test.cf 
  cf-agent -Kvf /tmp/test.cf | grep "pass 1"
 verbose: V: BEGIN variables (pass 1)
 verbose: C: BEGIN classes / conditions (pass 1)

Write policy that tells you

This policy uses conditionals to determine if classes are evaluated before variables, or if variables are evaluated first. It shows the determination using reports guarded on the class that describes which is evaluated first.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  bundle agent main
  #@ brief Demonstrate if vars or classes come first
  {
    classes:
        "classes_are_first" expression => not( isvariable( "main.classes_are_first" ) );
        "vars_are_first" expression => isvariable( "main.vars_are_first" );

    vars:
        "classes_are_first" string => "Classes come first";
        "vars_are_first" string => "Vars come first", if => not( "vars_are_first" );

    reports:
      "CFEngine $(sys.cf_version)";

      "$(classes_are_first)"
        if => "classes_are_first";

      "$(vars_are_first)"
        if => "vars_are_first";

  }
R: CFEngine 3.11.0
R: Vars come first
R: Without intermediary vars: ifelse: Vars come first

You can use the with attribute and ifelse() to reduce the policy a bit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    bundle agent main
    #@ brief Demonstrate if vars or classes come first
    {
      classes:
          "classes_are_first" expression => not( isvariable( "main.variable" ) );
          "vars_are_first" expression => isvariable( "main.vars_are_first" );

      vars:
          "classes_are_first" string => "Classes come first";
          "vars_are_first" string => "Vars come first", if => not( "vars_are_first" );

      reports:
        "CFEngine $(sys.cf_version)";

        "Without intermediary vars: $(with)"
          with => ifelse( classes_are_first, "ifelse: Classes come first",
                          vars_are_first, "ifelse: Vars come first",
                          "Logic Error" );

    }
R: CFEngine 3.11.0
R: Without intermediary vars: ifelse: Classes come first