Hi folks,
I have a question concerning scope of classes in CFEngine 3. I run CFE 3.10.2 on CentOS 7.4.
# cf-agent -V CFEngine Core 3.10.2
# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core)
I'm logged in as root and located in current working dir /root. I have the following file
# ll ./samples/scope_of_class.cf -rwx------. 1 root root 720 10. Jul 16:33 ./samples/scope_of_class.cf
with content
----BEGIN---------------------------------- bundle agent scope_of_class() {
vars: any:: "web_servers" slist => { "ws-1.example.com", "ws-2.example.com", "webserver.example.com", };
methods: any:: "scope_of_class_b1" usebundle => scope_of_class_b1( $(scope_of_class.web_servers) );
}
bundle agent scope_of_class_b1( server ) {
classes: any:: "is_dir" expression => isdir( "/tmp/scope_of_class/$(server)" ), scope => "bundle";
reports: is_dir:: "is_dir is SET"; !is_dir:: "is_dir is UNset"; any:: "server = $(server)";
} ----END------------------------------------
From my understanding the scope "bundle" is default for a class definition inside a bundle of type agent, but I added the scope to be sure. The definition of class is_dir should depend on directories existing inside /tmp/scope_of_class. I have two subdirectories
# ls -1 /tmp/scope_of_class/ webserver.example.com ws-1.example.com
but when I run CFE I do NOT get expected behaviour for the definition of class is_dir:
# cf-agent -IK --file ./samples/scope_of_class.cf --bundlesequence scope_of_class info: Using command line specified bundlesequence R: is_dir is SET R: server = ws-1.example.com R: is_dir is UNset R: server = ws-2.example.com R: server = webserver.example.com
When the bundle scope_of_class_b1 is processed for parameter webserver.example.com I expect is_dir to bet set, but from the report it seems not to be set.
If I change the slist definition to hold "webserver.example.com" as the first entry, then the class is_dir is set correctly:
# grep slist ./samples/scope_of_class.cf -A 4 "web_servers" slist => { "webserver.example.com", "ws-1.example.com", "ws-2.example.com", }; # cf-agent -IK --file ./samples/scope_of_class.cf --bundlesequence scope_of_class info: Using command line specified bundlesequence R: is_dir is SET R: server = webserver.example.com R: server = ws-1.example.com R: is_dir is UNset R: server = ws-2.example.com
It also works "correct" (or as expected by me) if "ws-2.example.com" is first entry in the slist definition:
# grep slist ./samples/scope_of_class.cf -A 4 "web_servers" slist => { "ws-2.example.com", "ws-1.example.com", "webserver.example.com", }; # cf-agent -IK --file ./samples/scope_of_class.cf --bundlesequence scope_of_class info: Using command line specified bundlesequence R: is_dir is UNset R: server = ws-2.example.com R: is_dir is SET R: server = ws-1.example.com R: server = webserver.example.com
I do not understand why the ordering inside slist influences how the class is_dir will be defined later by CFE for each processing of scope_of_class_b1.
Some background information: my aim is to create webserver vhost configuration files where I have two variants, one with SSL configuration and one without SSL configuration. Which one to configure depends if the directory with the SSL certificate exists for a given vhost or not. I'll replace the report promise type by a file promise type, which should bring the correct vhost configuration file in place, assumed that I understand how the scope of the class definition works.
Thanks in advance for any help or explanation of that behaviour.
Regards,
Meikel
Am 10.07.2019 um 18:07 schrieb Meikel:
Thanks in advance for any help or explanation of that behaviour.
Hi folks,
yesterday in the IRC I got an answer which explains everything for me, so from my point of view my question is answered and the problem is solved.
In short with my words:
The bundle scope_of_class_b1 is called one time for each entry in the slist, so it is called three times.
The promisee of the "reports" type is
"is_dir is SET"
and even if the class "is_dir" is set in two of the three executions, the "report" is print out only once, because the promisee is the same, and a promise for the same promisee is only kept/repaired/executed only once in an agent run. To get the expected output the promisee of the "reports" has to be rewritten to become unique for each execution, i.e. adding $(server) like this:
reports: is_dir:: "is_dir is SET"; is_dir:: "$(server): is_dir is SET"; !is_dir:: "$(server): is_dir is UNset";
I kept "is_dir is SET" to better show the difference. It gives the following result:
# cf-agent -IK --file ./samples/scope_of_class.cf --bundlesequence scope_of_class info: Using command line specified bundlesequence R: is_dir is SET R: ws-1.example.com: is_dir is SET R: ws-2.example.com: is_dir is UNset R: webserver.example.com: is_dir is SET
The output "is_dir is SET" is never shown more than once in one agent run, even if all three directories exist, but if the promisee becomes unique, i.e. "ws-1.example.com: is_dir is SET" vs. "webserver.example.com: is_dir is SET" then they're both print out.
The problem is NOT, that the definition/evaluation of the class "is_dir" does not work as expected, it works as expected, but I didn't see it in the output, because my expectation of what to see was wrong.
As I don't have skills in CFE my wording might be imprecise, I'm sorry, hopefully the idea became clear.
Regards,
Meikel