Forum: CFEngine Help Subject: Re: 3.1.4 => 3.3.4: has something changed regarding classes in bundles? Author: davidlee Link to topic: https://cfengine.com/forum/read.php?3,26274,26278#msg-26278
I've been doing a little more digging. I think the main fault is a long-standing one in the COPBL "set_variable_values()". A coding bug in the old code (e.g. 3.1.4) masked it; some sort of coding change (probably to fix other manifestations of that underlying bug) since then now exposes it. Firstly, from the manual: ==================== Another type of class definition happens when you define classes based on the outcome of a promise, e.g. to set a class if a promise is repaired, one might write: "promiser..." ... classes => if_repaired("signal_class"); These classes are global in scope. [...] ==================== Note that final "global in scope". This suggests that a class that is set in this manner in the depths of one call to "set_variable_values" SHOULD be preserved, and could be expected to affect subsequent actions. Here is COPBL's "set_variable_values" (slightly simplified for clarity here): ==================== bundle edit_line set_variable_values(v) { vars: "index" slist => getindices("$(v)"); # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); field_edits: # match a line starting like the key = something "\s*$(index)\s*=.*" edit_field => col("=","2","$($(v)[$(index)])","set"), classes => if_ok("$(cindex[$(index)])_in_file"), comment => "Match a line starting like key = something"; insert_lines: "$(index)=$($(v)[$(index)])", comment => "Insert a variable definition", ifvarclass => "!$(cindex[$(index)])_in_file"; } ==================== Focus on those two "XXX_in_class" occurrences. Suppose the user edits two similar files, using similar data, e.g. pattern "v => VALUE1" etc. Suppose, too, that the first file already includes a "KEY1..." line, and the second does not have such a line. Then the first file will use the "field_edits" section, and will set a class "KEY1_in_file". (It will also be prevented from using its "insert_lines" section, which is exactly want we want.) Good. But the problem is the class "KEY1_in_file" is globally scoped. So what happens next? In the second file, which lacks "KEY1", the user would expect a "KEY1" line to be inserted. But the "KEY1_in_file" is still lurking from the distant past on the first file; it will prevent the use of "insert_lines" on the second file, even though the user's intention is that it should insert the line. So it looks like the older version of cfengine was doing what the user intended, but by accident. The newer version is behaving in the technically correct fashion (according to the manual page), but not how the user intended. To test this, I made a private copy of "set_variable_values()", but instead of calling the class (on its two occurrences) "XXX_in_file", I called it "XXX_in_$(edit.filename)". (I used "XXX" there merely as shorthand for clarity; my new class is actually "$(cindex[$(index)])_in_$(edit.filename)".) This version seems to behave as the user intends for both 3.1.4 and 3.3.4. Summary: Old code had a bug, "set_variable_values()" also has a bug. Old combination worked as the user expected, but by accident. New code corrects its own bug, but now exposes the "set_variable_values()" bug. Suggested fix: "set_variable_values()" should include $(edit.filename) in the class it sets. _______________________________________________ Help-cfengine mailing list Help-cfengine@cfengine.org https://cfengine.org/mailman/listinfo/help-cfengine