Forum: Cfengine Help Subject: Promise outcomes flip-flopping during runtime Author: Authority Link to topic: https://cfengine.com/forum/read.php?3,17077,17077#msg-17077
I was trying to write a classes body that would ensure that one, and only one, of two classes would be set based on the outcome of a promise. I start with the concept of a "YES" class and a "NO" class. If the promise is kept or repaired, I want the "YES" class set and for completeness' sake, the "NO" class to be cancelled (even though it should have never been added anyway). If the promise was not kept, it should trigger the "NO" class and cancel the "YES." And being a fan of verboseness, I began by adding every possible attribute to my classes body to leave no ambiguity of what was happening. Unfortunately, I got quite the opposite. I've found that a promise would be called kept even if the repair failed, which was making for a very difficult time trying to determine why my promises were not doing what I expected. Based on my own logic and the implied logic of the classes body (as I'm not a source code guy), it would seem to me that if the repair failed a promise should not be called "kept" at any point. Cfengine seems to be a bit premature in calling a promise kept. The following input file demonstrates what I've found: body common control { bundlesequence => { "test" }; } bundle agent test { files: "/tmp/touchme" touch => "true" , classes => xor("yes"); "/tmp/notouching" touch => "true" , classes => xor("no"); reports: yes_YES:: "YES!"; yes_NO:: "NO?"; no_YES:: "YES?"; no_NO:: "NO!"; } body classes xor(str) { promise_repaired => { "$(str)_YES" }; promise_kept => { "$(str)_YES" }; #cancel_notkept => { "$(str)_YES" }; repair_failed => { "$(str)_NO" }; repair_denied => { "$(str)_NO" }; repair_timeout => { "$(str)_NO" }; #cancel_kept => { "$(str)_NO" }; #cancel_repaired => { "$(str)_NO" }; } My "xor" classes body if very similar to the "if_else" classes body from the COBPL (which has an undeclared variable in the copy included in the 3.0.4 source) except I've added the promise_kept attribute because I want the "YES" class to be effective whether corrective action had to be taken or not. In order to make the 2nd touch promise to fail, I've set the immutable attribute on the file (chattr +i). # cf-agent -IKf ./xor_classes.cf -> Touched (updated time stamps) /tmp/touchme Touch /tmp/notouching failed to update timestamps !!! System reports error for utime: "Permission denied" R: YES! R: YES? R: NO! As you can see, both the kept and failure classes are set for the 2nd promise. If I then add the cancel_notkept attribute, it will cancel the "YES" class and give me what I'm expecting (at least in this case). If I then add in the cancel_kept and cancel_repaired attributes, both outcomes are cancelled since the promise is first marked kept, cancelling the "NO," and then marked unkept, cancelling the "YES" and not resetting the "NO." I guess the normal ordering of classes bodies is something along the lines of "Kept or not? Failed or not? Apply cancels." Now since English is the only language I speak (silly American, I know), I tend to think I have a pretty good understanding of it (although I probably use commas too much) and the English construction of logic and this just doesn't make sense. Even Cfengine's own logic seems to correspond to my own since it obviously considers the promise "not kept" when it triggers the "cancel_notkept" class, but after first triggering the "promise_kept" or "promise_repaired" class. If you don't have the "cancel_notkept" attribute, you can have a failed promised marked as kept. Does that really make sense and/or is there some use case for this sort of convoluted logic? Once again I find myself asking, is this a failure of my own logic or Cfengine's? I, of course, tend to think the latter. _______________________________________________ Help-cfengine mailing list Help-cfengine@cfengine.org https://cfengine.org/mailman/listinfo/help-cfengine