question about body inheritance

57 views
Skip to first unread message

Xander Cage

unread,
Apr 20, 2021, 7:51:59 AM4/20/21
to help-cfengine

hi,

this topic puzzles me for quite a long time.

lets say i have this classes body:

body classes set_some_fancy_classes ( x, y)
{
promise_kept => { "some_fancy_class_${x}_ ${y} _kept" };
promise_repaired => { "some_fancy_class _${x}_ ${y} _repaired" }; 
repair_failed => { "some_fancy_class _${x}_ ${y} _notkept" };
repair_denied => { "some_fancy_class _${x}_ ${y} _notkept" };
repair_timeout => { "some_fancy_class _${x}_ ${y} _notkept" };
}

which is used like this:

commands:
   "/bin/true"
       handle => "some meaningful string",
       classes => set_some_fancy_classes( "$(this.promiser)", "$(this.handle)" );

so far so good, the one thing that i dont get is, how do i set "additional" classes in this scenario, for example i want to set another class  like this (not handled by the mentioned classes body):

commands:
    "/bin/true"
        handle => "some meaningful string",
        classes => set_some_fancy_classes( "$(this.promiser)", "$(this.handle)" ),
        classes = if_repaired("some_class_ to_handle_dependencies");

problem is, "last one wins" rule is firing, so no luck here.

i read about the "inherit_from" attribute, but i have no clue how to implement this or if it is possible anyway. the documentation / examples left me clueless.

i want to set the classes from the " set_some_fancy_classes" body PLUS the class from the "if_repaired" attribute.

wbr

chris

Nick Anderson

unread,
Apr 20, 2021, 4:54:18 PM4/20/21
to Xander Cage, help-cfengine

Hi Chris,

Right, you should not attach multiple of the same attribute to the same promise. Perhaps we should make the parser disallow it all together because it's not an expected use.

I believe this example implements what you are looking for.

We define a new classes body my_set_some_extra_fancy_classes, it takes 3 arguments where the third argument is an additional class to set when the promise is repaired. Note, since we are setting promise_repaired differently in my_set_some_extra_fancy_classes than my_set_some_fancy_classes we have to completely re-define it.

bundle agent __main__
{
  commands:
      "/bin/true"
        handle => "some meaningful string"
,
        classes => my_set_some_extra_fancy_classes( "$(this.promiser)",
                                              "$(this.handle)",
                                              "some_class_to_handle_dependencies" );

      "/bin/false"
        handle => "some meaningless string",
        classes => my_set_some_extra_fancy_classes( "$(this.promiser)",
                                              "$(this.handle)",
                                              "some_class_to_handle_dependencies" );
}

body classes my_set_some_extra_fancy_classes( x, y, z)
# @breif In addition to the classes set by `set_some_fancy_classes` define `z` when the promise is repaired 
{
        inherit_from => set_some_fancy_classes( $(x), $(y) );
        promise_repaired => { "some_fancy_class_${x}_${y}_repaired", $(z) };
}

body classes set_some_fancy_classes ( x, y)
{
        promise_kept => { "some_fancy_class_${x}_${y}_kept" };
        promise_repaired => { "some_fancy_class_${x}_${y}_repaired" };
        repair_failed => { "some_fancy_class_${x}_${y}_notkept" };
        repair_denied => { "some_fancy_class_${x}_${y}_notkept" };
        repair_timeout => { "some_fancy_class_${x}_${y}_notkept" };
}

# cf-agent --no-lock --log-level info --show-evaluated-classes=some_ --file example.cf
    info: Executing 'no timeout' ... '/bin/true'
    info: Completed execution of '/bin/true'
    info: Executing 'no timeout' ... '/bin/false'
   error: Finished command related to promiser '/bin/false' -- an error occurred, returned 1
    info: Completed execution of '/bin/false'
Class name                                                   Meta tags                               
some_class_to_handle_dependencies                                                                    
some_fancy_class__bin_false_some_meaningless_string_notkept                                          
some_fancy_class__bin_true_some_meaningful_string_repaired                                           

Here I use --show-evaluated-classes which lists the namespace scoped classes defined at the end of the agent run filtered for those starting with some_. We can see that both some_class_to_handle_dependencies and some_fancy_class__bin_true_some_meaningful_string_kept get defined.

# cf-agent --no-lock --log-level info --show-evaluated-classes=some_ --file example.cf
    info: Executing 'no timeout' ... '/bin/true'
    info: Completed execution of '/bin/true'
Class name                                                   Meta tags                               
some_class_to_handle_dependencies                                                                    
some_fancy_class__bin_true_some_meaningful_string_kept                                               

