Did you know CFEngine can self-organize hosts into different groups?
Say you have a few hosts that you want to reboot once a month. You don’t care when, but you want the hosts to self-organize and pick a date. The select_class
attribute for classes
type promises might be what you’re looking for. Let’s take a look.
We’ll keep things simple, so we want each host to self-select a day of the month (1-28).
bundle agent reboot_day
{
vars:
# one option for each of 28 days in a month.
"options" slist => { expandrange( "reboot_day_[1-28]", 1 ) };
selected_option::
"selected"
string => "$(with)",
if => "$(options)",
with => regex_replace( "$(options)", "reboot_day_(.*)", "$1", "" ),
meta => { "inventory", "attribute_name=Reboot Day" };
classes:
"selected_option" select_class => { @(options) };
reports:
selected_option::
"I selected option $(selected)";
}
bundle agent __main__
{
methods:
"reboot_day";
}
In the above policy, we have the options
string list, a list of 28 elements, reboot_day_1
through reboot_day_28
. This list of options is fed to the select_class
attribute of our selected_option
classes promise.1 When a choice is made both selected_class
and reboot_day_N
classes will be defined. We use the knowledge of this selection and regex_replace()
to set the selected
variable to the selected day of the month. The variable is tagged for inventory, for greater visibility from Mission Portal in CFEngine Enterprise.2
Running this on a host you will find that the same selection is always made:
cf-agent --no-lock --log-level info --file /tmp/feature-friday.cf
R: I selected option 15
Through Mission Portal, it’s easy to see the distribution of the selected day:
Looking at a Pie chart we can see a fairly even distribution:
Hosts will continue to select the same day as long as the options to select from remain consistent (in order and number of options).
If we adjust the policy to select a day in the first 5 days of the month:
bundle agent reboot_day
{
vars:
# one option for each of the first 5 days in a month.
"options" slist => { expandrange( "reboot_day_[1-5]", 1 ) };
selected_option::
"selected"
string => "$(with)",
if => "$(options)",
with => regex_replace( "$(options)", "reboot_day_(.*)", "$1", "" ),
meta => { "inventory", "attribute_name=Reboot Day" };
classes:
"selected_option" select_class => { @(options) };
reports:
selected_option::
"I selected option $(selected)";
}
bundle agent __main__
{
methods:
"reboot_day";
}
We see hosts make new selections:
Not an absolutely even distribution, but still reasonable:
Go forth and let your groups select themselves!
Happy Friday! 🎉
-
Documentation for
select_class
: https://docs.cfengine.com/docs/3.21/reference-promise-types-classes.html#select_class ↩︎ -
Documentation for
regex_replace()
: https://docs.cfengine.com/docs/3.21/reference-functions-regex_replace.html ↩︎