Promise Types

Table of Contents

Within a bundle, the promise types are executed in a round-robin fashion in the following normal ordering. Which promise types are available depends on the bundle type:

Promise Type common agent server monitor
defaults - a default value for bundle parameters x x x x
classes - a class, representing a state of the system x x x x
meta - information about promise bundles x x x x
reports - report a message x x x x
vars - a variable, representing a value x x x x
commands - execute a command x
databases - configure a database x
files - configure a file x
packages - install a package x
guest_environments x
methods - take on a whole bundle of other promises x
processes - start or terminate processes x
services - manage services or define new abstractions x
storage - verify attached storage x
users - add or remove users x
access - grant or deny access to file objects x
roles - allow certain users to activate certain classes x
measurements - measure or sample data from the system x

See each promise type's reference documentation for detailed lists of available attributes.

Common Promise Attributes

The following attributes are available to all promise types.

action

Type: body action

The action settings allow general transaction control to be implemented on promise verification. Action bodies place limits on how often to verify the promise and what classes to raise in the case that the promise can or cannot be kept.

action_policy

Description: Determines whether to repair or report about non-kept promises

Type: (menu option)

Allowed input range:

  • fix makes changes to move toward the desired state
  • warn does not make changes, emits a warning level log message about non-compliance, raise repair_failed (not-kept)
  • nop alias for warn

Default value: fix

Example:

Policy:

body file control
{
      # Include the stdlib for local_dcp, policy, delete_lines
        inputs => { "$(sys.libdir)/stdlib.cf" };
}
bundle agent example_action_policy
{
  files:

      # We make sure there is some files to operate on, so we simply make a copy
      # of ourselves

      "$(this.promise_filename).nop"
        copy_from => local_dcp( $(this.promise_filename) );

      "$(this.promise_filename).warn"
        copy_from => local_dcp( $(this.promise_filename) );

      "$(this.promise_filename).fix"
        copy_from => local_dcp( $(this.promise_filename) );

      # We exercise each valid value of action_policy (nop, fix, warn) defining
      # classes named for the action_policy

      "$(this.promise_filename).nop"
        handle => "delete_lines_action_nop",
        edit_line => delete_lines_matching ( ".*" ),
        action => policy( "nop" ),
        classes => results( "namespace", "MY_files_promise_nop" );

      "$(this.promise_filename).warn"
        handle => "delete_lines_action_warn",
        edit_line => delete_lines_matching ( ".*" ),
        action => policy( "warn" ),
        classes => results( "namespace", "MY_files_promise_warn" );

      "$(this.promise_filename).fix"
        handle => "delete_lines_action_fix",
        edit_line => delete_lines_matching ( ".*" ),
        action => policy( "fix" ),
        classes => results( "namespace", "MY_files_promise_fix" );

  commands:

      "/bin/echo Running Command nop"
        handle => "command_nop",
        action => policy( "nop" ),
        classes => results( "namespace", "MY_commands_promise_nop" );

      "/bin/echo Running Command warn"
        handle => "command_warn",
        action => policy( "warn" ),
        classes => results( "namespace", "MY_commands_promise_warn" );

      "/bin/echo Running Command fix"
        handle => "command_fix",
        action => policy( "fix" ),
        classes => results( "namespace", "MY_commands_promise_fix" );

  reports:

      "MY classes:$(const.n)$(const.t)$(with)"
        with => join( "$(const.n)$(const.t)", sort( classesmatching( "MY_.*" ), "lex" ));

}
bundle agent __main__
{
  methods:
      "example_action_policy";
}

This policy can be found in /var/cfengine/share/doc/examples/action_policy.cf and downloaded directly from github.

Output:

 warning: Should edit file '/tmp/action_policy.cf.nop' but only a warning promised
 warning: Should edit file '/tmp/action_policy.cf.warn' but only a warning promised
 warning: Command '/bin/echo Running Command nop' needs to be executed, but only warning was promised
 warning: Command '/bin/echo Running Command warn' needs to be executed, but only warning was promised
