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

Reply via email to