Dynamic method calls in CFEngine

Meth­ods type promises are pow­er­ful abstrac­tion tools in CFEngine 3. Meth­ods allow you to acti­vate bun­dles (option­ally param­e­trized) from other bun­dles. This allows encap­su­la­tion of knowl­edge and lends itself to re-usability.

I just want to share an exam­ple of call­ing bun­dles dynam­i­cally. It’s a con­trived exam­ple, 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 out­put This Gist is brought to you using Sim­ple 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 Sim­ple Gist Embed.

Break­down

bun­dle agent main

Here we define two lists, a list of bun­dle names and a list of val­ues. Because of implicit list iter­a­tion we then call “handler_iterator” 2 times. Once for each value of the mybun­dles list. Each acti­va­tion also passes in the myval­ues list.

Bun­dle agent handler_iterator

handler_iterator is where the neat part hap­pens. You can see that we call the bun­dle $(han­dler) (out­side of quotes) with the para­me­ter @(handler_iterator.values). This is what I found so inter­est­ing. I Have called bun­dles dynam­i­cally in the past, but I have always put the vari­able inside of quotes. That worked fine but it pre­vented me from using para­me­ters when call­ing because the para­me­ters were seen as part of the bun­dle name.  Here is an exam­ple of the handler_iterator bun­dle try­ing to use a param­e­trized 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 out­put This Gist is brought to you using Sim­ple Gist Embed.

Since $(han­dler) is a sin­gle value (we iter­ated over the list of bun­dles in bun­dle agent main) only one method acti­va­tion will hap­pen for each acti­va­tion of handler_iterator.

bun­dle agent handlerx

The han­dlers them­selves just report once for each item in the list passed to them.

Spe­cific Use Case

Well, I don’t have one. I can how­ever imag­ine that based on some vari­able event you might want to call a bun­dle with some vari­able para­me­ter. Some­thing like the nagios_plugin_agent sketch comes to mind. (It can call a vari­able bun­dle 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