For episode 0b111111 Nick and Craig demo CFEngine 3.28 live: container data in Mission Portal, and classes promises gain more flexibility.
In this episode, after learning that 63 is the ASCII code for ?, the atomic number for Europium, and the country code for the Philippines Craig followed up on Episode 61 (libntech and json) showing container inventory flowing into Mission Portal surfacing Docker and Podman containers and images. Then Nick showed new low level policy features: optional arguments on getusers/getgroups, a single-value expandrange fix from Normation, and two new classes promise attributes (cancel and timer_policy) that give you more direct control over classes and when they should be defined. There was also a fun discussion with Martin about variables and how bundles aren’t functions (though several features like the bundle_return_value_index of reports promises and how classic associative arrays are cleared at the start of each bundle actuation are very useful if you are going to abuse them).
After the show there was nice discussion about Promise Theory, where CFEngine fits more or less naturally in the infrastructure and one user learned that packages promises can be made about packages on disk (you don’t have to run a command to install a local package, just promise it’s path) and that you generally are not required to specify the package_module you wish to use if that’s also the platforms default package manager..
bundle agent packages_example
{
packages:
"/opt/emacs/my-emacs.deb"
package_policy => "present";
}Container inventory lands in Mission Portal
Earlier episodes showed how CFEngine can collect container and image data from hosts, that data is now flowing into Mission Portal’s UI.
The new Containers tab in the host detail view shows a summary (total images, sizes, volumes, running engines) and a full table of containers with sortable columns. Images and containers from both engines appear in a single unified view, just like a docker ps but with historical timestamps and host-side context.
The collection happens automatically during the reporting phase of the agent run, no inventory policy needed.
New & changed functions
getusers() and getgroups() arguments now optional
Both functions now return the full list if called with no arguments. Previously you had to pass two empty strings to get all users/groups.
bundle agent main
{
reports:
'getusers() -> $(length(getusers())) = $(with)';
}R: getusers() -> 26expandrange() can now emit a single value
The agent no longer errors when the expanded range produces a single element — a fix contributed by Normation.
bundle agent main
{
vars:
"hosts" slist => expandrange("host[1-1]", 3);
reports:
"$(hosts)";
}R: host1Classes promises
Cancel / undefine a class directly
Classes promises can now un-set a class. Previously you had to piggyback on a commands or files outcome using cancel_kept / cancel_repaired in a body classes:
bundle agent __main__
{
classes:
"My_Class"
expression => "any",
comment => "Simulate a feature flag that is currently on";
commands:
"/bin/true"
classes => if_ok_cancel("My_Class");
reports:
My_Class:: "My_Class is defined";
!My_Class:: "My_Class is not defined";
}
body classes if_ok(x)
# @brief Define the class `x` if the promise is kept or repaired
# @param x The name of the class that should be defined
{
promise_repaired => { "$(x)" };
promise_kept => { "$(x)" };
}In 3.28 you can undefine a class directly from a classes promise with the new cancel attribute (a boolean). The class-context guard controls when it fires:
bundle agent main
{
classes:
"My_Class"
expression => "any";
"My_Class"
cancel => "true";
}Extend a persistent class timer
The new timer_policy attribute for classes promises controls whether a persistent class keeps its original expiry (“absolute”) or restarts the countdown each time the promise is evaluated (“reset”).
In 3.28.0 the default is “reset” — a persistent class that is still in context gets its timer extended on every agent run. The attribute was backported to 3.24.5 and 3.27.2 with a default of “absolute”, preserving the pre-existing behavior.
bundle agent main
{
classes:
"cached_class"
expression => "any",
persistence => "120",
timer_policy => "reset";
}This is the kind of change that silently affects anyone already using persistent classes — if you’re currently relying on the absolute expiry behavior and haven’t pinned a version, the default will now extend instead.
Video
The video recording is available on YouTube:
At the end of every webinar, we stop the recording for a nice and relaxed, off-the-record chat with attendees. Join the next webinar to not miss this discussion.