R: MY classes:
    MY_commands_promise_fix_reached
    MY_commands_promise_fix_repaired
    MY_commands_promise_nop_error
    MY_commands_promise_nop_failed
    MY_commands_promise_nop_not_kept
    MY_commands_promise_nop_reached
    MY_commands_promise_warn_error
    MY_commands_promise_warn_failed
    MY_commands_promise_warn_not_kept
    MY_commands_promise_warn_reached
    MY_files_promise_fix_reached
    MY_files_promise_fix_repaired
    MY_files_promise_nop_error
    MY_files_promise_nop_failed
    MY_files_promise_nop_not_kept
    MY_files_promise_nop_reached
    MY_files_promise_warn_error
    MY_files_promise_warn_failed
    MY_files_promise_warn_not_kept
    MY_files_promise_warn_reached
 warning: Method 'example_action_policy' invoked repairs, but only warnings promised

ifelapsed

Description: The number of minutes before next allowed assessment of a promise is set using ifelapsed. This overrides the global settings. Promises which take a long time to verify should usually be protected with a long value for this parameter.

This serves as a resource 'spam' protection. A CFEngine check could easily run every 5 minutes provided resource intensive operations are not performed on every run. Using time classes such as Hr12 is one part of this strategy; using ifelapsed is another, which is not tied to a specific time.

ifelapsed => "0" disables function caching for the specific promise it's attached to.

Type: int

Allowed input range: 0,99999999999

Default value: body agent control ifelapsed value

Example:

#local

body action example
{
  ifelapsed   => "120";  # 2 hours
  expireafter => "240";  # 4 hours
}

# global

body agent control
{
  ifelapsed   => "180";  # 3 hours
}

Notes:

  • This is not a reliable way to control frequency over a long period of time.
  • Locks provide simple but weak frequency control.
  • Locks older than 4 weeks are automatically purged.

See also: promise locking, ifelapsed in body agent control, ifelapsed and function caching

History:

  • ifelapsed => "0" disables function caching for specific promise introduced in 3.19.0, 3.18.1

expireafter

Description: The Number of minutes a promise is allowed to run before the agent is terminated.

Note: Not to be confused with body contain exec_timeout in commands type promises, the original agent does not terminate the promise. When a subsequent agent notices that a promise actuation has persisted for longer than expireafter the subsequent agent will kill the agent that appears to be stuck on the long running promise.

Type: int

Allowed input range: 0,99999999999

Default value: control body value

Example:

body action example
{
  ifelapsed   => "120";  # 2 hours
  expireafter => "240";  # 4 hours
}

See also: body contain exec_timeout, body agent control expireafter, body executor control agent_expireafter

log_string

Description: The message to be written to the log when a promise verification leads to a repair.

The log_string works together with log_kept, log_repaired, and log_failed to define a string for logging to one of the named files depending on promise outcome, or to standard output if the log file is stipulated as stdout. Log strings on standard output are denoted by an L: prefix.

Note that log_string does not interact with log_level, which is about regular system output messages.

Type: string

Allowed input range: (arbitrary string)

Example:

  promise-type:

      "promiser"

        attr => "value",
        action => log_me("checked $(this.promiser) in promise $(this.handle)");

    # ..

  body action log_me(s)
{
  log_string => "$(s)";
}

Hint: The promise handle $(this.handle) can be a useful referent in a log message, indicating the origin of the message. In CFEngine Enterprise, promise handles make it easy to interpret report data.

log_kept

log_repaired

log_failed

Description: The names of files to which log_string will be saved for kept, repaired and failed promises.

When used together with log_string, the current promise will log its status using the log string to the respective file.

If these log names are absent, the default logging destination for the log string is syslog, but only for non-kept promises. Only the log_string is affected by this setting. Other messages destined for logging are sent to syslog.

Type: string

