Feature Friday #34: Self organizing groups with select_class

Posted by Nick Anderson
November 1, 2024

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).

/tmp/feature-friday.cf
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:

command
cf-agent --no-lock --log-level info --file /tmp/feature-friday.cf
output
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:

/tmp/feature-friday.cf
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! 🎉