commands

Commands and processes are separated cleanly. Restarting of processes must be coded as a separate command. This stricter type separation allows for more careful conflict analysis to be carried out.

     commands:

       "/path/to/command args"

                  args = "more args",
                  contain = contain_body,
                  module = true/false;

Output from commands executed here is quoted inline, but prefixed with the letter Q to distinguish it from other output; for example, from reports, which is prefixed with the letter R.

It is possible to set classes based on the return code of a commands-promise in a very flexible way. See the kept_returncodes, repaired_returncodes and failed_returncodes attributes.

bundle agent example

{
commands:

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

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

}

When referring to executables whose paths contain spaces, you should quote the entire program string separately so that CFEngine knows the name of the executable file. For example:

      commands:

       windows::

        "\"c:\Program Files\my name with space\" arg1 arg2";

       linux::

        "\"/usr/bin/funny command name\" -a -b -c";

Attributes

args

Description: Allows to separate the arguments to the command from the command itself.

Sometimes it is convenient to separate command and arguments. The final arguments are the concatenation with one space.

Type: string

Allowed input range: (arbitrary string)

commands:

  "/bin/echo one"

   args => "two three";

So in the example above the command would be:

 /bin/echo one two three

contain

Description: Allows running the command in a 'sandbox'.

Command containment allows you to make a `sandbox' around a command, to run it as a non-privileged user inside an isolated directory tree.

Type: body contain

Example:

    body contain example
    {
        useshell => "noshell";
           umask => "077";
      exec_owner => "mysql_user";
      exec_group => "nogroup";
    exec_timeout => "60";           
           chdir => "/working/path";
          chroot => "/private/path";
    }

useshell

Description: Specifies which shell to use when executing the command.

The default is to not use a shell when executing commands. Use of a shell has both resource and security consequences. A shell consumes an extra process and inherits environment variables, reads commands from files and performs other actions beyond the control of CFEngine.

If one does not need shell functionality such as piping through multiple commands then it is best to manage without it. In the Windows version of CFEngine Enterprise, the command is run in the cmd Command Prompt if this attribute is set to useshell, or in the PowerShell if the attribute is set to powershell.

Type: (menu option)

Allowed input range:

    useshell
    noshell
    powershell

For compatibility, the boolean values are also supported, and map to useshell and noshell, respectively.

Default value: noshell

Example:

     body contain example
     {
     useshell => "useshell";
     }

umask

Description: Sets the internal umask for the process.

Default value for the mask is 077. On Windows, umask is not supported and is thus ignored by Windows versions of CFEngine.

Type: (menu option)

Allowed input range:

    0
    77
    22
    27
    72
    077
    022
    027
    072

Example:

     body contain example
     {
     umask => "077";
     }

exec_owner

Description: Specifies the user under which the command executes.

This is part of the restriction of privilege for child processes when running cf-agent as the root user, or a user with privileges.

Windows requires the clear text password for the user account to run under. Keeping this in CFEngine policies could be a security hazard. Therefore, this option is not yet implemented on Windows versions of CFEngine.

Type: string

Allowed input range: (arbitrary string)

Example:

     body contain example
     {
     exec_owner => "mysql_user";
     }

exec_group

Description: Associates the command with a group.

This is part of the restriction of privilege for child processes when running cf-agent as the root group, or a group with privileges. It is ignored on Windows, as processes do not have any groups associated with them.

Type: string

Allowed input range: (arbitrary string)

Example:

     body contain example
     {
     exec_group => "nogroup";
     }

exec_timeout

Description: Attempt to time-out after this number of seconds.

This cannot be guaranteed as not all commands are willing to be interrupted in case of failure.

Type: int

Allowed input range: 1,3600

Example:

     body contain example
     {
     exec_timeout => "30";
     }

chdir

Description: Run the command with a working directory.

This attribute has the effect of placing the running command into a current working directory equal to the parameter given; in other words, it works like the cd shell command.

Type: string

Allowed input range: "?(/.*)

Example:

     body contain example

     {
     chdir => "/containment/directory";
     }

chroot

Description: Specify the path that will be the root directory for the process.

The path of the directory will be experienced as the top-most root directory for the process. In security parlance, this creates a 'sandbox' for the process. Windows does not support this feature.

Type: string

Allowed input range: "?(/.*)

Example:

     body contain example

     {
     chroot => "/private/path";
     }

preview

Description: This is the preview command when running in dry-run mode (with -n).

Previewing shell scripts during a dry-run is a potentially misleading activity. It should only be used on scripts that make no changes to the system. It is CFEngine best practice to never write change-functionality into user-written scripts except as a last resort. CFEngine can apply its safety checks to user defined scripts.

Type: boolean

Default value: false

Example:

     body contain example
     {
     preview => "true";
     }

no_output

Description: Allows to discard all output from the command.

Setting this attribute to true is equivalent to piping standard output and error to /dev/null.

Type: boolean

Default value: false

Example:

     body contain example
     {
     no_output => "true";
     }

module

Description: Set variables and classes based on command output.

CFEngine modules are commands that support a simple protocol in order to set additional variables and classes on execution from user defined code. Modules are intended for use as system probes rather than additional configuration promises. Such a module may be written in any language.

This attribute determines whether or not to expect the CFEngine module protocol. If true, the module protocol is supported for this command:

  • lines which begin with a + are treated as classes to be defined (like -D)
  • lines which begin with a - are treated as classes to be undefined (like -N)
  • lines which begin with = are scalar variables to be defined
  • lines which begin with @ are lists.

These variables end up in a context that has the same name as the module.

Any other lines of output are cited by cf-agent as being erroneous, so you should normally make your module completely silent.

Type: boolean

Default value: false

Example:

Here is an example module written in shell:

     #!/bin/sh
     /bin/echo "@mylist= { \"one\", \"two\", \"three\" }"
     /bin/echo "=myscalar= scalar val"
     /bin/echo "+module_class"

And here is an example using it:

    body common control
    {
    bundlesequence  => { def, modtest };
    }

    bundle agent def
    {
    commands:

      "$(sys.workdir)/modules/module_name"
        module => "true";

    reports:

      # Each module forms a private context with its name as id
      module_class::

        "Module set variable $(module_name.myscalar)";
    }


    bundle agent modtest
    {
    vars:

      "mylist" slist => { @(module_name.mylist) };

    reports:

      module_class::

        "Module set variable $(mylist)";
    }

Here is an example module written in Perl:

     #!/usr/bin/perl
     #
     # module:myplugin
     #

       # lots of computation....

     if (special-condition)
        {
        print "+specialclass";
        }

If your module is simple and is best expressed as a shell command, then we suggest that you expose the class being defined in the command being executed (making it easier to see what classes are used when reading the promises file). For example, the promises could read as follows (the two echo commands are to ensure that the shell always exits with a successful execution of a command):

    bundle agent sendmail
    {
    commands:
      # This next module checks a specific failure mode of dcc, namely
      # more than 3 error states since the last time we ran cf-agent
      is_mailhost::
            "/bin/test `/usr/bin/tail -100 /var/log/maillog | /usr/bin/grep 'Milter (dcc): to error state' | /usr/bin/wc -l` -gt 3  echo '+start_dccm' || echo
    ''"
        contain => shell_command,
        module => "true";

        start_dccm::
          "/var/dcc/libexec/start-dccm"
              contain => not_paranoid;
    }

    body contain shell_command
    {
        useshell    => "useshell";
    }

    body contain not_paranoid
    {
        useshell    => "no";
        exec_owner  => "root";
        umask       => "22";
    }

Modules inherit the environment variables from cf-agent and accept arguments, just as a regular command does.