Xander Cage

unread,
Apr 21, 2021, 3:06:34 AM4/21/21
to help-cfengine
wow, this qualifies as advanced sorcery :),  await the owl with the hogwarts acceptance letter.

thank you

chris

Nick Anderson

unread,
Apr 21, 2021, 9:40:16 AM4/21/21
to Xander Cage, help-cfengine

Xander Cage <christia...@itsv.at> writes:

wow, this qualifies as advanced sorcery :), await the owl with the hogwarts acceptance letter.

thank you

Great, glad you found it helpful. I can take that example and include it in the docs.

dumbledore-pensive.gif

Xander Cage

unread,
May 4, 2021, 10:00:24 AM5/4/21
to help-cfengine
today i tried this theorem in a more practically orientated context, and i was confronted with a somewhat peculiar behaviour.
one difference is, that the two classes bodies are in an  imported file (custom library file)  and not  directly in the bundle/promise file, but i guess this should not provoke any troubles.

body classes itsv_custom_classes ( promiser, handle )
{
      promise_kept      => { "${promiser}_handle_${handle}_kept" };
      promise_repaired  => { "${promiser}_handle_${handle}_repaired" };
      repair_failed     => { "${promiser}_handle_${handle}_notkept" };
      repair_denied     => { "${promiser}_handle_${handle}_notkept" };
      repair_timeout    => { "${promiser}_handle_${handle}_notkept" };
}

body classes itsv_keeper_of_the_classes ( promiser, handle, workflow_class)
# @brief: In addition to the classes set by "itsv_custom_classes", define "workflow_class" when the promise is repaired.
# mainly used for keeping already existing classes in the policys when activating reporting.
# see discussion: https://groups.google.com/g/help-cfengine/c/WpDuScsMxxI
{
        inherit_from => itsv_custom_classes( $(promiser), $(handle) );
        promise_repaired => { "${workflow_class}_repaired", $(workflow_class) };

}

test bundle:

bundle agent b005_reporting_output_test

{

 meta:
    "tags"  slist => { "itsv" };


 commands:
      "/bin/true"
        handle    => "itsv_reporting_$(this.bundle)",
        #classes   => itsv_keeper_of_the_classes( "$(this.promiser)", "$(this.handle)", itsv_TEST_WORKFLOW_CLASS ),
        classes   => itsv_custom_classes( "$(this.promiser)", "$(this.handle)" ),

        action    => itsv_reporting( "$(this.handle)", "$(this.promiser)", "ITSV Cfengine", "1" );
}

this works as expected:

root@aixtest01: /var/cfengine/masterfiles/itsv # /var/cfengine/bin/cf-agent -KI --show-evaluated-classes=itsv_
info: Executing 'no timeout' ... '/bin/true'
info: Completed execution of '/bin/true'
R: autorun is executing
R: default:b005_reporting_output_test: found bundle default:b005_reporting_output_test
 Class name                                                   Meta tags
_bin_true_handle_itsv_reporting_b005_reporting_output_test_repaired

edited bundle with the inhere_from body:

bundle agent b005_reporting_output_test

{

 meta:
    "tags"  slist => { "itsv" };


 commands:
      "/bin/true"
        handle    => "itsv_reporting_$(this.bundle)",
        classes   => itsv_keeper_of_the_classes( "$(this.promiser)", "$(this.handle)", itsv_TEST_WORKFLOW_CLASS ),
        #classes   => itsv_custom_classes( "$(this.promiser)", "$(this.handle)" ),

        action    => itsv_reporting( "$(this.handle)", "$(this.promiser)", "ITSV Cfengine", "1" );
}

output:

root@aixtest01: /var/cfengine/masterfiles/itsv # /var/cfengine/bin/cf-agent -KI --show-evaluated-classes=itsv_

info: Executing 'no timeout' ... '/bin/true'
 info: Completed execution of '/bin/true'
R: autorun is executing
R: default:b005_reporting_output_test: found bundle default:b005_reporting_output_test
Class name                                                   Meta tags
itsv_TEST_WORKFLOW_CLASS
itsv_TEST_WORKFLOW_CLASS_repaired
itsv_reporting                                               source=promise

itsv_TEST_WORKFLOW_CLASS is defined twice (with and without "_repaired" prefix), which does not correlate with the your example.
the class ( _bin_true_handle_itsv_reporting_b005_reporting_output_test_repaired
) which should be inherited from the " itsv_custom_classes" body is missing.

seems the two body are not playing well together.

so, any idea whats going on?

Nick Anderson

