Feature Friday #6: cf-promises

Posted by Nick Anderson
April 19, 2024

Will your policy work? cf-promises can check the CFEngine policy for syntax errors and give you an overview of the host’s context.

It’s always a good idea to check your policy for syntax errors.

Consider this policy file:

/tmp/feature-friday-6.cf
bundle agent feature_friday
{
  reports:
    "$(this.promise_filename)"
      printfile => cat( "$(this.promise_filename)" )
}

Can you spot the error? Let’s see if cf-promises can help:

command
cf-promises -f /tmp/feature-friday-6.cf
output
/tmp/feature-friday-6.cf:6:2: error: syntax error
}
 ^
/tmp/feature-friday-6.cf:6:2: error: Check previous line, Expected ';', got '}'
}
 ^
   error: There are syntax errors in policy files

The output tells us that there is a syntax error near line 6, column 2. A semicolon (;) was expected but instead, a closing curly brace (}) was found. We are missing the semicolon that terminates the promise for bundle feature_friday_6 which is called as a methods promise.

If we correct it as follows, and run cf-promises -f /tmp/feature-friday-6-1.cf, it no longer complains.

/tmp/feature-friday-6-1.cf
bundle agent feature_friday
{
  reports:
    "$(this.promise_filename)"
      printfile => cat( "$(this.promise_filename)" );
}

cf-promises can also give you an overview of classes and variables that will be defined when your policy executes with the --show-vars and --show-classes options. It won’t show you everything, but variables and namespace scoped classes that can be derived without a full three-pass evaluation will be shown.

command
cf-promises --show-vars
output
Variable name                            Variable value                                               Meta tags                                Comment
default:cfe_autorun_inventory_dmidecode.dmi[bios-vendor] Dell Inc.                                                    source=promise,inventory,attribute_name=BIOS vendor
default:cfe_autorun_inventory_dmidecode.dmi[bios-version] 1.20.0                                                       source=promise,inventory,attribute_name=BIOS version
default:sys.os_name_human                Ubuntu                                                       source=agent,derived-from=ubuntu
default:sys.os_version_major             22                                                           source=agent,derived-from=flavor
command
cf-promises --show-classes
output
Class name                                                   Meta tags                                Comment
192_168_42_232                                               inventory,attribute_name=none,source=agent,hardclass
20_cpus                                                      source=agent,derived-from=sys.cpus,hardclass
Afternoon                                                    time_based,cfengine_internal_time_based_autoremove,source=agent,hardclass
mac_00_00_00_00_00_00                                        inventory,attribute_name=none,source=agent,hardclass
ubuntu_22_04                                                 inventory,attribute_name=none,source=agent,derived-from-file=/etc/os-release,hardclass
x86_64                                                       source=agent,derived-from=sys.machine,hardclass

But wait, that’s not all! cf-promises also has the --syntax-description option which can output a JSON representation of the syntax. This can be useful for integration with other tooling like editors for syntax checking as well as a way to identify native promise types and attributes.

For example, combined with jq we can get a list of native promise types:

command
cf-promises --syntax-description=json | jq -r '.promiseTypes|keys[]'
output
access
build_xpath
classes
commands
databases
defaults
delete_attribute
delete_lines
delete_text
delete_tree
field_edits
files
guest_environments
insert_lines
insert_text
insert_tree
measurements
meta
methods
packages
processes
replace_patterns
reports
roles
services
set_attribute
set_text
storage
users
vars

And we can count how many native functions exist:

command
cf-promises --syntax-description=json | jq '.functions|keys|length'
output
188

Happy Friday! 🎉