Allowed input range: stdout|udp_syslog|("?[a-zA-Z]:\\.*)|(/.*)

This string should be the full path to a text file which will contain the log, or one of the following special values:

  • stdout

Send the log message to the standard output, prefixed with an L: to indicate a log message.

  • udp_syslog

Log messages to syslog_host as defined in body common control over UDP. Please note UDP is unreliable.

Example:

bundle agent test
{
  vars:

      "software" slist => { "/root/xyz", "/tmp/xyz" };

  files:

      "$(software)"

        create => "true",
         action => logme("$(software)");

}

body action logme(x)
{
  log_kept => "/tmp/private_keptlog.log";
  log_failed => "/tmp/private_faillog.log";
  log_repaired => "/tmp/private_replog.log";
  log_string => "$(sys.date) $(x) promise status";
}

body action immediate_syslog(x)
{
  log_repaired => "udp_syslog";
  log_string => "CFEngine repaired promise $(this.handle) - $(x)";
}

It is intended that named file logs should be different for the three cases: promise kept, promise not kept and promise repaired.

log_level

Description: Describes the reporting level sent to syslog.

Use this as an alternative to auditing if you wish to use the syslog mechanism to centralize or manage messaging from CFEngine. A backup of these messages will still be kept in WORKDIR/outputs if you are using cf-execd.

On the native Windows version of CFEngine Enterprise, using verbose will include a message when the promise is kept or repaired in the event log.

Type: (menu option)

Allowed input range:

    inform
    verbose
    error
    log

Example:

body action example
{
  log_level => "inform";
}

Note: This attribute can not make the logging for an individual promise less verbose than specified by an agent option ( -v, --verbose, -I, --inform, -d, --debug ).

log_priority

Type: (menu option)

Allowed input range:

    emergency
    alert
    critical
    error
    warning
    notice
    info
    debug

Description: The log_priority menu option policy is the priority level of the log message, as interpreted by a syslog server. It determines the importance of messages from CFEngine.

Example:

body action low_priority
{
  log_priority => "info";
}

value_kept

Deprecated: This menu option policy is deprecated as of 3.6.0. It performs no action and is kept for backward compatibility.

value_repaired

Deprecated: This menu option policy is deprecated as of 3.6.0. It performs no action and is kept for backward compatibility.

value_notkept

Deprecated: This menu option policy is deprecated as of 3.6.0. It performs no action and is kept for backward compatibility.

audit

Deprecated: This menu option policy is deprecated as of 3.6.0. It performs no action and is kept for backward compatibility.

background

Description: A true/false switch for parallelizing the promise repair.

If possible, perform the verification of the current promise in the background (up to max_children in body agent control). This is advantageous only if the verification might take a significant amount of time, e.g. in remote copying of filesystem/disk scans.

On the Windows version of CFEngine Enterprise, this can be useful if we don't want to wait for a particular command to finish execution before checking the next promise. This is particular for the Windows platform because there is no way that a program can start itself in the background here; in other words, fork off a child process. However, file operations can not be performed in the background on Windows.

Type: boolean

Default value: false

Example:

bundle agent main
{
  commands:

    "/bin/sleep 10"
      action  => background;

    "/bin/sleep"
      args => "20",
      action  => background;

}
body action background
{
  background => "true";
}

See also: max_children in body agent control

report_level

Description: Defines the reporting level for standard output for this promise.

cf-agent can be run in verbose mode (-v), inform mode (-I) and just print errors (no arguments). This attribute allows to set these three output levels on a per promise basis, allowing the promise to be more verbose than the global setting (but not less).

Type: (menu option)

Allowed input range:

    inform
    verbose
    error
    log

Default value: none

Example:

body action example
{
  report_level => "verbose";
}

measurement_class

Description: If set, performance will be measured and recorded under this identifier.

By setting this string you switch on performance measurement for the current promise, and also give the measurement a name.

Type: string

Allowed input range: (arbitrary string)

Example:

body action measure
{
  measurement_class => "$(this.promiser) long job scan of /usr";
}

The identifier forms a partial identity for optional performance scanning of promises of the form:

    ID:promise-type:promiser.

classes

Type: body classes

scope

Description: Scope of the class set by this body.

Type: (menu option)

Allowed input range:

    namespace
    bundle

Default value: namespace

Example:

body classes bundle_class
{
  scope => "bundle";
  promise_kept => { "bundle_context" };
}

History: This attribute was introduced in CFEngine 3.5

See also: scope in classes promises

promise_repaired

Description: Classes to be defined globally if the promise was 'repaired'.

If the classes are set, a corrective action had to be taken to keep the promise.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  promise_repaired => { "change_happened" };
}

