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
[email protected]
https://cfengine.org/mailman/listinfo/help-cfengine