Dynamic method calls in CFEngine

Methods type promises are powerful abstraction tools in CFEngine 3. Methods allow you to activate bundles (optionally parametrized) from other bundles. This allows encapsulation of knowledge and lends itself to re-usability.

I just want to share an example of calling bundles dynamically. It’s a contrived example, but I thought it was neat so here it is.

R: in bundle agent handler1: I got value1
R: in bundle agent handler1: I got value2
 !! Method invoked repairs
 !! Method invoked repairs
R: in bundle agent handler2: I got value1
R: in bundle agent handler2: I got value2
 !! Method invoked repairs
 !! Method invoked repairs

view raw output This Gist is brought to you using Simple Gist Embed.
body common control {

    bundlesequence => {"main",};

}

bundle agent main{
vars:
  "mybundles" slist => { "handler1","handler2" };
  "myvalues" slist => { "value1", "value2" };

methods:
  "$(mybundle)" usebundle => handler_iterator("$(mybundles)", "@(main.myvalues)");

}

bundle agent handler_iterator(handler, values)
# This expects a single value
{
methods:
  "$(handler)" usebundle => $(handler)("@(handler_iterator.values)");

}
bundle agent handler1(value1)
{
reports:
  cfengine::
    "in bundle agent handler1: I got $(value1)";
}

bundle agent handler2(value1)
{
reports:
  cfengine::
  "in bundle agent handler2: I got $(value1)";
}

view raw test.cf This Gist is brought to you using Simple Gist Embed.

Breakdown

bundle agent main

Here we define two lists, a list of bundle names and a list of values. Because of implicit list iteration we then call “handler_iterator” 2 times. Once for each value of the mybundles list. Each activation also passes in the myvalues list.

Bundle agent handler_iterator

handler_iterator is where the neat part happens. You can see that we call the bundle $(handler) (outside of quotes) with the parameter @(handler_iterator.values). This is what I found so interesting. I Have called bundles dynamically in the past, but I have always put the variable inside of quotes. That worked fine but it prevented me from using parameters when calling because the parameters were seen as part of the bundle name.  Here is an example of the handler_iterator bundle trying to use a parametrized value inside of quotes.

bundle agent handler_iterator(handler, values)
# This expects a single value
{
methods:
  "$(handler) $(values)" usebundle => "$(handler)($(values))";

}
 !! A method attempted to use a bundle "handler1(value1)" that was apparently not defined!
I: Report relates to a promise with handle ""
I: Made in version 'not specified' of './test.cf' near line 21
 !! A method attempted to use a bundle "handler1(value2)" that was apparently not defined!
I: Report relates to a promise with handle ""
I: Made in version 'not specified' of './test.cf' near line 21
 !! Method failed in some repairs or aborted
 !! A method attempted to use a bundle "handler2(value1)" that was apparently not defined!
I: Report relates to a promise with handle ""
I: Made in version 'not specified' of './test.cf' near line 21
 !! A method attempted to use a bundle "handler2(value2)" that was apparently not defined!
I: Report relates to a promise with handle ""
I: Made in version 'not specified' of './test.cf' near line 21
 !! Method failed in some repairs or aborted

view raw output This Gist is brought to you using Simple Gist Embed.

Since $(handler) is a single value (we iterated over the list of bundles in bundle agent main) only one method activation will happen for each activation of handler_iterator.

bundle agent handlerx

The handlers themselves just report once for each item in the list passed to them.

Specific Use Case

Well, I don’t have one. I can however imagine that based on some variable event you might want to call a bundle with some variable parameter. Something like the nagios_plugin_agent sketch comes to mind. (It can call a variable bundle right now).

No Comments

Leave a Reply

Your email is never shared.Required fields are marked *

To submit your comment, click the image below where it asks you to...
Clickcha - The One-Click Captcha