Important: Complex promises can report misleadingly; for example, files promises that set multiple parameters on a file simultaneously.

The classes for different parts of a promise are not separable. Thus, if you promise to create and file and change its permissions, when the file exists with incorrect permissions, cf-agent will report that the promise_kept for the file existence, but promise_repaired for the permissions. If you need separate reports, you should code two separate promises rather than 'overloading' a single one.

repair_failed

Description: Classes to be defined globally if the promise could not be kept.

If the classes are set, the corrective action to keep the promise failed for some reason.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  repair_failed => { "unknown_error" };
}

repair_denied

Description: Classes to be defined globally if the promise could not be repaired due to denied access to required resources.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  repair_denied => { "permission_failure" };
}

In the above example, a promise could not be kept because access to a key resource was denied.

repair_timeout

Description: Classes to be defined globally if the promise could not be repaired due to timeout.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  repair_timeout => { "too_slow", "did_not_wait" };
}

In the above example, a promise maintenance repair timed-out waiting for some dependent resource.

promise_kept

Description: Classes to be defined globally if the promise was kept without any corrective action.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  promise_kept => { "success", "kaplah" };
}

The class in the above example is set if no action was necessary by cf-agent, because the promise concerned was already kept without further action required.

Note: Complex promises can report misleadingly. For example, filespromises that set multiple parameters on a file simultaneously.

The classes for different parts of a promise are not separable. Thus, if you promise to create and file and change its permissions, when the file exists with incorrect permissions, cf-agent will report that the promise_kept for the file existence, but promise_repaired for the permissions. If you need separate reports, you should code two separate promises rather than 'overloading' a single one.

cancel_kept

Description: Classes to be canceled if the promise is kept.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  cancel_kept => { "success", "kaplah" };
}

In the above example, if the promise was already kept and nothing was done, cancel (undefine) any of the listed classes so that they are no longer defined.

Notes:

  • Hard classes can not be undefined. If you try to undefine or cancel a hard class an error will be emitted, for example error: You cannot cancel a reserved hard class 'cfengine' in post-condition classes.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

cancel_repaired

Description: Classes to be canceled if the promise is repaired.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  cancel_repaired => { "change_happened" };
}

In the above example, if the promise was repaired and changes were made to the system, cancel (undefine) any of the listed classes so that they are no longer defined.

Notes:

  • Hard classes can not be undefined. If you try to undefine or cancel a hard class an error will be emitted, for example error: You cannot cancel a reserved hard class 'cfengine' in post-condition classes.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

cancel_notkept

Description: Classes to be canceled if the promise is not kept for any reason.

Type: slist

Allowed input range: [a-zA-Z0-9_$(){}\[\].:]+

Note that any strings passed to this list are automatically canonified, so it is unnecessary to call a canonify function on such inputs.

Example:

body classes example
{
  cancel_notkept => { "failure" };
}

In the above example, if the promise was not kept but nothing could be done, cancel (undefine) any of the listed classes so that they are no longer defined.

Notes:

  • Hard classes can not be undefined. If you try to undefine or cancel a hard class an error will be emitted, for example error: You cannot cancel a reserved hard class 'cfengine' in post-condition classes.

History: This attribute was introduced in CFEngine version 3.0.4 (2010)

kept_returncodes

Description: Return codes that indicate a kept commands promise.