unread,
May 4, 2021, 10:49:52 AM5/4/21
to Xander Cage, help-cfengine

Xander Cage <christia...@itsv.at> writes:

seems the two body are not playing well together.

so, any idea whats going on?

Can you make it a standalone example, I don't have itsv_reporting.

bundle agent __main__{ methods: "b005_reporting_output_test"; }
bundle agent b005_reporting_output_test

{

 meta:
    "tags"  slist => { "itsv" };


 commands:
      "/bin/true"
        handle    => "itsv_reporting_$(this.bundle)",
        classes   => itsv_keeper_of_the_classes( "$(this.promiser)", "$(this.handle)", itsv_TEST_WORKFLOW_CLASS ),
        #classes   => itsv_custom_classes( "$(this.promiser)", "$(this.handle)" ),
        action    => itsv_reporting( "$(this.handle)", "$(this.promiser)", "ITSV Cfengine", "1" );
}

body classes itsv_custom_classes ( promiser, handle )
{
        promise_kept      => { "${promiser}_handle_${handle}_kept" };
        promise_repaired  => { "${promiser}_handle_${handle}_repaired" };
        repair_failed     => { "${promiser}_handle_${handle}_notkept" };
        repair_denied     => { "${promiser}_handle_${handle}_notkept" };
        repair_timeout    => { "${promiser}_handle_${handle}_notkept" };
}

body classes itsv_keeper_of_the_classes ( promiser, handle, workflow_class)
# @brief: In addition to the classes set by "itsv_custom_classes", define
# "workflow_class" when the promise is repaired.
#
# mainly used for keeping already existing classes in the policys when activating reporting.
# see discussion: https://groups.google.com/g/help-cfengine/c/WpDuScsMxxI
{
        inherit_from => itsv_custom_classes( $(promiser), $(handle) );
        promise_repaired => { "${workflow_class}_repaired",
                              $(workflow_class) };

}

/home/nickanderson/org/cfengine3-kSDomr:15:0: error: Undefined body itsv_reporting with type action

Xander Cage

unread,
May 4, 2021, 11:09:29 AM5/4/21
to help-cfengine
root@aixtest01: /root # cat body_inheritance_test.cf
body file control
{
  inputs => { "$(sys.libdir)/stdlib.cf",
            };

}



bundle agent b005_reporting_output_test

{

 meta:
    "tags"  slist => { "itsv" };


 commands:
      "/bin/true"
        handle    => "itsv_reporting_$(this.bundle)",
        classes   => itsv_keeper_of_the_classes( "$(this.promiser)", "$(this.handle)", itsv_TEST_WORKFLOW_CLASS ),
        #classes   => itsv_custom_classes( "$(this.promiser)", "$(this.handle)" ),
        action    => itsv_reporting( "$(this.handle)", "$(this.promiser)", "ITSV Cfengine", "1" );
}

body action itsv_reporting ( handle, promiser, promisee, if_elapsed )
#
#  officially stolen and carefully extracted from neil watsons ingenious delta reporting
#
{
   ifelapsed   => "${if_elapsed}";
   expireafter => "${if_elapsed}";

   itsv_reporting::
      log_kept     => "${itsvrep_c.itsv_promise_log}";
      log_repaired => "${itsvrep_c.itsv_promise_log}";
      log_failed   => "${itsvrep_c.itsv_promise_log}";
      log_string   => "${handle} ;; ${promiser} ;; ${promisee}";

}

body classes itsv_custom_classes ( promiser, handle )
{
        promise_kept      => { "${promiser}_handle_${handle}_kept" };
        promise_repaired  => { "${promiser}_handle_${handle}_repaired" };
        repair_failed     => { "${promiser}_handle_${handle}_notkept" };
        repair_denied     => { "${promiser}_handle_${handle}_notkept" };
        repair_timeout    => { "${promiser}_handle_${handle}_notkept" };
}

body classes itsv_keeper_of_the_classes ( promiser, handle, workflow_class)
# @brief: In addition to the classes set by "itsv_custom_classes", define

# "workflow_class" when the promise is repaired.

#
# mainly used for keeping already existing classes in the policys when activating reporting.
# see discussion: https://groups.google.com/g/help-cfengine/c/WpDuScsMxxI
{
        inherit_from => itsv_custom_classes( $(promiser), $(handle) );
        promise_repaired => { "${workflow_class}_repaired",
                              $(workflow_class) };

}

bundle agent __main__
{
  methods: "b005_reporting_output_test";
}


Nick Anderson

unread,
May 4, 2021, 11:58:06 AM5/4/21
to Xander Cage, help-cfengine