Currently, the attribute has impact on the following command-related promises:

  • All promises of type commands:
  • files-promises containing a transformer-attribute
  • The package manager change command in packages-promises (e.g. the command for add, remove, etc.)

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

Example:

bundle agent cmdtest
{
  commands:
      "/bin/false"
       classes => example;

  reports:
      waskept::
        "The command-promise was kept!";
}

body classes example
{
  kept_returncodes => { "0", "1" };
  promise_kept => { "waskept" };
}

In the above example, a list of integer return codes indicates that a command-related promise has been kept. This can in turn be used to define classes using the promise_kept attribute, or merely alter the total compliance statistics.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

repaired_returncodes

Description: Return codes that indicate a repaired commands promise

Currently, the attribute has impact on the following command-related promises:

  • All promises of type commands:
  • files-promises containing a transformer-attribute
  • The package manager change command in packages-promises (e.g. the command for add, remove, etc.)

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

Example:

bundle agent cmdtest
{
  commands:
      "/bin/false"
      classes => example;

  reports:
      wasrepaired::
        "The command-promise got repaired!";
}

body classes example
{
  repaired_returncodes => { "0", "1" };
  promise_repaired => { "wasrepaired" };
}

In the above example, a list of integer return codes indicating that a command-related promise has been repaired. This can in turn be used to define classes using the promise_repaired attribute, or merely alter the total compliance statistics.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

failed_returncodes

Description: A failed_returncodes slist contains return codes indicating a failed command-related promise.

Currently, the attribute has impact on the following command-related promises:

  • All promises of type commands:
  • files-promises containing a transformer-attribute
  • The package manager change command in packages-promises (e.g. the command for add, remove, etc.)

If none of the attributes kept_returncodes, repaired_returncodes, or failed_returncodes are set, the default is to consider a return code zero as promise repaired, and nonzero as promise failed.

Type: slist

Allowed input range: [-0-9_$(){}\[\].]+

Note that the return codes may overlap, so multiple classes may be set from one return code. In Unix systems the possible return codes are usually in the range from 0 to 255.

Example:

body common control
{
  bundlesequence => { "cmdtest" };
}

bundle agent cmdtest
{
  files:
      "/tmp/test"
        copy_from => copy("/etc/passwd");


      "/tmp/test"
        classes => example,
        transformer => "/bin/grep -q lkajfo999999 $(this.promiser)";

  reports:
      hasfailed::
        "The files-promise failed!";
}

body classes example
{
  failed_returncodes => { "1" };
  repair_failed => { "hasfailed" };
}

body copy_from copy(file)
{
  source => "$(file)";
}

The above example contains a list of integer return codes indicating that a command-related promise has failed. This can in turn be used to define classes using the promise_repaired attribute, or merely alter the total compliance statistics.

History: Was introduced in version 3.1.3, Nova 2.0.2 (2010)

persist_time

Description: The number of minutes the specified classes should remain active.

By default classes are ephemeral entities that disappear when cf-agent terminates. By setting a persistence time, they can last even when the agent is not running. When a persistent class is activated it gets scope namespace.

Type: int

Allowed input range: 0,99999999999

Example:

body classes example
{
  persist_time => "10";
}

See also: persistance classes attribute, persist_time in classes body

timer_policy

Description: Determines whether a persistent class restarts its counter when rediscovered.

In most cases resetting a timer will give a more honest appraisal of which classes are currently important, but if we want to activate a response of limited duration as a rare event then an absolute time limit is useful.

Type: (menu option)

Allowed input range:

    absolute
    reset

Default value: reset

Example:

body classes example
{
  timer_policy => "reset";
}

comment

Description: Describes the real intention of the promise.

Comments written in code follow the program, they are not merely discarded; they appear in verbose logs and error messages.

Type: string

Allowed input range: (arbitrary string)

Example:

  comment => "This comment follows the data for reference ...",

depends_on

Description: A list of promise handles for promises that must have an outcome of KEPT or REPAIRED in order for the promise to be actuated.

This is a list of promise handles for whom this promise is a promisee. In other words, we acknowledge that this promise will be affected by the list of promises whose handles are specified. It has the effect of partially ordering promises.

As of version 3.4.0, this feature may be considered short-hand for setting classes. If one promise depends on a list of others, it will not be verified unless the dependent promises have already been verified and kept: in other words, as long as the dependent promises are either kept or repaired the dependee can be verified.

Handles in other namespaces may be referred to by namespace:handle.

Type: slist

Allowed input range: (arbitrary string)

Example:

body common control
{
      bundlesequence => { "one"  };
}

bundle agent one
{
  reports:

      "two"
      depends_on => { "handle_one" };

      "one"
      handle => "handle_one";

}

This policy can be found in /var/cfengine/share/doc/examples/depends_on.cf and downloaded directly from github.

handle

Description: A unique id-tag string for referring to this as a promisee elsewhere.

A promise handle allows you to refer to a promise as the promisee of depends_on client of another promise. Handles are essential for mapping dependencies and performing impact analyses.

Type: string

Allowed input range: (arbitrary string)

Handles may consist of regular identifier characters. If the handle is likely to contain non-identifier characters, you can use canonify() to turn them into such characters.

Example:

  access:

      "/source"
        handle  => "update_rule",
        admit   => { "127.0.0.1" };

Notes: If the handle name is based on a variable, and the variable fails to expand, the handle will be based on the name of the variable rather than its content.

if

Description: Class expression to further restrict the promise context. Previously called ifvarclass.

This is an additional class expression that will be evaluated after the class:: classes have selected promises. It is provided in order to enable a channel between variables and classes.

The result is thus the logical AND of the ordinary classes and the variable classes.

Type: string

Allowed input range: (arbitrary string)

Example:

The generic example has the form:

  promise-type:

      "promiser"
        if => "$(program)_running|($(program)_notfoundHr12)";

A specific example would be:

bundle agent example
{
  commands:

      any::

        "/bin/echo This is linux"
          if => "linux";

        "/bin/echo This is solaris"
          if => "solaris";
}

This function is provided so that one can form expressions that link variables and classes. For example:

  # Check that all components are running

  vars:

      "component" slist => { "cf-monitord", "cf-serverd" };

  processes:

      "$(component)" restart_class => canonify("$(component)_not_runnning");

  commands:

      "/var/cfengine/bin/$(component)"
        if => canonify("$(component)_not_runnning");

Notes:

While strings are automatically canonified during class definition, they are not automatically canonified when checking. You may need to use canonify() to convert strings containing invalid class characters into a valid class.

In most cases, if => something and if => not(something) are opposite, but because of function skipping, both of these will be skipped if something is never resolved:

bundle agent main
{
  classes:
      "a" if => "$(no_such_var)";      # Will be skipped
      "b" if => not("$(no_such_var)"); # Will be skipped
}

If you need a condition which defaults to not skipping in the cases above, unless does this; for any expression where if will skip, unless will not skip.

if and unless both make choices about whether to skip a promise. Both if and unless can force a promise to be skipped - if a promise has both if and unless constraints, skipping takes precedence.

History: In 3.7.0 if was introduced as a shorthand for ifvarclass (and unless as an opposite).

ifvarclass

Description: Deprecated, use if instead.

History: New name if was introduced in 3.7.0, ifvarclass deprecated in 3.17.0.

meta

Description: A list of strings to be associated with the promise for knowledge management purposes. The strings are usually called "meta tags" or simply "tags."

Any promise (of any type) can be given a "meta" attribute. Since the right hand side for this attribute is an slist, multiple strings (tags) can be associated with the same promise.

Note that the inventory reporting of CFEngine Enterprise 3.6 and later uses the meta attributes inventory and attribute_name=, so these should be considered reserved for this purpose.

A "meta" attribute can likewise be added into any body (of any type).

Type: slist

Allowed input range: (arbitrary string list)