Xander Cage <christia...@itsv.at> writes:

itsv_TEST_WORKFLOW_CLASS is defined twice (with and without "_repaired" prefix), which does not correlate with the your example.

body classes itsv_keeper_of_the_classes has promise_repaired set to "promise_repaired => { "${workflow_class}_repaired", $(workflow_class) };" which should define both with and without the suffix in the event of a repair, or have I confused myself here?

the class ( _bin_true_handle_itsv_reporting_b005_reporting_output_test_repaired) which should be inherited from the " itsv_custom_classes" body is missing.

body classes itsv_keeper_of_the_classes defines promise_repaired overriding whatever was inherited. You need to add that class to the list of classes defined by promise_repaired like this:

bundle agent b005_reporting_output_test

{

  meta:
      "tags"  slist => { "itsv" };


  commands:
      "/bin/true"
        handle    => "itsv_reporting_$(this.bundle)",
        classes   => itsv_keeper_of_the_classes( "$(this.promiser)", "$(this.handle)", itsv_TEST_WORKFLOW_CLASS ),
      #classes   => itsv_custom_classes( "$(this.promiser)", "$(this.handle)" ),
        action    => itsv_reporting( "$(this.handle)", "$(this.promiser)", "ITSV Cfengine", "1" );
}

body action itsv_reporting ( handle, promiser, promisee, if_elapsed )
#
#  officially stolen and carefully extracted from neil watsons ingenious delta reporting
#
{
        ifelapsed   => "${if_elapsed}";
        expireafter => "${if_elapsed}";

    itsv_reporting::
        log_kept     => "${itsvrep_c.itsv_promise_log}";
        log_repaired => "${itsvrep_c.itsv_promise_log}";
        log_failed   => "${itsvrep_c.itsv_promise_log}";
        log_string   => "${handle} ;; ${promiser} ;; ${promisee}";

}

body classes itsv_custom_classes ( promiser, handle )
{
        promise_kept      => { "${promiser}_handle_${handle}_kept" };
        promise_repaired  => { "${promiser}_handle_${handle}_repaired" };
        repair_failed     => { "${promiser}_handle_${handle}_notkept" };
        repair_denied     => { "${promiser}_handle_${handle}_notkept" };
        repair_timeout    => { "${promiser}_handle_${handle}_notkept" };
}

body classes itsv_keeper_of_the_classes ( promiser, handle, workflow_class)
# @brief: In addition to the classes set by "itsv_custom_classes", define

# "workflow_class" when the promise is repaired.

#
# mainly used for keeping already existing classes in the policys when activating reporting.
# see discussion: https://groups.google.com/g/help-cfengine/c/WpDuScsMxxI
{
        inherit_from => itsv_custom_classes( $(promiser), $(handle) );
        promise_repaired => { "${workflow_class}_repaired"
,
                              $(workflow_class),
                              
"${promiser}_handle_${handle}_repaired" }
;
      #       ⊂_ヽ
      #         \\
      #          \(͡°͜ʖ͡°)
      #           > ⌒ヽ
      #          /   へ\
      #          /  / \\
      #          レ ノ   ヽ_つ
      #         / /
      #         / /|
      #        ( (ヽ
      #         | |、\
      #         | 丿 \ ⌒)
      #         | |  ) /
      #        ノ )  Lノ
      #       (_/

}

bundle agent __main__
{
      methods: "b005_reporting_output_test";
}

# cf-agent --no-lock --log-level info --show-evaluated-classes=.\*itsv.\* --file example.cf
    info: Executing 'no timeout' ... '/bin/true'
    info: Completed execution of '/bin/true'
Class name                                                   Meta tags                               
_bin_true_handle_itsv_reporting_b005_reporting_output_test_repaired                                         
itsv_TEST_WORKFLOW_CLASS                                                                             
itsv_TEST_WORKFLOW_CLASS_repaired                                                                    

Off topic, I see you are taking some things from delta reporting. classfiltercsv() may interest you.

Xander Cage

unread,
May 4, 2021, 12:23:55 PM5/4/21
to help-cfengine
maybe i'm littel bit dull..but i ask again...if its allowed to add unlimited classes to the for example "promise_repaired" attribute, why should i use another classes body instead of adding the wanted classes to the initial classes body?
sounds superflous or am i missing something obvious? *scratching my head*

Xander Cage

unread,
May 4, 2021, 12:25:33 PM5/4/21
to help-cfengine
ah got it the third attribute....sorry
Reply all
Reply to author
Forward
Message has been deleted
0 new messages