Example:

  files:

      "/etc/special_file"

        comment => "Special file is a requirement. Talk to John.",
        create => "true",

        meta => { "owner=John",  "version=2.0", "ticket=CFE-1234" };

Another example:

  some_promise_type:
      any::
        "my_promiser"
          meta => { "Team Foo", "workaround", "non-critical" };

The meta tags may be referred to programmatically in various ways, or may be solely for human consumption. Meta tags on vars promises and classes promises are particularly suited for programmatic interpretation; meta tags on other promise types (or in bodies) are more likely to be intended only for human consumption.

Relevant CFEngine functions are: classesmatching(), classmatch(), countclassesmatching(), getclassmetatags(), getvariablemetatags(), variablesmatching(), variablesmatching_as_data().

Also see meta promises: While "meta" attribute can be added to a promise of any type, there can also be promises of promise type "meta" added to any bundle. If mention is made of "tags" on a bundle, what is actually meant is meta promises in that bundle. (This is just a terminology point.)

Note: When a variable is re-defined the associated meta tags are also re-defined.

History: Was introduced in 3.3.0, Nova 2.2.0 (2012)

unless

Description: Class expression to further restrict the promise context. This is exactly like if but logically inverted; see its description for details. For any case where if would skip the promise, unless should evaluate the promise.

Type: string

Allowed input range: (arbitrary string)

Example:

The generic example has the form:

  promise-type:
      "promiser"
        unless => "forbidden";

A specific example would be:

bundle agent example
{
  commands:
      any::
        "/bin/echo This is NOT linux"
          unless => "linux";
}

Notes:

While strings are automatically canonified during class definition, they are not automatically canonified when checking. You may need to use canonify() to convert strings containing invalid class characters into a valid class.

if and unless both make choices about whether to skip a promise. Both if and unless can force a promise to be skipped - if a promise has both if and unless constraints, skipping takes precedence.

unless will skip a promise, only if the class expression is evaluated to false. If the class expression is true, or not evaluated (because of unexpanded variables, or unresolved function calls) it will not cause the promise to be skipped. Since if defaults to skipping in those cases, unless defaults to not skipping.

bundle agent main
{
  classes:
      "a"     if => "any";            # Will be evaluated
      "b" unless => "any";            # Will be skipped

      "c"     if => "$(no_such_var)"; # Will be skipped
      "d" unless => "$(no_such_var)"; # Will be evaluated
}

History: Was introduced in 3.7.0.

with

Description: Reusable promise attribute to avoid repetition.

Very often, it's handy to refer to a single value in many places in a promise, especially in the promiser. Especially when iterating over a list, the with attribute can save you a lot of work and code.

Another use of the with attribute is when in reports you want to use format() or other functions that produce lots of text, but don't want to create an intermediate variable.

Another common use of with is to avoid canonifying a value. In that case, you'd use with => canonify("the value") so you don't have to create a "canonification" array.

Type: string

Allowed input range: (arbitrary string)

Example:

bundle agent main
{
  vars:
      "todo" slist => { "a 1", "b 2", "c 3" };
      # Here, `with` is the canonified version of $(todo), letting us avoid an
      # intermediate canonification array.
      "$(with)" string => "$(todo)", with => canonify($(todo));

      "complex" data => '
{
  "x": 200,
  "y": [ 1, 2, null, true, false ]
}
';

  reports:
      "For iterable '$(todo)' we created variable '$(with)' and its value is '$(todo)'"
        with => canonify($(todo));

      "We can print a data container compactly without creating a temporary variable: $(with)"
        with => format("%S", complex);

      "We can print a data container fully without creating a temporary variable: $(with)"
        with => storejson(complex);
}

Output:

R: For iterable 'a 1' we created variable 'a_1' and its value is 'a 1'
R: For iterable 'b 2' we created variable 'b_2' and its value is 'b 2'
R: For iterable 'c 3' we created variable 'c_3' and its value is 'c 3'
R: We can print a data container compactly without creating a temporary variable: {"x":200,"y":[1,2,null,true,false]}
R: We can print a data container fully without creating a temporary variable: {
  "x": 200,
  "y": [
    1,
    2,
    null,
    true,
    false
  ]
}

History: Was introduced in 3.11.0

Common Body Attributes

The following attributes are available to all body types.

inherit_from

Description: Inherits all attributes from another body of the same type as a function call. For a detailed description, see Bodies.

Type: fncall

Allowed input range: (arbitrary body invocation)

Examples:

bundle agent __main__
{
  files:
      "$(this.promise_filename).txt"
        content => "Hello World$(const.n)2$(const.n)3$(const.n)4$(const.n)half-way
6$(const.n)7$(const.n)8$(const.n)9$(const.n)Byeeeeeee",
        create => "true";

  reports:
      "The first 3 lines of this file are:"
        printfile => head_n( "$(this.promise_filename).txt", "3" );

      "The whole file contains:"
        printfile => cat( "$(this.promise_filename).txt" );
}

body printfile head_n(file, lines)
{
      # Sets file_to_print the same as cat
        inherit_from => cat( $(file) );

      # Overrides number_of_lines from cat
        number_of_lines => "$(lines)";
}
body printfile cat(file)
{
        file_to_print   => "$(file)";
        number_of_lines => "inf";
}
R: The first 3 lines of this file are:
R: Hello World
R: 2
R: 3
R: The whole file contains:
R: Hello World
R: 2
R: 3
R: 4
R: half-way
R: 6
R: 7
R: 8
R: 9
R: Byeeeeeee

This policy can be found in /var/cfengine/share/doc/examples/inherit_from.cf and downloaded directly from github.

bundle agent __main__
{
  commands:
      "/bin/true"
        handle => "some meaningful string",
        classes => my_set_some_extra_fancy_classes( "$(this.promiser)",
                                                    "$(this.handle)",
                                                    "some_class_to_handle_dependencies" );

      "/bin/false"
        handle => "some meaningless string",
        classes => my_set_some_extra_fancy_classes( "$(this.promiser)",
                                                    "$(this.handle)",
                                                    "some_class_to_handle_dependencies" );

  reports:
      "Defined classes:$(const.n)$(with)"
        with => join( "$(const.n)", sort( classesmatching( "some_.*"), "lex" ));
}

body classes my_set_some_extra_fancy_classes(x, y, z)
{
        inherit_from => set_some_fancy_classes( $(x), $(y) );
        promise_repaired => { "some_fancy_class_${x}_${y}_repaired", $(z) };
}

body classes set_some_fancy_classes(x, y)
{
        promise_kept => { "some_fancy_class_${x}_${y}_kept" };
        promise_repaired => { "some_fancy_class_${x}_${y}_repaired" };
        repair_failed => { "some_fancy_class_${x}_${y}_notkept" };
        repair_denied => { "some_fancy_class_${x}_${y}_notkept" };
        repair_timeout => { "some_fancy_class_${x}_${y}_notkept" };
}
   error: Finished command related to promiser '/bin/false' -- an error occurred, returned 1
R: Defined classes:
some_class_to_handle_dependencies
some_fancy_class__bin_false_some_meaningless_string_notkept
some_fancy_class__bin_true_some_meaningful_string_repaired

This policy can be found in /var/cfengine/share/doc/examples/inherit_from_classes.cf and downloaded directly from github.

History: Was introduced in 3.8.0.

meta

Description: A list of strings to be associated with the body for knowledge management purposes. The strings are usually called "meta tags" or simply "tags."

Any body can be given a "meta" attribute. Since the right hand side for this attribute is an slist, multiple strings (tags) can be associated with the same body.

Type: slist

Allowed input range: (arbitrary string list)

Example:

body ANYTYPE mybody
{
  meta => { "deprecated" , "CFE-1234", "CVE-2020-1234" };
}

Note: When a variable is re-defined the associated meta tags are also re-defined.

History: Was introduced in 3.7.0.