Generic methods

This section documents all the generic methods available in the Technique Editor.

Command

command_execution

Execute a command

Compatible with nodes running Rudder 5.0 or higher.

Parameters

  • command: Command to run

Classes defined

command_execution_${command}_{kept, repaired, not_ok, reached}

command_execution_once

Execute a command only once on a node

Compatible with nodes running Rudder 5.0 or higher.

Usage

Execute a command only once.

This method is useful for specific commands that should only be executed once per node.

If you can spot a condition for the command execution by testing the state of its target, it is better to use condition_from_command to test the state and command_execution_result to run the command if necessary.

When you use this method, it will:

  • If a command_execution_once has already been executed on this machine with the same unique id, define a command_execution_once_${command}_kept condition and do nothing

  • If it is the first occurrence, it will execute the command and:

    • If the until parameter is any, it will consider the command as executed on the machine and define command_execution_once_${command}_repaired/error depending if the return code is in ok_codes

    • If the until parameter is ok, it will store consider it done only if the return code is in the ok_codes list and define command_execution_once_${command}_repaired. If not, it will retry at the next agent run and define command_execution_once_${command}_error

If an exit code is not in the list it will lead to an error status. If you want 0 to be a success you have to list it in the ok_codes list

Example

If you use:

command_execution_once("command -a -t", "0", "ok", "my_program_setup")

Will retry to run command -a -t until it returns 0. Then it will not execute it again.

Parameters

  • command: Command to run

  • ok_codes: List of codes that produce a repaired status separated with commas (ex: 1,2,5). Defaults to 0.

  • until: Try to execute the command until a particular state: `ok', `any' (defaults to `any')

  • unique_id: To identify the action without losing track if the command changes. Defaults to the command if you don’t need it.

Classes defined

command_execution_once_${command}_{kept, repaired, not_ok, reached}

command_execution_result

Execute a command and create result conditions depending on its exit code

Compatible with nodes running Rudder 5.0 or higher.

Usage

Execute a command and create result conditions depending on the exit codes given in parameters. If an exit code is not in the list it will lead to an error status. If you want 0 to be a success you have to list it in the kept_codes list

Parameters

  • command: Command to run

  • kept_codes: List of codes that produce a kept status separated with commas (ex: 1,2,5)

  • repaired_codes: List of codes that produce a repaired status separated with commas (ex: 3,4,6)

Classes defined

command_execution_result_${command}_{kept, repaired, not_ok, reached}

Condition

condition_from_command

Execute a command and create result conditions depending on its exit code

Compatible with nodes running Rudder 5.0 or higher.

Usage

This method executes a command, and defines a ${condition_prefix}_true or a ${condition_prefix}_false condition depending on the result of the command:

  • If the exit code is in the true_codes list, this will produce a kept outcome class and a ${condition_prefix}_true condition

  • If the exit code is in the false_codes list, this will produce a repaired outcome class and a ${condition_prefix}_false condition

  • If the exit code is not in the list, or if the command is not present, this will produce an error outcome class and no classes with ${condition_prefix}

  • In audit mode, this method will still execute the command passed in parameter. Which means that you should only pass non system-impacting commands to this method.

This method will still execute the given command in Audit mode. This is because we assume that only commands which are not changing the system state should be used to define a condition.

The created condition is global to the agent.

Example

If you run a command /bin/check_network_status that output code 0, 1 or 2 in case of correct configuration, and 18 or 52 in case of invalid configuration, and you want to get this define a condition based on this command, you can use the following policy

condition_from_command("network_correctly_defined", "/bin/check_network_status", "0,1,2", "18,52")
  • If the command exits 0, 1 or 2, then it will define the following conditions network_correctly_defined_true, condition_from_command_network_correctly_defined_kept, condition_from_command_network_correctly_defined_reached

  • If the command exits 18, 52, then it will define the following conditions network_correctly_defined_false, condition_from_command_network_correctly_defined_kept, condition_from_command_network_correctly_defined_reached

  • If the command exits any other code, then it will define the following conditions condition_from_command_network_correctly_defined_error, condition_from_command_network_correctly_defined_reached

  • Finally, if the command is not present on the node, it will define condition_from_command_network_correctly_defined_error, condition_from_command_network_correctly_defined_reached

Parameters

  • condition_prefix: The condition name

  • command: The command to run

  • true_codes: List of codes that produce a true status separated with commas (ex: 1,2,5)

  • false_codes: List of codes that produce a false status separated with commas (ex: 3,4,6)

Classes defined

condition_from_command_${condition_prefix}_{kept, repaired, not_ok, reached}

condition_from_expression

Create a new condition

Compatible with nodes running Rudder 5.0 or higher.

Usage

This method evaluates an expression, and produces a ${condition_prefix}_true or a ${condition_prefix}_false condition depending on the result on the expression:

  • If the expression results in a `defined'' state, this will produce a kept outcome class and a `${condition_prefix}_true condition

  • If the expression results in an `undefined'' state, this will produce a kept outcome class and a `${condition_prefix}_false condition

Calling this method with a condition expression transforms a complex expression into a single condition.

The created condition is global to the agent.

Example

If you want to check if a condition evaluates to true, like checking that you are on Monday, 2am, on RedHat systems, you can use the following policy

condition_from_expression("backup_time", "Monday.redhat.Hr02")
  • If the system is a RedHat like system, on Monday, at 2am, then it will define the following conditions backup_time_true, condition_from_expression_backup_time_kept, condition_from_expression_backup_time_reached

  • If the system not a RedHat like system, or it’s not Monday, or it’s not 2am, then it will define the following conditions backup_time_false, condition_from_expression_backup_time_kept, condition_from_expression_backup_time_reached

  • If the condition is invalid (cannot be parsed), it will define only condition_from_expression_backup_time_kept, condition_from_expression_backup_time_reached

Parameters

  • condition_prefix: The condition prefix

  • condition_expression: The expression evaluated to create the condition (use `any' to always evaluate to true)

Classes defined

condition_from_expression_${condition_prefix}_{kept, repaired, not_ok, reached}

condition_from_expression_persistent

Create a new condition that persists across runs

Compatible with nodes running Rudder 5.0 or higher.

Usage

This method evaluates an expression, and produces a ${condition_prefix}_true or a ${condition_prefix}_false condition depending on the result on the expression, that lasts for the duration time:

  • If the expression results in a `defined'' state, this will produce a kept outcome class and a `${condition_prefix}_true condition

  • If the expression results in an `undefined'' state, this will produce a kept outcome class and a `${condition_prefix}_false condition

Calling this method with a condition expression transforms a complex expression into a single class condition.

The created condition is global to the agent and is persisted across runs. The persistence duration is controlled using ${duration}; it defines for how long the resulting condition will be defined (in minutes). Note that there is no way to persist indefinitely.

Example

If you want to check if a condition evaluates to true, like checking that you are on Monday, 2am, on RedHat systems, and make it last one hour you can use the following policy

condition_from_expression_persistent_("backup_time", "Monday.redhat.Hr02", "60")
  • If the system is a RedHat like system, on Monday, at 2am, then it will define the following conditions backup_time_true, condition_from_expression_persistent_backup_time_kept, condition_from_expression_persistent_backup_time_reached

  • If the system not a RedHat like system, or it’s not Monday, or it’s not 2am, then it will define the following conditions backup_time_false, condition_from_expression_persistent_backup_time_kept, condition_from_expression_persistent_backup_time_reached

  • If the condition is invalid (cannot be parsed), it will define only condition_from_expression_persistent_backup_time_kept, condition_from_expression_persistent_backup_time_reached

Parameters

  • condition_prefix: The condition prefix

  • condition_expression: The expression evaluated to create the condition (use `any' to always evaluate to true)

  • duration: The persistence suffix in minutes

Classes defined

condition_from_expression_persistent_${condition_prefix}_{kept, repaired, not_ok, reached}

condition_from_variable_existence

Create a condition from the existence of a variable

Compatible with nodes running Rudder 5.0 or higher.

Usage

This bundle will define a condition {condition_prefix}_{variable_name}_{true/false} * {condition_prefix}_{variable_name}_true if the variable is defined * {condition_prefix}_{variable_name}_false if the variable is not defined

Parameters

  • condition_prefix: Prefix of the condition

  • variable_name: Complete name of the variable being tested, like my_prefix.my_variable

Classes defined

condition_from_variable_existence_${condition_prefix}_{kept, repaired, not_ok, reached}

condition_from_variable_match

Test the content of a string variable

Compatible with nodes running Rudder 5.0 or higher.

Usage

Test a variable content and create outcome classes depending on its value. This generic method will define a class condition_from_variable_match_${condition_prefix}_{kept, repaired, error, reached}.

  • If the variable is found and its content matches the given regex, this will produce a kept outcome condition and a ${condition_prefix}_true condition

  • If the variable is found but its content does not match the given regex, it will produce a kept outcome condition and a ${condition_prefix}_false condition

  • If the variable can not be found, it will produce an error outcome condition and a ${condition_prefix}_false condition

/! Regex for unix machine must be PCRE compatible and those for Windows agent must respect the .Net regex format.

  • If you want to test a technique parameter, use the technique_id of the technique as prefix and the parameter_name as variable name.

Parameters

  • condition_prefix: Prefix of the class (condition) generated

  • variable_name: Complete name of the variable being tested, like my_prefix.my_variable

  • expected_match: Regex to use to test if the variable content is compliant

Classes defined

condition_from_variable_match_${condition_prefix}_{kept, repaired, not_ok, reached}

condition_once

Create a new condition only once

Compatible with nodes running Rudder 5.0 or higher.

Usage

This method evaluates an expression, and produces a ${condition} when it is first called. Following calls will not define the condition.

This allows executing actions only once on a given machine.

The created condition is global to the agent.

Example

If you use:

condition_once("my_condition")

The first agent run will have my_condition defined, contrary to subsequent runs for which no class will be defined.

Parameters

  • condition: The condition to define

Classes defined

condition_once_${condition}_{kept, repaired, not_ok, reached}

Directory

directory_absent

Ensure a directory’s absence

Compatible with nodes running Rudder 5.0 or higher.

Usage

If recursive is false, only an empty directory can be deleted.

Parameters

  • target: Directory to remove

  • recursive: Should deletion be recursive, true'' or false'' (defaults to ``false'')

Classes defined

directory_absent_${target}_{kept, repaired, not_ok, reached}

directory_check_exists

Checks if a directory exists

Compatible with nodes running Rudder 5.0 or higher.

Usage

This bundle will define a condition directory_check_exists_${directory_name}_{ok, reached, kept} if the directory exists, or directory_check_exists_${directory_name}_{not_ok, reached, not_kept, failed} if the directory doesn’t exists

Parameters

  • directory_name: Full path of the directory to check

Classes defined

directory_check_exists_${directory_name}_{kept, repaired, not_ok, reached}

directory_create

Create a directory if it doesn’t exist

WARNING: This generic method is deprecated. Use directory_present instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters

  • target: Full path of directory to create (trailing `/' is optional)

Classes defined

directory_create_${target}_{kept, repaired, not_ok, reached}

directory_present

Create a directory if it doesn’t exist

Compatible with nodes running Rudder 5.0 or higher.

Parameters

  • target: Full path of directory to create (trailing `/' is optional)

Classes defined

directory_present_${target}_{kept, repaired, not_ok, reached}

Dsc

dsc_built_in_resource

This generic method defines if service should run or be stopped

Compatible with nodes running Rudder 5.0 or higher.

Usage

Apply a given DSC resource to the node.

Parameters

  • tag parameter is purely informative and has no impact on the resource.

  • ResourceName must be the explicit name of the DSC resource you wish to apply

  • ScriptBlock must be a powershell script in plain text, returning an Hashtable containing the parameters to pass to the resource.

Note that this method can only apply built-in Windows resources. It will not be able to apply an external resource.

Example

If we want to apply a Registry resource. The resourceName used will be Registry And a potential ScriptBlock could be:

 $HKLM_SOFT="HKEY_LOCAL_MACHINE\SOFTWARE"
 $Ensure      = "Present"
 $Key         = $HKLM_SOFT + "\ExampleKey"

 $table = @{}
 $table.Add("Ensure", $Ensure)
 $table.Add("Key", $Key)
 $table.Add("ValueName", "RudderTest")
 $table.Add("ValueData", "TestData")
 $table

Note that all the ScriptBlock will be readable on the Rudder logs or in the policy files.

Parameters

  • tag: Informative name

  • resourceName: resourceName

  • scriptBlock: Desired state for the resource

Classes defined

dsc_built_in_resource_${tag}_{kept, repaired, not_ok, reached}

Environment

environment_variable_present

Enforce an environment variable value. Caution, the new environment variable will not be usable by the agent until it is restarted

Compatible with nodes running Rudder 5.0 or higher.

Parameters

  • name: Name of the environment variable

  • value: Value of the environment variable

Classes defined

environment_variable_present_${name}_{kept, repaired, not_ok, reached}

File

file_absent

Remove a file if it exists

Compatible with nodes running Rudder 5.0 or higher.

Parameters

  • target: File to remove (absolute path on the target node)

Classes defined

file_absent_${target}_{kept, repaired, not_ok, reached}

file_augeas_commands

Use Augeas binaries to execute augtool commands and options directly on the agent.

Compatible with nodes running Rudder 5.0 or higher.

Usage

Augeas is a tool that provides an abstraction layer for all the complexities that turn around editing files with regular expressions. It’s a tree based hierarchy tool, that handles system configuration files where you can securely modify your files and to do so you have to provide the path to the node label’s value. Augeas uses lenses which are like sort of modules that are in charge of identifying and converting files into tree and back. This way, you can manipulate at first the tree and then save changes into the configuration files on the system.

This method gives the possibilty to enter a list of augtool commands and options as a parameter. The method has in total 4 parameters: variable_prefix, variable_name, commands and autoload. Augtool provides bunch of other commands and options that you can use in this generic method such as `match' to print the matches for a specific path expression, `span' to print position in input file corresponding to tree, `retrieve' to transform tree into text and `save' to save all pending changes. If Augeas isn’t installed on the agent, it will produces an error.

The particular thing you may want to do with this method is using it depending on you needs and in two cases.

Use case 1:

The first case includes activating the autoload option, it is true by default, means you can leave the autoload parameter’s field empty and Augeas will accordingly charge all files and lenses before executing the commands you have specified. Below is an example that will shows as a result the configuration files that are parsed by default in /files/etc directory and then also print the content of the sshd_config file, you can either leave the autoload parameter empty or fill it by putting true as a value.

file_augeas_commands("label","value","ls /files/etc \n print /files/etc/ssh/sshd_config","")
file_augeas_commands("label","value","ls /files/etc \n print /files/etc/ssh/sshd_config","true")

Use case 2:

The second case is when you deactivate that option which means that you are specifying false as parameter and in this case you have to charge manually your files and lenses in the commands parameter by using the set commands. Below is the second example where you can for example set the lens and the file then verifying by checking the /augeas/load path.

file_augeas_commands("label","value","set /augeas/load/Sshd/lens "Sshd.lns \n set /augeas/load/Sshd/incl "/etc/ssh/sshd_config" \n load \n print /augeas/load/Sshd \n print /augeas/load/Sshd \n print /files/etc/ssh/sshd_config","false")

Parameters

  • variable_prefix: The prefix of the variable name

  • variable_name: The variable to define, the full name will be variable_prefix.variable_name

  • commands: The augeas command(s)

  • autoload: Deactivate the autoload option if you don’t want augeas to charge all the files/lens, it’s true by default.

Classes defined

file_augeas_commands_${variable_name}_{kept, repaired, not_ok, reached}

file_augeas_set

Use Augeas binaries to call Augtool commands and options to set a node label’s value.

Compatible with nodes running Rudder 5.0 or higher.

Usage

Augeas is a tool that provides an abstraction layer for all the complexities that turn around editing files with regular expressions. It’s a tree based hierarchy tool, that handles system configuration files where you can securely modify your files and to do so you have to provide the path to the node label’s value. Augeas uses lenses which are like sort of modules that are in charge of identifying and converting files into tree and back. This way, you can manipulate at first the tree and then save changes into the configuration files on the system.

In this method, we introduce using augtool commands and options in order to set the value of a given node’s label in the parameters (which means that you simply want to modify your configuration file), this can be done by specifying the path to it. The method has in total 4 parameters: path, value, lens and hosts.

Actually there is two ways you can use this method, either you simply provide a path to the node’s label as a parameter or you specify a file associated with a lens then you put the regular path. When you only specify the path to the node’s label, your request will includes by default Augeas charging all the lenses and files, on the other hand, if you have a specific file for example such as a Json file and you want to associate it to the existing Json lense, then in that case, you need to fill in addition the file and the lens parameter, this way Augeas won’t load all its files and lenses except the ones you have specified.

The generic method will set a node label’s value on the agent, otherwise, if Augeas isn’t installed on the agent, it will produces an error. The method provides a way to make a backup of the file you modified before applying any changes on the node, you can find them in the `/var/rudder/modified-files/' directory.

Two uses cases examples:

Use case 1: In the first case, let’s suppose that you want to simply set the value of the ip address of the first line in the /etc/hosts file to 192.168.1.5,

to do so you need to provide the path and value parameters.

....
file_augeas_set("/etc/hosts/1/ipaddr","192.168.1.5");
....

Use case 2: The second case includes two needs of using it, either you
want to prevent Augeas from charging all lenses and files while
executing your request or
----------------------------------------------------------------------------------------------------------------------------------------------------------------

you want to associate the `Hosts` lens with the `/etc/hosts` file then
set the value for the given path node.
file_augeas_set(``/etc/hosts/1/ipaddr'',``192.168.1.5'',``Hosts'',``/etc/hosts'');

Parameters
++++++++++

* *path*: The path to the file and node label
* *value*: The value to set
* *lens*: The lens specified by the user in case he wants to load a
specified lens associated with its file
* *file*: The file specified by the user in case he wants to load a
specified file associated with its lens

Classes defined
+++++++++++++++

....

file_augeas_set_${lens}_{kept, repaired, not_ok, reached}
....

file_block_present
^^^^^^^^^^^^^^^^^^

Ensure that a text block is present in a specific location

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *block*: Block(s) to add in the file

Classes defined
+++++++++++++++

....

file_block_present_${file}_{kept, repaired, not_ok, reached}
....

file_block_present_in_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a section contains exactly a text block

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section_start*: Start of the section
* *section_end*: End of the section
* *block*: Block representing the content of the section

Classes defined
+++++++++++++++

....

file_block_present_in_section_${file}_{kept, repaired, not_ok, reached}
....

file_check_FIFO_pipe
^^^^^^^^^^^^^^^^^^^^

Checks if a file exists and is a FIFO/Pipe

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_FIFO_pipe_${file_name}_{ok, reached, kept}` if the file is a
FIFO, or
`file_check_FIFO_pipe_${file_name}_{not_ok, reached, not_kept, failed}`
if the file is not a fifo or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_FIFO_pipe_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_block_device
^^^^^^^^^^^^^^^^^^^^^^^

Checks if a file exists and is a block device

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_block_device_${file_name}_{ok, reached, kept}` if the file
is a block_device, or
`file_check_block_device_${file_name}_{not_ok, reached, not_kept, failed}`
if the file is not a block device or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_block_device_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_character_device
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Checks if a file exists and is a character device

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_character_device_${file_name}_{ok, reached, kept}` if the
file is a character device, or
`file_check_character_device_${file_name}_{not_ok, reached, not_kept, failed}`
if the file is not a character device or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_character_device_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_exists
^^^^^^^^^^^^^^^^^

Checks if a file exists

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_exists_${file_name}_{ok, reached, kept}` if the file exists,
or `file_check_exists_${file_name}_{not_ok, reached, not_kept, failed}`
if the file doesn’t exists

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_exists_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_hardlink
^^^^^^^^^^^^^^^^^^^

Checks if two files are the same (hard links)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_hardlink_${file_name_1}_{ok, reached, kept}` if the two
files `${file_name_1}` and `${file_name_2}` are hard links of each
other, or
`file_check_hardlink_${file_name_1}_{not_ok, reached, not_kept, failed}`
if if the files are not hard links.

Parameters
++++++++++

* *file_name_1*: File name #1 (absolute path on the target node)
* *file_name_2*: File name #2 (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_hardlink_${file_name_1}_{kept, repaired, not_ok, reached}
....

file_check_regular
^^^^^^^^^^^^^^^^^^

Checks if a file exists and is a regular file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_regular_${file_name}_{ok, reached, kept}` if the file is a
regular_file, or
`file_check_regular_${file_name}_{not_ok, reached, not_kept, failed}` if
the file is not a regular file or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_regular_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_socket
^^^^^^^^^^^^^^^^^

Checks if a file exists and is a socket

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_socket_${file_name}_{ok, reached, kept}` if the file is a
socket, or
`file_check_socket_${file_name}_{not_ok, reached, not_kept, failed}` if
the file is not a socket or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_socket_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_symlink
^^^^^^^^^^^^^^^^^^

Checks if a file exists and is a symlink

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_symlink_${file_name}_{ok, reached, kept}` if the file is a
symlink, or
`file_check_symlink_${file_name}_{not_ok, reached, not_kept, failed}` if
the file is not a symlink or does not exist

Parameters
++++++++++

* *file_name*: File name (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_symlink_${file_name}_{kept, repaired, not_ok, reached}
....

file_check_symlinkto
^^^^^^^^^^^^^^^^^^^^

Checks if first file is symlink to second file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`file_check_symlinkto_${target}_{ok, reached, kept}` if the file
`${symlink}` is a symbolic link to `${target}`, or
`file_check_symlinkto_${target}_{not_ok, reached, not_kept, failed}` if
if it is not a symbolic link, or any of the files does not exist. The
symlink’s path is resolved to the absolute path and checked against the
target file’s path, which must also be an absolute path.

Parameters
++++++++++

* *symlink*: Symbolic link (absolute path on the target node)
* *target*: Target file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_check_symlinkto_${symlink}_{kept, repaired, not_ok, reached}
....

file_content
^^^^^^^^^^^^

Enforce the content of a file

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to add in the file - if lines is a list, please use
@\{lines} to pass the iterator rather than iterating over each values
* *enforce*: Enforce the file to contain only line(s) defined (true or
false)

Classes defined
+++++++++++++++

....

file_lines_present_${file}_{kept, repaired, not_ok, reached}
....

file_copy_from_local_source
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source

*WARNING*: This generic method is deprecated. Use
link:#_file_from_local_source[file_from_local_source] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_copy_from_local_source_${destination}_{kept, repaired, not_ok, reached}
....

file_copy_from_local_source_recursion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source

*WARNING*: This generic method is deprecated. Use
link:#_file_from_local_source_recursion[file_from_local_source_recursion]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *recursion*: Recursion depth to enforce for this path (0, 1, 2, …,
inf)

Classes defined
+++++++++++++++

....

file_copy_from_local_source_${destination}_{kept, repaired, not_ok, reached}
....

file_copy_from_local_source_with_check
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source if a check
command succeeds

*WARNING*: This generic method is deprecated. Use
link:#_file_from_local_source_with_check[file_from_local_source_with_check]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method is a conditionnal file copy.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *check_command*: Command to run, it will get the source path as
argument
* *rc_ok*: Return codes to be considered as valid, separated by a comma
(default is 0)

Classes defined
+++++++++++++++

....

file_copy_from_local_source_with_check_${destination}_{kept, repaired, not_ok, reached}
....

file_copy_from_remote_source
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a policy server

*WARNING*: This generic method is deprecated. Use
link:#_file_from_remote_source[file_from_remote_source] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

_Note_: This method uses CFEngine file copy protocol, and can only
download files from the policy server. To download a file from an
external source, you can use HTTP with the
link:#_file_download[file_download] method.

This method requires that the policy server is configured to accept copy
of the source file from the agents it will be applied to.

You have to write the full path of the file on the policy server, for
example:

....
/home/myuser/myfile
....

If you are using Rudder, you can download a file from the shared files
with:

....
/var/rudder/configuration-repository/shared-files/PATH_TO_YOUR_FILE
....

Parameters
++++++++++

* *source*: Source file (absolute path on the policy server)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_copy_from_remote_source_${destination}_{kept, repaired, not_ok, reached}
....

file_copy_from_remote_source_recursion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a policy server

*WARNING*: This generic method is deprecated. Use
link:#_file_from_remote_source_recursion[file_from_remote_source_recursion]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method requires that the policy server is configured to accept copy
of the source file or directory from the agents it will be applied to.

You have to write the full path of the file or directory on the policy
server, for example:

....
/home/myuser/mydirectory
....

If you are using Rudder, you can download a file from the shared files
with:

....
/var/rudder/configuration-repository/shared-files/PATH_TO_YOUR_DIRECTORY_OR_FILE
....

Parameters
++++++++++

* *source*: Source file (absolute path on the policy server)
* *destination*: Destination file (absolute path on the target node)
* *recursion*: Recursion depth to enforce for this path (0, 1, 2, …,
inf)

Classes defined
+++++++++++++++

....

file_copy_from_remote_source_${destination}_{kept, repaired, not_ok, reached}
....

file_create
^^^^^^^^^^^

Create a file if it doesn’t exist

*WARNING*: This generic method is deprecated. Use
link:#_file_present[file_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *target*: File to create (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_create_${target}_{kept, repaired, not_ok, reached}
....

file_create_symlink
^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target
except if a file or directory already exists.

*WARNING*: This generic method is deprecated. Use
link:#_file_symlink_present[file_symlink_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_create_symlink_${destination}_{kept, repaired, not_ok, reached}
....

file_create_symlink_enforce
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target.
This is also possible to enforce its creation

*WARNING*: This generic method is deprecated. Use
link:#_file_symlink_present_option[file_symlink_present_option] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *enforce*: Force symlink if file already exist (true or false)

Classes defined
+++++++++++++++

....

file_create_symlink_${destination}_{kept, repaired, not_ok, reached}
....

file_create_symlink_force
^^^^^^^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target
even if a file or directory already exists.

*WARNING*: This generic method is deprecated. Use
link:#_file_symlink_present_force[file_symlink_present_force] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_create_symlink_${destination}_{kept, repaired, not_ok, reached}
....

file_download
^^^^^^^^^^^^^

Download a file if it does not exist, using curl with a fallback on wget

*WARNING*: This generic method is deprecated. Use
link:#_file_from_http_server[file_from_http_server] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method finds a HTTP command-line tool and downloads the given
source into the destination.

It tries `curl` first, and `wget` as fallback.

Parameters
++++++++++

* *source*: URL to download from
* *destination*: File destination (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_download_${destination}_{kept, repaired, not_ok, reached}
....

file_enforce_content
^^^^^^^^^^^^^^^^^^^^

Enforce the content of a file

*WARNING*: This generic method is deprecated. Use
link:#_file_content[file_content] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to add in the file - if lines is a list, please use
@\{lines} to pass the iterator rather than iterating over each values
* *enforce*: Enforce the file to contain only line(s) defined (true or
false)

Classes defined
+++++++++++++++

....

file_ensure_lines_present_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_block_in_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a section contains exactly a text block

*WARNING*: This generic method is deprecated. Use
link:#_file_block_present_in_section[file_block_present_in_section]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section_start*: Start of the section
* *section_end*: End of the section
* *block*: Block representing the content of the section

Classes defined
+++++++++++++++

....

file_ensure_block_in_section_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_block_present
^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a text block is present in a specific location

*WARNING*: This generic method is deprecated. Use
link:#_file_block_present[file_block_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *block*: Block(s) to add in the file

Classes defined
+++++++++++++++

....

file_ensure_block_present_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_key_value
^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains a pair of ``key separator value''

*WARNING*: This generic method is deprecated. Use
link:#_file_key_value_present[file_key_value_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit (or create) the file, and ensure it contains an entry key -> value
with arbitrary separator between the key and its value. If the key is
already present, the method will change the value associated with this
key.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Key to define
* *value*: Value to define
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)

Classes defined
+++++++++++++++

....

file_ensure_key_value_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_key_value_option
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains a pair of ``key separator value'', with
options on the spacing around the separator

*WARNING*: This generic method is deprecated. Use
link:#_file_key_value_present_option[file_key_value_present_option]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit (or create) the file, and ensure it contains an entry key -> value
with arbitrary separator between the key and its value. If the key is
already present, the method will change the value associated with this
key.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Key to define
* *value*: Value to define
* *option*: Option for the spacing around the separator: strict, which
prevent spacings (space or tabs) around separators, or lax which accepts
any number of spaces around separators
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)

Classes defined
+++++++++++++++

....

file_ensure_key_value_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_key_value_parameter_in_list
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that one parameter exists in a list of parameters, on one single
line, in the right hand side of a key->values line

*WARNING*: This generic method is deprecated. Use
link:#_file_key_value_parameter_present_in_list[file_key_value_parameter_present_in_list]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit the file, and ensure it contains the defined parameter in the list
of values on the right hand side of a key->values line. If the parameter
is not there, it will be added at the end, separated by
parameter_separator. Optionnaly, you can define leading and closing
character to enclose the parameters If the key does not exist in the
file, it will be added in the file, along with the parameter

Example
+++++++

If you have an initial file (`/etc/default/grub`) containing

....
GRUB_CMDLINE_XEN="dom0_mem=16G"
....

To add parameter `dom0_max_vcpus=32` in the right hand side of the line,
you’ll need the following policy

....
file_ensure_key_value_parameter_in_list("/etc/default/grub", "GRUB_CMDLINE", "=", "dom0_max_vcpus=32", " ", "\"", "\"");
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Full key name
* *key_value_separator*: character used to separate key and value in a
key-value line
* *parameter*: String representing the sub-value to ensure is present in
the list of parameters that form the value part of that line
* *parameter_separator*: Character used to separate parameters in the
list
* *leading_char_separator*: leading character of the parameters
* *closing_char_separator*: closing character of the parameters

Classes defined
+++++++++++++++

....

file_ensure_key_value_parameter_in_list_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_key_value_parameter_not_in_list
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a parameter doesn’t exist in a list of parameters, on one
single line, in the right hand side of a key->values line

*WARNING*: This generic method is deprecated. Use
link:#_file_key_value_parameter_absent_in_list[file_key_value_parameter_absent_in_list]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit the file, and ensure it does not contain the defined parameter in
the list of values on the right hand side of a key->values line. If the
parameter is there, it will be removed. Please note that the parameter
can be a regular expression. It will also remove any whitespace
character between the parameter and parameter_separator Optionnaly, you
can define leading and closing character to enclose the parameters

Example
+++++++

If you have an initial file (`/etc/default/grub`) containing

....
GRUB_CMDLINE_XEN="dom0_mem=16G dom0_max_vcpus=32"
....

To remove parameter `dom0_max_vcpus=32` in the right hand side of the
line, you’ll need the following policy

....
file_ensure_key_value_parameter_not_in_list("/etc/default/grub", "GRUB_CMDLINE", "=", "dom0_max_vcpus=32", " ", "\"", "\"");
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Full key name
* *key_value_separator*: character used to separate key and value in a
key-value line
* *parameter_regex*: Regular expression matching the sub-value to ensure
is not present in the list of parameters that form the value part of
that line
* *parameter_separator*: Character used to separate parameters in the
list
* *leading_char_separator*: leading character of the parameters
* *closing_char_separator*: closing character of the parameters

Classes defined
+++++++++++++++

....

file_ensure_key_value_parameter_not_in_list_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_key_value_present_in_ini_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a key-value pair is present in a section in a specific
location. The objective of this method is to handle INI-style files.

*WARNING*: This generic method is deprecated. Use
link:#_file_key_value_present_in_ini_section[file_key_value_present_in_ini_section]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section*: Name of the INI-style section under which the line should
be added or modified (not including the [] brackets)
* *name*: Name of the key to add or edit
* *value*: Value of the key to add or edit

Classes defined
+++++++++++++++

....

file_ensure_key_value_present_in_ini_section_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_keys_values
^^^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains all pairs of ``key separator value'', with
arbitrary separator between each key and its value

*WARNING*: This generic method is deprecated. Use
link:#_file_keys_values_present[file_keys_values_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method ensures key-value pairs are present in a file.

Usage
+++++

This method will iterate over the key-value pairs in the dict, and:

* If the key is not defined in the destination, add the _key_ +
_separator_ + _value_ line.
* If the key is already present in the file, replace the _key_ +
_separator_ + anything by _key_ + _separator_ + _value_

This method always ignores spaces and tabs when replacing (which means
for example that `key = value` will match the `=` separator).

Keys are considered unique (to allow replacing the value), so you should
use link:#_file_ensure_lines_present[file_ensure_lines_present] if you
want to have multiple lines with the same key.

Example
+++++++

If you have an initial file (`/etc/myfile.conf`) containing:

....
key1 = something
key3 = value3
....

To define key-value pairs, use the link:#_variable_dict[variable_dict]
or link:#_variable_dict_from_file[variable_dict_from_file] methods.

For example, if you use the following content (stored in
`/tmp/data.json`):

....
{
   "key1": "value1",
   "key2": "value2"
}
....

With the following policy:

....
# Define the `content` variable in the `configuration` prefix from the json file
variable_dict_from_file("configuration", "content", "/tmp/data.json")
# Enforce the presence of the key-value pairs
file_ensure_keys_values("/etc/myfile.conf", "configuration.content", " = ")
....

The destination file (`/etc/myfile.conf`) will contain:

....
key1 = value1
key3 = value3
key2 = value2
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *keys*: Name of the dict structure (without ``$\{}'') containing the
keys (keys of the dict), and values to define (values of the dict)
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)

Classes defined
+++++++++++++++

....

file_ensure_keys_values_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_line_present_in_ini_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a line is present in a section in a specific location. The
objective of this method is to handle INI-style files.

*WARNING*: This generic method is deprecated. Use
link:#_file_line_present_in_ini_section[file_line_present_in_ini_section]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section*: Name of the INI-style section under which lines should be
added (not including the [] brackets)
* *line*: Line to ensure is present inside the section

Classes defined
+++++++++++++++

....

file_ensure_line_present_in_ini_section_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_line_present_in_xml_tag
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a line is present in a tag in a specific location. The
objective of this method is to handle XML-style files. Note that if the
tag is not present in the file, it won’t be added, and the edition will
fail.

*WARNING*: This generic method is deprecated. Use
link:#_file_line_present_in_xml_tag[file_line_present_in_xml_tag]
instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *tag*: Name of the XML tag under which lines should be added (not
including the <> brackets)
* *line*: Line to ensure is present inside the section

Classes defined
+++++++++++++++

....

file_ensure_line_present_in_xml_tag_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_lines_absent
^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a line is absent in a specific location

*WARNING*: This generic method is deprecated. Use
link:#_file_lines_absent[file_lines_absent] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to remove in the file

Classes defined
+++++++++++++++

....

file_ensure_lines_absent_${file}_{kept, repaired, not_ok, reached}
....

file_ensure_lines_present
^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that one or more lines are present in a file

*WARNING*: This generic method is deprecated. Use
link:#_file_lines_present[file_lines_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to add in the file

Classes defined
+++++++++++++++

....

file_ensure_lines_present_${file}_{kept, repaired, not_ok, reached}
....

file_from_http_server
^^^^^^^^^^^^^^^^^^^^^

Download a file if it does not exist, using curl with a fallback on wget

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method finds a HTTP command-line tool and downloads the given
source into the destination.

This method *will NOT update the file after the first download* until
its removal.

It tries `curl` first, and `wget` as fallback.

Parameters
++++++++++

* *source*: URL to download from
* *destination*: File destination (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_http_server_${destination}_{kept, repaired, not_ok, reached}
....

file_from_local_source
^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_local_source_${destination}_{kept, repaired, not_ok, reached}
....

file_from_local_source_recursion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *recursion*: Recursion depth to enforce for this path (0, 1, 2, …,
inf)

Classes defined
+++++++++++++++

....

file_from_local_source_${destination}_{kept, repaired, not_ok, reached}
....

file_from_local_source_with_check
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a local source if a check
command succeeds

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method is a conditionnal file copy.

It allows comparing the source and destination, and if they are
different, call a command with the source file path as argument, and
only update the destination if the commands succeeds (i.e. returns a
code included in rc_ok).

Examples
++++++++

....
# To copy a configuration file only if it passes a config test:
file_from_local_source_with_check("/tmp/program.conf", "/etc/program.conf", "program --config-test", "0");
....

This will:

* Compare `/tmp/program.conf` and `/etc/program.conf`, and return `kept`
if files are the same
* If not, it will execute `program --config-test "/tmp/program.conf"`
and check the return code
* If it is one of the `rc_ok` codes, it will copy `/tmp/program.conf`
into `/etc/program.conf` and return a repaired
* If not, it will return an error

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *check_command*: Command to run, it will get the source path as
argument
* *rc_ok*: Return codes to be considered as valid, separated by a comma
(default is 0)

Classes defined
+++++++++++++++

....

file_from_local_source_with_check_${destination}_{kept, repaired, not_ok, reached}
....

file_from_remote_source
^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a policy server

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

_Note_: This method uses CFEngine file copy protocol, and can only
download files from the policy server. To download a file from an
external source, you can use HTTP with the
link:#_file_download[file_download] method.

This method requires that the policy server is configured to accept copy
of the source file from the agents it will be applied to.

You have to write the full path of the file on the policy server, for
example:

....
/home/myuser/myfile
....

If you are using Rudder, you can download a file from the shared files
with:

....
/var/rudder/configuration-repository/shared-files/PATH_TO_YOUR_FILE
....

Parameters
++++++++++

* *source*: Source file (absolute path on the policy server)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_remote_source_${destination}_{kept, repaired, not_ok, reached}
....

file_from_remote_source_recursion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from a policy server

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method requires that the policy server is configured to accept copy
of the source file or directory from the agents it will be applied to.

You have to write the full path of the file or directory on the policy
server, for example:

....
/home/myuser/mydirectory
....

If you are using Rudder, you can download a file from the shared files
with:

....
/var/rudder/configuration-repository/shared-files/PATH_TO_YOUR_DIRECTORY_OR_FILE
....

Parameters
++++++++++

* *source*: Source file (absolute path on the policy server)
* *destination*: Destination file (absolute path on the target node)
* *recursion*: Recursion depth to enforce for this path (0, 1, 2, …,
inf)

Classes defined
+++++++++++++++

....

file_from_remote_source_${destination}_{kept, repaired, not_ok, reached}
....

file_from_shared_folder
^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is copied from Rudder shared folder
(/var/rudder/configuration-repository/shared-files)

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (path, relative to
/var/rudder/configuration-repository/shared-files)
* *destination*: Destination file (absolute path on the target node)
* *hash_type*: Hash algorithm used to check if file is updated (md5,
sha1, sha256). Only used on Windows, ignored on Unix.

Classes defined
+++++++++++++++

....

file_from_shared_folder_${destination}_{kept, repaired, not_ok, reached}
....

file_from_string_mustache
^^^^^^^^^^^^^^^^^^^^^^^^^

Build a file from a mustache string

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *template*: String containing a template to be expanded
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_string_mustache_${destination}_{kept, repaired, not_ok, reached}
....

file_from_template
^^^^^^^^^^^^^^^^^^

Build a file from a legacy CFEngine template

*WARNING*: This generic method is deprecated. This method uses
CFEngine’s templating which is deprecated and not portable accross
agents. Please use
link:#_file_from_template_mustache[file_from_template_mustache] or
link:#_file_from_template_jinja2[file_from_template_jinja2] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_file_from_template_type[file_from_template_type] for general
documentation about templates usage.

Parameters
++++++++++

* *source_template*: Source file containing a template to be expanded
(absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_template_${destination}_{kept, repaired, not_ok, reached}
....

file_from_template_jinja2
^^^^^^^^^^^^^^^^^^^^^^^^^

Build a file from a jinja2 template

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_file_from_template_type[file_from_template_type] for general
documentation about templates usage.

This generic method will build a file from a jinja2 template using data
(conditions and variables) found in the execution context.

Setup
+++++

It requires to have the jinja2 python module installed on the node, it
can usually be done in ncf with
`package_present("python-jinja2", "", "", "")`.

WARNING: If you are using a jinja2 version older than 2.7 trailing
newlines will not be preserved in the destination file.

Syntax
++++++

Jinja2 is a powerful templating language, running in Python. The Jinja2
syntax reference documentation is
http://jinja.pocoo.org/docs/dev/templates/ which will likely be useful,
as Jinja2 is very rich and allows a lot more that what is explained
here.

This section presents some simple cases that cover what can be done with
mustache templating, and the way the agent data is provided to the
templating engine.

The main specificity of jinja2 templating is the use of two root
containers:

* `classes` to access currently defined conditions
* `vars` to access all currently defined variables

Note: You can add comments in the template, that will not be rendered in
the output file with `{# ... #}`.

You can extend the Jinja2 templating engine by adding custom FILTERS and
TESTS in the script
`/var/rudder/configuration-repository/ncf/10_ncf_internals/modules/extensions/jinja2_custom.py`

For instance, to add a filter to upperstring a string and a test if a
number is odd, you can create the file
`/var/rudder/configuration-repository/ncf/10_ncf_internals/modules/extensions/jinja2_custom.py`
on your Rudder server with the following content:

....
def upperstring(input):
    return input.upper()

def odd(value):
    return True if (value % 2) else False

FILTERS = {'upperstring': upperstring}
TESTS = {'odd': odd}
....

These filters and tests will be usable in your jinja templates
automatically.

Conditions

To display content based on conditions definition:

....
{% if classes.my_condition is defined  %}
   display this if defined
{% endif %}
{% if not classes.my_condition is defined %}
   display this if not defined
{% endif %}
....

Note: You cannot use condition expressions here.

You can also use other tests, for example other bilt-in ones or those
defined in `jinja2_custom.py`:

....
{% if vars.variable_prefix.my_number is odd  %}
   display if my_number is odd
{% endif %}
....

Scalar variables

Here is how to display a scalar variable value (integer, string, …), if
you have defined
`variable_string("variable_prefix", "my_variable", "my_value")`:

....
{{ vars.variable_prefix.my_variable }}
....

You can also modify what is displayed by using filters. The built-in
filters can be extended in `jinja2_custom.py`:

....
{{ vars.variable_prefix.my_variable | upperstring }}
....

Will display the variable in uppercase.

Iteration

To iterate over a list, for example defined with:

....
variable_iterator("variable_prefix", "iterator_name", "a,b,c", ",")
....

Use the following file:

....
{% for item in vars.variable_prefix.iterator_name %}
{{ item }} is the current iterator_name value
{% endfor %}
....

Which will be expanded as:

....
a is the current iterator_name value
b is the current iterator_name value
c is the current iterator_name value
....

To iterate over a container defined by the following json file, loaded
with `variable_dict_from_file("variable_prefix", "dict_name", "path")`:

....
{
   "hosts": [
       "host1",
       "host2"
   ],
   "files": [
       {"name": "file1", "path": "/path1", "users": [ "user1", "user11" ] },
       {"name": "file2", "path": "/path2", "users": [ "user2" ] }
   ],
   "properties": {
       "prop1": "value1",
       "prop2": "value2"
   }
}
....

Use the following template:

....
{% for item in vars.variable_prefix.dict_name.hosts %}
{{ item }} is the current hosts value
{% endfor %}

# will display the name and path of the current file
{% for file in vars.variable_prefix.dict_name.files %}
{{ file.name }}: {{ file.path }}
{% endfor %}

# will display the users list of each file
{% for file in vars.variable_prefix.dict_name.files %}
{{ file.name }}: {{ file.users|join(' ') }}
{% endfor %}


# will display the current properties key/value pair
{% for key, value in vars.variable_prefix.dict_name.properties.items() %}
{{ key }} -> {{ value }}
{% endfor %}
....

Which will be expanded as:

....
host1 is the current hosts value
host2 is the current hosts value

# will display the name and path of the current file
file1: /path1
file2: /path2

# will display the users list of each file
file1: user1 user11
file2: user2

# will display the current properties key/value pair
prop1 -> value1
prop2 -> value2
....

Parameters
++++++++++

* *source_template*: Source file containing a template to be expanded
(absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_template_${destination}_{kept, repaired, not_ok, reached}
....

file_from_template_mustache
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Build a file from a mustache template

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_file_from_template_type[file_from_template_type] for general
documentation about templates usage.

Syntax
++++++

Mustache is a logic-less templating language, available in a lot of
languages, and used for file templating in CFEngine. The mustache syntax
reference is https://mustache.github.io/mustache.5.html.

We will here describe the way to get agent data into a template. Ass
explained in the general templating documentation, we can access various
data in a mustache template.

The main specificity compared to standard mustache syntax of prefixes in
all expanded values:

* `classes` to access conditons
* `vars` to access all variables

Classes

Here is how to display content depending on conditions definition:

....
{{#classes.my_condition}}
   content when my_condition is defined
{{/classes.my_condition}}

{{^classes.my_condition}}
   content when my_condition is *not* defined
{{/classes.my_condition}}
....

Note: You cannot use condition expressions here.

Scalar variable

Here is how to display a scalar variable value (integer, string, …), if
you have defined
`variable_string("variable_prefix", "my_variable", "my_value")`:

....
{{{vars.variable_prefix.my_variable}}}
....

We use the triple `{{{ }}}` to avoid escaping html entities.

Iteration

Iteration is done using a syntax similar to scalar variables, but
applied on container variables.

* Use `{{#vars.container}} content {{/vars.container}}` to iterate
* Use `{{{.}}}` for the current element value in iteration
* Use `{{{key}}}` for the `key` value in current element
* Use `{{{.key}}}` for the `key` value in current element (Linux only)
* Use `{{{@}}}` for the current element key in iteration (Linux only)

To iterate over a list, for example defined with:

....
variable_iterator("variable_prefix", "iterator_name", "a,b,c", ",")
....

Use the following file:

....
{{#vars.variable_prefix.iterator_name}}
{{{.}}} is the current iterator_name value
{{/vars.variable_prefix.iterator_name}}
....

Which will be expanded as:

....
a is the current iterator_name value
b is the current iterator_name value
c is the current iterator_name value
....

To iterate over a container defined by the following json file, loaded
with `variable_dict_from_file("variable_prefix", "dict_name", "path")`:

....
{
   "hosts": [
       "host1",
       "host2"
   ],
   "files": [
       {"name": "file1", "path": "/path1", "users": [ "user1", "user11" ] },
       {"name": "file2", "path": "/path2", "users": [ "user2" ] }
   ],
   "properties": {
       "prop1": "value1",
       "prop2": "value2"
   }
}
....

Use the following template:

....
{{#vars.variable_prefix.dict_name.hosts}}
{{{.}}} is the current hosts value
{{/vars.variable_prefix.dict_name.hosts}}

# will display the name and path of the current file
{{#vars.variable_prefix.dict_name.files}}
{{{.name}}}: {{{.path}}}
{{/vars.variable_prefix.dict_name.files}}

# will display the users list of each file
{{#vars.variable_prefix.dict_name.files}}
{{{.name}}}:{{#users}} {{{.}}}{{/users}}
{{/vars.variable_prefix.dict_name.files}}


# will display the current properties key/value pair
{{#vars.variable_prefix.dict_name.properties}}
{{{@}}} -> {{{.}}}
{{/vars.variable_prefix.dict_name.properties}}
....

Which will be expanded as:

....
host1 is the current hosts value
host2 is the current hosts value

# will display the name and path of the current file
file1: /path1
file2: /path2

# will display the users list of each file
file1: user1 user11
file2: user2

# will display the current properties key/value pair
prop1 -> value1
prop2 -> value2
....

Note: You can use `{{#-top-}} ... {{/-top-}}` to iterate over the top
level container.

Parameters
++++++++++

* *source_template*: Source file containing a template to be expanded
(absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_from_template_${destination}_{kept, repaired, not_ok, reached}
....

file_from_template_type
^^^^^^^^^^^^^^^^^^^^^^^

Build a file from a template

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

These methods write a file based on a provided template and the data
available to the agent.

Usage
+++++

To use these methods (`file_from_template_*`), you need to have:

* a template file
* data to fill this template

The template file should be somewhere on the local file system, so if
you want to use a file shared from the policy server, you need to copy
it first (using
link:#_file_copy_from_remote_source[file_copy_from_remote_source]).

It is common to use a specific folder to store those templates after
copy, for example in `${sys.workdir}/templates/`.

The data that will be used while expanding the template is the data
available in the agent at the time of expansion. That means:

* CFEngine’s sytem variables (`${sys.*}`, …) and conditions (`linux`, …)
* data defined during execution (result conditions of generic methods,
…)
* conditions based on `condition_` generic methods
* data defined in ncf using `variable_*` generic methods, which allow
for example to load data from local json or yaml files.

Template types
++++++++++++++

ncf currently supports three templating languages:

* _mustache_ templates, which are documented in
link:#_file_from_template_mustache[file_from_template_mustache]
* _jinja2_ templates, which are documented in
link:#_file_from_template_jinja2[file_from_template_jinja2]
* CFEngine templates, which are a legacy implementation that is here for
compatibility, and should not be used for new templates.

Example
+++++++

Here is a complete example of templating usage:

The (basic) template file, present on the server in
`/PATH_TO_MY_FILE/ntp.conf.mustache` (for syntax reference, see
link:#_file_from_template_mustache[file_from_template_mustache]):

....
{{#classes.linux}}
server {{{vars.configuration.ntp.hostname}}}
{{/classes.linux}}
{{^classes.linux}}
server hardcoded.server.example
{{/classes.linux}}
....

And on your local node in `/tmp/ntp.json`, the following json file:

....
{ "hostname": "my.hostname.example" }
....

And the following policy:

....
# Copy the file from the policy server
file_copy_from_remote_source("/PATH_TO_MY_FILE/ntp.conf.mustache", "${sys.workdir}/templates/ntp.conf.mustache")
# Define the `ntp` varibale in the `configuration` prefix from the json file
variable_dict_from_file("configuration", "ntp", "/tmp/ntp.json")
# Expand yout template
file_from_template_type("${sys.workdir}/templates/ntp.conf.mustache", "/etc/ntp.conf", "mustache")
# or
# file_from_template_mustache("${sys.workdir}/templates/ntp.conf.mustache", "/etc/ntp.conf")
....

The destination file will contain the expanded content, for example on a
Linux node:

....
server my.hostname.example
....

Parameters
++++++++++

* *source_template*: Source file containing a template to be expanded
(absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *template_type*: Template type (cfengine, jinja2 or mustache)

Classes defined
+++++++++++++++

....

file_from_template_${destination}_{kept, repaired, not_ok, reached}
....

file_key_value_parameter_absent_in_list
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a parameter doesn’t exist in a list of parameters, on one
single line, in the right hand side of a key->values line

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit the file, and ensure it does not contain the defined parameter in
the list of values on the right hand side of a key->values line. If the
parameter is there, it will be removed. Please note that the parameter
can be a regular expression. It will also remove any whitespace
character between the parameter and parameter_separator Optionnaly, you
can define leading and closing character to enclose the parameters

Example
+++++++

If you have an initial file (`/etc/default/grub`) containing

....
GRUB_CMDLINE_XEN="dom0_mem=16G dom0_max_vcpus=32"
....

To remove parameter `dom0_max_vcpus=32` in the right hand side of the
line, you’ll need the following policy

....
file_ensure_key_value_parameter_not_in_list("/etc/default/grub", "GRUB_CMDLINE", "=", "dom0_max_vcpus=32", " ", "\"", "\"");
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Full key name
* *key_value_separator*: character used to separate key and value in a
key-value line
* *parameter_regex*: Regular expression matching the sub-value to ensure
is not present in the list of parameters that form the value part of
that line
* *parameter_separator*: Character used to separate parameters in the
list
* *leading_char_separator*: leading character of the parameters
* *closing_char_separator*: closing character of the parameters

Classes defined
+++++++++++++++

....

file_key_value_parameter_absent_in_list_${file}_{kept, repaired, not_ok, reached}
....

file_key_value_parameter_present_in_list
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that one parameter exists in a list of parameters, on one single
line, in the right hand side of a key->values line

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit the file, and ensure it contains the defined parameter in the list
of values on the right hand side of a key->values line. If the parameter
is not there, it will be added at the end, separated by
parameter_separator. Optionnaly, you can define leading and closing
character to enclose the parameters If the key does not exist in the
file, it will be added in the file, along with the parameter

Example
+++++++

If you have an initial file (`/etc/default/grub`) containing

....
GRUB_CMDLINE_XEN="dom0_mem=16G"
....

To add parameter `dom0_max_vcpus=32` in the right hand side of the line,
you’ll need the following policy

....
file_ensure_key_value_parameter_in_list("/etc/default/grub", "GRUB_CMDLINE", "=", "dom0_max_vcpus=32", " ", "\"", "\"");
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Full key name
* *key_value_separator*: character used to separate key and value in a
key-value line
* *parameter*: String representing the sub-value to ensure is present in
the list of parameters that form the value part of that line
* *parameter_separator*: Character used to separate parameters in the
list
* *leading_char_separator*: leading character of the parameters
* *closing_char_separator*: closing character of the parameters

Classes defined
+++++++++++++++

....

file_key_value_parameter_present_in_list_${file}_{kept, repaired, not_ok, reached}
....

file_key_value_present
^^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains a pair of ``key separator value''

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit (or create) the file, and ensure it contains an entry key -> value
with arbitrary separator between the key and its value. If the key is
already present, the method will change the value associated with this
key.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Key to define
* *value*: Value to define
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)

Classes defined
+++++++++++++++

....

file_key_value_present_${file}_{kept, repaired, not_ok, reached}
....

file_key_value_present_in_ini_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a key-value pair is present in a section in a specific
location. The objective of this method is to handle INI-style files.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section*: Name of the INI-style section under which the line should
be added or modified (not including the [] brackets)
* *name*: Name of the key to add or edit
* *value*: Value of the key to add or edit

Classes defined
+++++++++++++++

....

file_key_value_present_in_ini_section_${file}_{kept, repaired, not_ok, reached}
....

file_key_value_present_option
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains a pair of ``key separator value'', with
options on the spacing around the separator

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Edit (or create) the file, and ensure it contains an entry key -> value
with arbitrary separator between the key and its value. If the key is
already present, the method will change the value associated with this
key.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *key*: Key to define
* *value*: Value to define
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)
* *option*: Option for the spacing around the separator: strict, which
prevent spacings (space or tabs) around separators, or lax which accepts
any number of spaces around separators

Classes defined
+++++++++++++++

....

file_key_value_present_${file}_{kept, repaired, not_ok, reached}
....

file_keys_values_present
^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that the file contains all pairs of ``key separator value'', with
arbitrary separator between each key and its value

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method ensures key-value pairs are present in a file.

Usage
+++++

This method will iterate over the key-value pairs in the dict, and:

* If the key is not defined in the destination, add the _key_ +
_separator_ + _value_ line.
* If the key is already present in the file, replace the _key_ +
_separator_ + anything by _key_ + _separator_ + _value_

This method always ignores spaces and tabs when replacing (which means
for example that `key = value` will match the `=` separator).

Keys are considered unique (to allow replacing the value), so you should
use link:#_file_ensure_lines_present[file_ensure_lines_present] if you
want to have multiple lines with the same key.

Example
+++++++

If you have an initial file (`/etc/myfile.conf`) containing:

....
key1 = something
key3 = value3
....

To define key-value pairs, use the link:#_variable_dict[variable_dict]
or link:#_variable_dict_from_file[variable_dict_from_file] methods.

For example, if you use the following content (stored in
`/tmp/data.json`):

....
{
   "key1": "value1",
   "key2": "value2"
}
....

With the following policy:

....
# Define the `content` variable in the `configuration` prefix from the json file
variable_dict_from_file("configuration", "content", "/tmp/data.json")
# Enforce the presence of the key-value pairs
file_ensure_keys_values("/etc/myfile.conf", "configuration.content", " = ")
....

The destination file (`/etc/myfile.conf`) will contain:

....
key1 = value1
key3 = value3
key2 = value2
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *keys*: Name of the dict structure (without ``$\{}'') containing the
keys (keys of the dict), and values to define (values of the dict)
* *separator*: Separator between key and value, for example ``='' or " "
(without the quotes)

Classes defined
+++++++++++++++

....

file_keys_values_present_${file}_{kept, repaired, not_ok, reached}
....

file_line_present_in_ini_section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a line is present in a section in a specific location. The
objective of this method is to handle INI-style files.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *section*: Name of the INI-style section under which lines should be
added (not including the [] brackets)
* *line*: Line to ensure is present inside the section

Classes defined
+++++++++++++++

....

file_line_present_in_ini_section_${file}_{kept, repaired, not_ok, reached}
....

file_line_present_in_xml_tag
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a line is present in a tag in a specific location. The
objective of this method is to handle XML-style files. Note that if the
tag is not present in the file, it won’t be added, and the edition will
fail.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *tag*: Name of the XML tag under which lines should be added (not
including the <> brackets)
* *line*: Line to ensure is present inside the section

Classes defined
+++++++++++++++

....

file_line_present_in_xml_tag_${file}_{kept, repaired, not_ok, reached}
....

file_lines_absent
^^^^^^^^^^^^^^^^^

Ensure that a line is absent in a specific location

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to remove in the file

Classes defined
+++++++++++++++

....

file_lines_absent_${file}_{kept, repaired, not_ok, reached}
....

file_lines_present
^^^^^^^^^^^^^^^^^^

Ensure that one or more lines are present in a file

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *lines*: Line(s) to add in the file

Classes defined
+++++++++++++++

....

file_lines_present_${file}_{kept, repaired, not_ok, reached}
....

file_present
^^^^^^^^^^^^

Create a file if it doesn’t exist

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *target*: File to create (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_present_${target}_{kept, repaired, not_ok, reached}
....

file_remove
^^^^^^^^^^^

Remove a file if it exists

*WARNING*: This generic method is deprecated. Use
link:#_file_absent[file_absent] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *target*: File to remove (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_remove_${target}_{kept, repaired, not_ok, reached}
....

file_replace_lines
^^^^^^^^^^^^^^^^^^

Ensure that a line in a file is replaced by another one

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

You can replace lines in a files, based on regular expression and
captured pattern

Syntax
++++++

The content to match in the file is a PCRE regular expression,
unanchored that you can replace with the content of replacement.

Content can be captured in regular expression, and be reused with the
notation `${match.1}` (for first matched content), `${match.2}` for
second, etc, and the special captured group `${match.0}` for the whole
text.

Example
+++++++

Here is an example to remove enclosing specific tags

....
file_replace_lines("/PATH_TO_MY_FILE/file", "<my>(.*)<pattern>", "my ${match.1} pattern")
....

Parameters
++++++++++

* *file*: File name to edit (absolute path on the target node)
* *line*: Line to match in the file
* *replacement*: Line to add in the file as a replacement

Classes defined
+++++++++++++++

....

file_replace_lines_${file}_{kept, repaired, not_ok, reached}
....

file_report_content
^^^^^^^^^^^^^^^^^^^

Report the content of a file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Report the content of a file.

This method does nothing on the system, but only reports a complete or
partial content from a given file. This allows centralizing this
information on the searver, and avoid having to connect on each node to
get this information.

NOTE: This method only works in ``Full Compliance'' reporting mode.

Parameters
++++++++++

Target

This is the file you want to report content from. The method will return
an error if it does not exist.

Regex

If empty, the method will report the whole file content. If set, the
method will grep the file for the given regular expression, and report
the result.

Context

When specifying a regex, will add the number of lines of context around
matches (default is 0, i.e. no context).

When reporting the whole file, this parameter is ignored.

Examples
++++++++

....
# To get the whole /etc/hosts content
file_report_content("/etc/hosts", "", "");
# To get lines starting by "nameserver" in /etc/resolv.conf
file_report_content("/etc/resolv.conf", "^nameserver", "");
# To get lines containing "rudder" from /etc/hosts with 3 lines of context
file_report_content("/etc/hosts", "rudder", "3");
....

Parameters
++++++++++

* *target*: File to report content from
* *regex*: Regex to search in the file (empty for whole file)
* *context*: Number of context lines when matching regex (default is 0)

Classes defined
+++++++++++++++

....

file_report_content_${target}_{kept, repaired, not_ok, reached}
....

file_report_content_head
^^^^^^^^^^^^^^^^^^^^^^^^

Report the head of a file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Report the head of a file.

This method does nothing on the system, but only reports a partial
content from a given file. This allows centralizing this information on
the searver, and avoid having to connect on each node to get this
information.

NOTE: This method only works in ``Full Compliance'' reporting mode.

Parameters
++++++++++

Target

This is the file you want to report content from. The method will return
an error if it does not exist.

Limit

The number of line to report.

Examples
++++++++

....
# To get the 3 first line of /etc/hosts
file_report_content("/etc/hosts", "3");
....

Parameters
++++++++++

* *target*: File to report content from
* *limit*: Number of lines to report (default is 10)

Classes defined
+++++++++++++++

....

file_report_content_head_${target}_{kept, repaired, not_ok, reached}
....

file_report_content_tail
^^^^^^^^^^^^^^^^^^^^^^^^

Report the tail of a file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Report the tail of a file.

This method does nothing on the system, but only reports a partial
content from a given file. This allows centralizing this information on
the searver, and avoid having to connect on each node to get this
information.

NOTE: This method only works in ``Full Compliance'' reporting mode.

Parameters
++++++++++

Target

This is the file you want to report content from. The method will return
an error if it does not exist.

Limit

The number of line to report.

Examples
++++++++

....
# To get the 3 first line of /etc/hosts
file_report_content("/etc/hosts", "3");
....

Parameters
++++++++++

* *target*: File to report content from
* *limit*: Number of lines to report (default is 10)

Classes defined
+++++++++++++++

....

file_report_content_tail_${target}_{kept, repaired, not_ok, reached}
....

file_symlink_present
^^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target
except if a file or directory already exists.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_symlink_present_${destination}_{kept, repaired, not_ok, reached}
....

file_symlink_present_force
^^^^^^^^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target
even if a file or directory already exists.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)

Classes defined
+++++++++++++++

....

file_symlink_present_${destination}_{kept, repaired, not_ok, reached}
....

file_symlink_present_option
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Create a symlink at a destination path and pointing to a source target.
This is also possible to enforce its creation

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *source*: Source file (absolute path on the target node)
* *destination*: Destination file (absolute path on the target node)
* *enforce*: Force symlink if file already exist (true or false)

Classes defined
+++++++++++++++

....

file_symlink_present_${destination}_{kept, repaired, not_ok, reached}
....

file_template_expand
^^^^^^^^^^^^^^^^^^^^

This is a bundle to expand a template in a specific location

*WARNING*: This generic method is deprecated. This method uses
CFEngine’s templating which is deprecated and not portable accross
agents. Please use
link:#_file_from_template_mustache[file_from_template_mustache] or
link:#_file_from_template_jinja2[file_from_template_jinja2] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *tml_file*: File name (with full path within the framework) of the
template file
* *target_file*: File name (with full path) where to expand the template
* *mode*: Mode of destination file
* *owner*: Owner of destination file
* *group*: Froup of destination file

Classes defined
+++++++++++++++

....

file_template_expand_${target_file}_{kept, repaired, not_ok, reached}
....

Group
~~~~~

group_absent
^^^^^^^^^^^^

Make sure a group is absent

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *group*: Group name

Classes defined
+++++++++++++++

....

group_absent_${group}_{kept, repaired, not_ok, reached}
....

group_present
^^^^^^^^^^^^^

Create a group

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *group*: Group name

Classes defined
+++++++++++++++

....

group_present_${group}_{kept, repaired, not_ok, reached}
....

Http
~~~~

http_request_check_status_headers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Checks status of an HTTP URL

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Perform a HTTP request on the URL, method and headers provided and check
that the response has the expected status code (ie 200, 404, 503, etc)

Parameters
++++++++++

* *method*: Method to call the URL (GET, POST, PUT, DELETE)
* *url*: URL to query
* *expected_status*: Expected status code of the HTTP response
* *headers*: Headers to include in the HTTP request (as a string,
without ’)

Classes defined
+++++++++++++++

....

http_request_check_status_headers_${url}_{kept, repaired, not_ok, reached}
....

http_request_content_headers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Make an HTTP request with a specific header

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Perform a HTTP request on the URL, method and headers provided and send
the content provided. Will return an error if the request failed.

Parameters
++++++++++

* *method*: Method to call the URL (POST, PUT)
* *url*: URL to send content to
* *content*: Content to send
* *headers*: Headers to include in the HTTP request

Classes defined
+++++++++++++++

....

http_request_content_headers_${url}_{kept, repaired, not_ok, reached}
....

Kernel
~~~~~~

kernel_module_configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that the modprobe configuration of a given kernel module is
correct

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that the modprobe configuration of a given kernel module is
correct. Rudder will search for the module configuration in a per-module
dedicated section in /etc/modprobe.d/managed_by_rudder.conf.

* If the module configuration is not found or incorrect, Rudder will
(re-)create its configuration.
* If the module is configured but with a different option file than used
by Rudder, it will add the expected one in
/etc/modprobe.d/managed_by_rudder.conf but will leave intact the already
present one.

The configuration syntax must respect the one used by /etc/modprobe.d
defined in the modprobe.d manual page.
`# To pass a parameter to a module:    options module_name parameter_name=parameter_value    # To blacklist a module    blacklist modulename    # etc...`

Notes:
++++++

If you want to force the module to be loaded at boot, use instead the
method `kernel_module_enabled_at_boot` which uses other Rudder dedicated
files.

Example:
++++++++

To pass options to a broadcom module * `module_name` = b43 *
`configuration` = options b43 nohwcrypt=1 qos=0

Will produce the resulting block in
/etc/modprobe.d/managed_by_rudder.conf:
`### b43 start section  options b43 nohwcrypt=1 qos=0  ### b43 end section`

Parameters
++++++++++

* *module_name*: Complete name of the kernel module, as seen by lsmod or
listed in /proc/modules
* *configuration*: Complete configuration block to put in
/etc/modprobe.d/

Classes defined
+++++++++++++++

....

kernel_module_configuration_${module_name}_{kept, repaired, not_ok, reached}
....

kernel_module_enabled_at_boot
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a given kernel module will be loaded at system boot

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a given kernel module is enabled at boot on the system. This
method only works on systemd systems. Rudder will look for a line
matching the module name in a given section in the file:

* `/etc/modules-load.d/enabled_by_rudder.conf` on systemd systems

If the module is already enabled by a different option file than used by
Rudder, it will add an entry in the file managed by Rudder listed above,
and leave intact the already present one. The modifications are
persistent and made line per line, meaning that this Generic Method will
never remove lines in the configuration file but only add it if needed.

Please note that this method will not load the module nor configure it,
it will only enable its loading at system boot. If you want to force the
module to be loaded, use instead the method `kernel_module_loaded`. If
you want to configure the module, use instead the method
`kernel_module_configuration`.

Parameters
++++++++++

* *module_name*: Complete name of the kernel module, as seen by lsmod or
listed in /proc/modules

Classes defined
+++++++++++++++

....

kernel_module_enabled_at_boot_${module_name}_{kept, repaired, not_ok, reached}
....

kernel_module_loaded
^^^^^^^^^^^^^^^^^^^^

Ensure that a given kernel module is loaded on the system

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a given kernel module is loaded on the system. If the module
is not loaded, it will try to load it via modprobe.

Parameters
++++++++++

* *module_name*: Complete name of the kernel module, as seen by lsmod or
listed in /proc/modules

Classes defined
+++++++++++++++

....

kernel_module_loaded_${module_name}_{kept, repaired, not_ok, reached}
....

kernel_module_not_loaded
^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a given kernel module is not loaded on the system

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a given kernel module is not loaded on the system. If the
module is loaded, it will try to unload it using modprobe.

Parameters
++++++++++

* *module_name*: Complete name of the kernel module, as seen by lsmod or
listed in /proc/modules

Classes defined
+++++++++++++++

....

kernel_module_not_loaded_${module_name}_{kept, repaired, not_ok, reached}
....

Monitoring
~~~~~~~~~~

monitoring_parameter
^^^^^^^^^^^^^^^^^^^^

Add a monitoring parameter to a node (requires a monitoring plugin)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method adds monitoring parameters to rudder nodes. The monitoring
parameters are used to pass configuration to the monitoring plugins
running with Rudder. Expected keys and parameters are specific to each
plugin and can be found in their respective documentation.

Parameters
++++++++++

* *key*: Name of the parameter
* *value*: Value of the parameter

Classes defined
+++++++++++++++

....

monitoring_parameter_${key}_{kept, repaired, not_ok, reached}
....

monitoring_template
^^^^^^^^^^^^^^^^^^^

Add a monitoring template to a node (requires a monitoring plugin)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method assigns monitoring templates to a Rudder node. The Rudder
plugin respective to each monitoring platform will apply those templates
to the node.

Parameters
++++++++++

* *template*: Name of the monitoring template

Classes defined
+++++++++++++++

....

monitoring_template_${template}_{kept, repaired, not_ok, reached}
....

Package
~~~~~~~

package_absent
^^^^^^^^^^^^^^

Enforce the absence of a package

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_package_state[package_state] for documentation.

Parameters
++++++++++

* *name*: Name of the package
* *version*: Version of the package or ``any'' for any version (defaults
to ``any'')
* *architecture*: Architecture of the package, can be an architecture
name or ``default'' (defaults to ``default'')
* *provider*: Package provider to use, can be ``yum'', ``apt'',
``zypper'', ``zypper_pattern'', ``slackpkg'', ``pkg'' or ``default'' for
system default package manager (defaults to ``default'')

Classes defined
+++++++++++++++

....

package_absent_${name}_{kept, repaired, not_ok, reached}
....

package_check_installed
^^^^^^^^^^^^^^^^^^^^^^^

Verify if a package is installed in any version

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`package_check_installed_${file_name}_{ok, reached, kept}` if the
package is installed, or
`package_check_installed_${file_name}_{not_ok, reached, not_kept, failed}`
if the package is not installed

Parameters
++++++++++

* *package_name*: Name of the package to check

Classes defined
+++++++++++++++

....

package_check_installed_${package_name}_{kept, repaired, not_ok, reached}
....

package_install
^^^^^^^^^^^^^^^

Install or update a package in its latest version available

*WARNING*: This generic method is deprecated. Use
link:#_package_present[package_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *package_name*: Name of the package to install

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

package_install_version
^^^^^^^^^^^^^^^^^^^^^^^

Install or update a package in a specific version

*WARNING*: This generic method is deprecated. Use
link:#_package_present[package_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *package_name*: Name of the package to install
* *package_version*: Version of the package to install (can be
``latest'' to install it in its latest version)

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

package_install_version_cmp
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Install a package or verify if it is installed in a specific version, or
higher or lower version than a version specified

*WARNING*: This generic method is deprecated. Use
link:#_package_present[package_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

_Example_:

....
methods:
    "any" usebundle => package_install_version_cmp("postgresql", ">=", "9.1", "verify");
....

Parameters
++++++++++

* *package_name*: Name of the package to install or verify
* *version_comparator*: Comparator between installed version and defined
version, can be ==,<=,>=,<,>,!=
* *package_version*: The version of the package to verify (can be
``latest'' for latest version)
* *action*: Action to perform, can be add, verify (defaults to verify)

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

package_install_version_cmp_update
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Install a package or verify if it is installed in a specific version, or
higher or lower version than a version specified, optionally test update
or not (Debian-, Red Hat- or SuSE-like systems only)

*WARNING*: This generic method is deprecated. Use
link:#_package_present[package_present] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

_Example_:

....
methods:
    "any" usebundle => package_install_version_cmp_update("postgresql", ">=", "9.1", "verify", "false");
....

Parameters
++++++++++

* *package_name*: Name of the package to install or verify
* *version_comparator*: Comparator between installed version and defined
version, can be ==,<=,>=,<,>,!=
* *package_version*: The version of the package to verify (can be
``latest'' for latest version)
* *action*: Action to perform, can be add, verify (defaults to verify)
* *update_policy*: While verifying packages, check against latest
version (``true'') or just installed (``false'')

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

package_present
^^^^^^^^^^^^^^^

Enforce the presence of a package

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_package_state[package_state] for documentation.

Parameters
++++++++++

* *name*: Name of the package, or path to a local package
* *version*: Version of the package, can be ``latest'' for latest
version or ``any'' for any version (defaults to ``any'')
* *architecture*: Architecture of the package, can be an architecture
name or ``default'' (defaults to ``default'')
* *provider*: Package provider to use, can be ``yum'', ``apt'',
``zypper'', ``zypper_pattern'', ``slackpkg'', ``pkg'' or ``default'' for
system default package manager (defaults to ``default'')

Classes defined
+++++++++++++++

....

package_present_${name}_{kept, repaired, not_ok, reached}
....

package_remove
^^^^^^^^^^^^^^

Remove a package

*WARNING*: This generic method is deprecated. Use
link:#_package_absent[package_absent] instead.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

_Example_:

....
methods:
    "any" usebundle => package_remove("htop");
....

Parameters
++++++++++

* *package_name*: Name of the package to remove

Classes defined
+++++++++++++++

....

package_remove_${package_name}_{kept, repaired, not_ok, reached}
....

package_state
^^^^^^^^^^^^^

Enforce the state of a package

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

These methods manage packages using a package manager on the system.

`package_present` and `package_absent` use a new package implementation,
different from `package_install_*`, `package_remove_*` and
`package_verify_*`. It should be more reliable, and handle upgrades
better. It is compatible though, and you can call generic methods from
both implementations on the same host. The only drawback is that the
agent will have to maintain double caches for package lists, which may
cause a little unneeded overhead.

Setup
+++++

If you are using ncf inside Rudder, no specific setup is necessary.

If your are using ncf without Rudder, you need to call the
`initialization` bundle before using package methods.

Package parameters
++++++++++++++++++

There is only one mandatory parameter, which is the package name to
install. When it should be installed from a local package, you need to
specify the full path to the package as name.

The version parameter allows specifying a version you want installed. It
should be the complete versions string as used by the used package
manager. This parameter allows two special values:

* _any_ which is the default value, and is satisfied by any version of
the given package
* _latest_ which will ensure, at each run, that the package is at the
latest available version.

The last parameter is the provider, which is documented in the next
section.

You can use link:#_package_state_options[package_state_options] to pass
options to the underlying package manager (currently only with _apt_
package manager).

Package providers
+++++++++++++++++

This method supports several package managers. You can specify the
package manager you want to use or let the method choose the default for
the local system.

The package providers include a caching system for package information.
The package lists (installed, available and available updates) are only
updated when the cache expires, or when an operation is made by the
agent on packages.

_Note_: The implementation of package operations is done in scripts
called modules, which you can find in
`${sys.workdir}/modules/packages/`.

apt

This package provider uses _apt_/_dpkg_ to manage packages on the
system. _dpkg_ will be used for all local actions, and _apt_ is only
needed to manage update and installation from a repository.

rpm

This package provider uses _yum_/_rpm_ to manage packages on the system.
_rpm_ will be used for all local actions, and _yum_ is only needed to
manage update and installation from a repository.

It is able to downgrade packages when specifying an older version.

zypper

This package provider uses _zypper_/_rpm_ to manage packages on the
system. _rpm_ will be used for all local actions, and _zypper_ is only
needed to manage update and installation from a repository.

Note: If the package version you want to install contains an epoch, you
have to specify it in the version in the `epoch:version` form, like
reported by `zypper info`.

zypper_pattern

This package provider uses zypper with the `-t pattern` option to manage
zypper patterns or meta-packages on the system.

Since a zypper pattern can be named differently than the rpm package
name providing it, please always use the exact pattern name (as listed
in the output of `zypper patterns`) when using this provider.

Note: When installing a pattern from a local rpm file, Rudder assumes
that the pattern is built following the
https://doc.opensuse.org/projects/libzypp/HEAD/zypp-pattern-packages.html[official
zypper documentation].

Older implementations of zypper patterns may not be supported by this
module.

slackpkg

This package provider uses Slackware’s installpkg and upgradepkg tools
to manage packages on the system

pkg

This package provider uses FreeBSD’s _pkg_ to manage packages on the
system.

Examples
++++++++

....
# To install postgresql in version 9.1 for x86_64 atchitecture
package_present("postgresql", "9.1", "x86_64", "");
# To ensure postgresql is always in the latest available version
package_present("postgresql", "latest", "", "");
# To ensure installing postgresql in any version
package_present("postgresql", "", "", "");
# To ensure installing postgresql in any version, forcing the yum provider
package_present("postgresql", "", "", "yum");
# To ensure installing postgresql from a local package
package_present("/tmp/postgresql-9.1-1.x86_64.rpm", "", "", "");
# To remove postgresql
package_absent("postgresql", "", "", "");
....

See also : link:#_package_present[package_present],
link:#_package_absent[package_absent],
link:#_package_state_options[package_state_options]

Parameters
++++++++++

* *name*: Name of the package, or path to a local package if state is
present
* *version*: Version of the package, can be ``latest'' for latest
version or ``any'' for any version (defaults to ``any'')
* *architecture*: Architecture of the package, can be an architecture
name or ``default'' (defaults to ``default'')
* *provider*: Package provider to use, can be ``yum'', ``apt'',
``zypper'', ``zypper_pattern'', ``slackpkg'', ``pkg'' or ``default'' for
system default package manager (defaults to ``default'')
* *state*: State of the package, can be ``present'' or ``absent''
(defaults to ``present'')

Classes defined
+++++++++++++++

....

package_state_${name}_{kept, repaired, not_ok, reached}
....

package_state_options
^^^^^^^^^^^^^^^^^^^^^

Enforce the state of a package with options

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_package_state[package_state] for documentation.

Parameters
++++++++++

* *name*: Name of the package, or path to a local package if state is
present
* *version*: Version of the package, can be ``latest'' for latest
version or ``any'' for any version (defaults to ``any'')
* *architecture*: Architecture of the package, can be an architecture
name or ``default'' (defaults to ``default'')
* *provider*: Package provider to use, can be ``yum'', ``apt'',
``zypper'', ``zypper_pattern'', ``slackpkg'', ``pkg'' or ``default'' for
system default package manager (defaults to ``default'')
* *state*: State of the package, can be ``present'' or ``absent''
(defaults to ``present'')
* *options*: Options no pass to the package manager (defaults to empty)

Classes defined
+++++++++++++++

....

package_state_options_${name}_{kept, repaired, not_ok, reached}
....

package_verify
^^^^^^^^^^^^^^

Verify if a package is installed in its latest version available

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *package_name*: Name of the package to verify

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

package_verify_version
^^^^^^^^^^^^^^^^^^^^^^

Verify if a package is installed in a specific version

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *package_name*: Name of the package to verify
* *package_version*: Version of the package to verify (can be ``latest''
for latest version)

Classes defined
+++++++++++++++

....

package_install_${package_name}_{kept, repaired, not_ok, reached}
....

Permissions
~~~~~~~~~~~

permissions
^^^^^^^^^^^

Set permissions on a file or directory (non recursively)

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to the file/directory
* *mode*: Mode to enforce (like ``640'')
* *owner*: Owner to enforce (like ``root'')
* *group*: Group to enforce (like ``wheel'')

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_acl_entry
^^^^^^^^^^^^^^^^^^^^^

Verify that an ace is present on a file or directory. This method will
append the given aces to the current POSIX ACLs of the target.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be a regex with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

User and Group

ACE for user and group can be left blank if they do not need any
specification. If fulfill, they must respect the format:

`<username|groupname>:<operator><mode>`

with:

* `username` being the Linux account name
* `groupname` the Linux group name
* Current `owner user` and `owner group` can be designed by the
character `*`

The operator can be: * `+` to add the given ACE to the current ones. *
`-` to remove the given ACE to the current ones. * `=` to force the
given ACE to the current ones.

You can define multiple ACEs by separating them with commas.

Other

ACE for other must respect the classic:

* `[+-=]r?w?x?` It can also be left blank to let the `Other` ACE
unchanged.

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::---
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `user`: *:-x, bob:
* `group`: *:+rw
* `other`: =r

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rw-
user:bob:---
group::rw-
mask::rw-
other::r--
....

This method can not remove a given ACE, see here how the user bob ACE is
handled.

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'')
* *user*: User acls, comma separeted, like: bob:+rwx, alice:-w
* *group*: Group acls, comma separeted, like: wheel:+wx, anon:-rwx
* *other*: Other acls, like -x

Classes defined
+++++++++++++++

....

permissions_acl_entry_${path}_{kept, repaired, not_ok, reached}
....

permissions_dirs
^^^^^^^^^^^^^^^^

Verify if a directory has the right permissions non recursively

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path of the directory
* *mode*: Mode to enforce
* *owner*: Owner to enforce
* *group*: Group to enforce

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_dirs_recurse
^^^^^^^^^^^^^^^^^^^^^^^^

Verify if a directory has the right permissions recursively

*WARNING*: This generic method is deprecated. Use
link:#_permissions_dirs_recursive[permissions_dirs_recursive] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to the directory
* *mode*: Mode to enforce
* *owner*: Owner to enforce
* *group*: Group to enforce

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_dirs_recursive
^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify if a directory has the right permissions recursively

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to the directory
* *mode*: Mode to enforce
* *owner*: Owner to enforce
* *group*: Group to enforce

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_group_acl_absent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify that an ace is absent on a file or directory for a given group.
This method will make sure that no ace is present in the POSIX ACL of
the target.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be a regex with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

User

`Username` to enforce the ace absence, being the Linux account name.
This method can only handle one groupname.

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
group::r--
group:bob:rwx
mask::rwx
other::---
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `group`: bob

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
group::r--
mask::r--
other::---
....

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'')
* *group*: Group name

Classes defined
+++++++++++++++

....

permissions_group_acl_absent_${path}_{kept, repaired, not_ok, reached}
....

permissions_group_acl_present
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify that an ace is present on a file or directory for a given group.
This method will make sure the given ace is present in the POSIX ACL of
the target for the given group.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be a regex with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

Group

`Group` to enfoorce the ace, being the Linux account name. This method
can only handle one groupname.

ACE

The operator can be: * `+` to add the given ACE to the current ones. *
`-` to remove the given ACE to the current ones. * `=` to force the
given ACE to the current ones. * `empty` if no operator is specified, it
will be interpreted as `=`.

ACE must respect the classic:

* `^[+-=]?(?=.*[rwx])r?w?x?$`

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
group::r--
group:bob:rwx
mask::rwx
other::---
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `group`: bob
* `ace`: -rw

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
group::r--
group:bob:--x
mask::r-x
other::---
....

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'')
* *group*: Group name
* *ace*: ACE to enforce for the given group.

Classes defined
+++++++++++++++

....

permissions_group_acl_present_${path}_{kept, repaired, not_ok, reached}
....

permissions_ntfs
^^^^^^^^^^^^^^^^

Ensure NTFS permisions on a file for a given user.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that the correct NTFS permisions are applied on a file for a
given user.

Inheritence and propagation flags can also be managed. If left blank, no
propagation will be set.

To manage effective propagation or effective access, please disable the
inheritance on the file before applying this generic method.

Note: that the `Synchronize` permission may not work in some cases. This
is a known bug.

Right validate set:

None, ReadData, ListDirectory, WriteData, CreateFiles, AppendData,
CreateDirectories, ReadExtendedAttributes, WriteExtendedAttributes,
ExecuteFile, Traverse, DeleteSubdirectoriesAndFiles, ReadAttributes,
WriteAttributes, Write, Delete, ReadPermissions, Read, ReadAndExecute,
Modify, ChangePermissions, TakeOwnership, Synchronize, FullControl

AccesType validate set:

Allow, Deny

PropagationPolicy validate set:

ThisFolderOnly, ThisFolderSubfoldersAndFiles, ThisFolderAndSubfolders,
ThisFolderAndFiles, SubfoldersAndFilesOnly, SubfoldersOnly, FilesOnly

Parameters
++++++++++

* *path*: File path
* *user*: DOMAIN
* *rights*: Comma separated right list
* *accesstype*: ``Allow'' or ``Deny''
* *propagationpolicy*: Define the propagation policy of the access rule
that Rudder is applying

Classes defined
+++++++++++++++

....

permissions_ntfs_${path}_{kept, repaired, not_ok, reached}
....

permissions_other_acl_present
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify that the other ace given is present on a file or directory. This
method will make sure the given other ace is present in the POSIX ACL of
the target for.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be a regex with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

Other_ACE

The operator can be: * `+` to add the given ACE to the current ones. *
`-` to remove the given ACE to the current ones. * `=` to force the
given ACE to the current ones. * `empty` if no operator is specified, it
will be interpreted as `=`.

ACE must respect the classic:

* `^[+-=]?(?=.*[rwx])r?w?x?$`

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::r-x
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `other ace`: -rw

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::--x
....

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'')
* *other*: ACE to enforce for the given other.

Classes defined
+++++++++++++++

....

permissions_other_acl_present_${path}_{kept, repaired, not_ok, reached}
....

permissions_posix_acls_absent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that files or directories has no ACLs set

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.
#### Parameters

Path

Path can be globbing with the following format:

* ** matches any filename or directory at one level, e.g. _.cf will
match all files in one directory that end in .cf but it won’t search
across directories. _/*.cf on the other hand will look two levels deep.
* ? matches a single letter
* [a-z] matches any letter from a to z
* \{x,y,anything} will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

Example
+++++++

The method has basically the same effect as `setfacl -b <path>`.

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:vagrant:rwx
group::r--
mask::rwx
other::---
....

It will remove all ACLs, and only let classic rights, here:

....
root@server# getfacl myTestFile
# file: myTestFile
# owner: root
# group: root
user::rwx
group::r--
other::---

root@server# ls -l myTestFile
-rwxr----- 1 root root 0 Mar 22 11:24 myTestFile
root@server#
....

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Should ACLs cleanup be recursive, ``true'' or ``false''
(defaults to ``false'')

Classes defined
+++++++++++++++

....

permissions_posix_acls_absent_${path}_{kept, repaired, not_ok, reached}
....

permissions_recurse
^^^^^^^^^^^^^^^^^^^

Verify if a file or directory has the right permissions recursively

*WARNING*: This generic method is deprecated. Use
link:#_permissions_recursive[permissions_recursive] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to the file / directory
* *mode*: Mode to enforce
* *owner*: Owner to enforce
* *group*: Group to enforce

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_recursive
^^^^^^^^^^^^^^^^^^^^^

Verify if a file or directory has the right permissions recursively

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to the file / directory
* *mode*: Mode to enforce
* *owner*: Owner to enforce
* *group*: Group to enforce

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_type_recursion
^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a file or directory is present and has the right
mode/owner/group

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *path*: Path to edit
* *mode*: Mode of the path to edit
* *owner*: Owner of the path to edit
* *group*: Group of the path to edit
* *type*: Type of the path to edit (all/files/directories)
* *recursion*: Recursion depth to enforce for this path (0, 1, 2, …,
inf)

Classes defined
+++++++++++++++

....

permissions_${path}_{kept, repaired, not_ok, reached}
....

permissions_user_acl_absent
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify that an ace is absent on a file or directory for a given user.
This method will make sure that no ace is present in the POSIX ACL of
the target.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be a regex with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

User

`Username` to enforce the ace absence, being the Linux account name.
This method can only handle one username.

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::---
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `user`: bob

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
group::r--
mask::r--
other::---
....

Parameters
++++++++++

* *path*: Path of the file or directory
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'')
* *user*: Username of the Linux account.

Classes defined
+++++++++++++++

....

permissions_user_acl_absent_${path}_{kept, repaired, not_ok, reached}
....

permissions_user_acl_present
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify that an ace is present on a file or directory for a given user.
This method will make sure the given ace is present in the POSIX ACL of
the target.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `permissions_*acl_*` manage the POSIX ACL on files and directories.

Please note that the mask will be automatically recalculated when
editing ACLs.

Parameters
++++++++++

Path

Path can be globbing with the following format:

* `*` matches any filename or directory at one level, e.g. `*.cf` will
match all files in one directory that end in .cf but it won’t search
across directories. `*/*.cf` on the other hand will look two levels
deep.
* `?` matches a single letter
* `[a-z]` matches any letter from a to z
* `{x,y,anything}` will match x or y or anything.

Recursive

Can be:

* `true` to apply the given aces to folder and sub-folders and files.
* or `false` to apply to the strict match of `Path`

If left blank, recursivity will automatically be set to `false`

User

`Username` to enforce the ace, being the Linux account name. This method
can only handle one username.

ACE

The operator can be: * `+` to add the given ACE to the current ones. *
`-` to remove the given ACE to the current ones. * `=` to force the
given ACE to the current ones. * `empty` if no operator is specified, it
will be interpreted as `=`.

ACE must respect the classic:

* `^[+-=]?(?=.*[rwx])r?w?x?$`

Example
+++++++

Given a file with the following getfacl output:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::---
....

Applying this method with the following parameters:

* `path`: /tmp/myTestFile
* `recursive`: false
* `user`: bob
* `ace`: -rw

Will transform the previous ACLs in:

....
root@server# getfacl /tmp/myTestFile
getfacl: Removing leading '/' from absolute path names
# file: tmp/myTestFile
# owner: root
# group: root
user::rwx
user:bob:--x
group::r--
mask::r-x
other::---
....

Parameters
++++++++++

* *path*: Path of the file or directory.
* *recursive*: Recursive Should ACLs cleanup be recursive, ``true'' or
``false'' (defaults to ``false'').
* *user*: Username of the Linux account.
* *ace*: ACE to enforce for the given user.

Classes defined
+++++++++++++++

....

permissions_user_acl_present_${path}_{kept, repaired, not_ok, reached}
....

Registry
~~~~~~~~

registry_entry_absent
^^^^^^^^^^^^^^^^^^^^^

This generic method checks that a registry entry does not exists

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *key*: Registry key (ie, HKLM:)
* *entry*: Registry entry name

Classes defined
+++++++++++++++

....

registry_entry_absent_${entry}_{kept, repaired, not_ok, reached}
....

registry_entry_present
^^^^^^^^^^^^^^^^^^^^^^

This generic method defines if a registry entry exists with the correct
value

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *key*: Registry key (ie, HKLM:)
* *entry*: Registry entry
* *value*: Registry value
* *registryType*: Registry value type (String, ExpandString,
MultiString, Dword, Qword)

Classes defined
+++++++++++++++

....

registry_entry_present_${entry}_{kept, repaired, not_ok, reached}
....

registry_key_absent
^^^^^^^^^^^^^^^^^^^

This generic method checks that a registry key does not exists

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Remove a Registry Key if it is present on the system.

There are two different supported syntaxes to describe a Registry Key:

* with short drive name and ``:'' like HKLM:
* with long drive name and without ``:'' like HKEY_LOCAL_MACHINE:

Please, note that Rudder can not remove drives and ``first-level''
Registry Keys.

Parameters
++++++++++

* *key*: Registry key (ie, HKLM:)

Classes defined
+++++++++++++++

....

registry_key_absent_${key}_{kept, repaired, not_ok, reached}
....

registry_key_present
^^^^^^^^^^^^^^^^^^^^

This generic method checks that a Registry Key exists

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Create a Registry Key if it does not exist. There are two different
supported syntaxes to describe a Registry Key:

* with short drive name and ``:'' like HKLM:
* with long drive name and without ``:'' like HKEY_LOCAL_MACHINE:

Please, note that Rudder can not create new drive and new
``first-level'' Registry Keys.

Parameters
++++++++++

* *key*: Registry key (ie, HKLM:)

Classes defined
+++++++++++++++

....

registry_key_present_${key}_{kept, repaired, not_ok, reached}
....

Schedule
~~~~~~~~

schedule_simple
^^^^^^^^^^^^^^^

Trigger a repaired outcome when a job should be run

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method compute the expected time for running the job, based on the
parameters and splayed uing system ids, and define a conditions based on
this computation: * `schedule_simple_${job_id}_kept` if the job should
not be run now * `schedule_simple_${job_id}_repaired` if the job should
be run * `schedule_simple_${job_id}_error` if their is an inconsistency
in the method parameters

Example
+++++++

If you want to run a job, at every hour and half-hour (0:00 and 0:30),
with no spread across system, with an agent running with default
schedule of 5 minutes, and making sure that the job is run (if the agent
couldn’t run it, then at the next agent execution the job should be
run), you will call the method with the following parameters:

....
schedule_simple("job_schedule_id", "5", "0", "0",  "0", "0", "0",  "30", "0", "0", "catchup")
....

During each run right after o’clock and half-hour, this method will
define the condition schedule_simple_job_schedule_id_repaired, that you
can use as a condition for a generic method `command_execution`

Parameters
++++++++++

* *job_id*: A string to identify this job
* *agent_periodicity*: Agent run interval (in minutes)
* *max_execution_delay_minutes*: On how many minutes you want to spread
the job
* *max_execution_delay_hours*: On how many hours you want to spread the
job
* *start_on_minutes*: At which minute should be the first run
* *start_on_hours*: At which hour should be the first run
* *start_on_day_of_week*: At which day of week should be the first run
* *periodicity_minutes*: Desired job run interval (in minutes)
* *periodicity_hours*: Desired job run interval (in hours)
* *periodicity_days*: Desired job run interval (in days)
* *mode*: ``nodups'': avoid duplicate runs in the same period /
``catchup'': avoid duplicates and one or more run have been missed, run
once before next period / ``stateless'': no check is done on past runs

Classes defined
+++++++++++++++

....

schedule_simple_${job_id}_{kept, repaired, not_ok, reached}
....

schedule_simple_catchup
^^^^^^^^^^^^^^^^^^^^^^^

Trigger a repaired outcome when a job should be run (avoid losing a job)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`schedule_simple_${job_id}_{kept,repaired,not_ok,ok,reached}` * _ok or
_kept for when there is nothing to do * _repaired if the job should run
* _not_ok and _reached have their usual meaning If the agent run is
skipped during the period, method tries to catchup the run on next agent
run. If the agent run is skipped twice,, only one run is catched up. If
the agent is run twice (for example from a manual run), the job is run
only once.

Parameters
++++++++++

* *job_id*: A string to identify this job
* *agent_periodicity*: Agent run interval (in minutes)
* *max_execution_delay_minutes*: On how many minutes you want to spread
the job
* *max_execution_delay_hours*: On how many hours you want to spread the
job
* *start_on_minutes*: At which minute should be the first run
* *start_on_hours*: At which hour should be the first run
* *start_on_day_of_week*: At which day of week should be the first run
* *periodicity_minutes*: Desired job run interval (in minutes)
* *periodicity_hours*: Desired job run interval (in hours)
* *periodicity_days*: Desired job run interval (in days)

Classes defined
+++++++++++++++

....

schedule_simple_${job_id}_{kept, repaired, not_ok, reached}
....

schedule_simple_nodups
^^^^^^^^^^^^^^^^^^^^^^

Trigger a repaired outcome when a job should be run (avoid running
twice)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`schedule_simple_${job_id}_{kept,repaired,not_ok,ok,reached}` * _ok or
_kept for when there is nothing to do * _repaired if the job should run
* _not_ok and _reached have their usual meaning If the agent is run
twice (for example from a manual run), the jo is run only once. However
if the agent run is skipped during the period, the job is never run.

Parameters
++++++++++

* *job_id*: A string to identify this job
* *agent_periodicity*: Agent run interval (in minutes)
* *max_execution_delay_minutes*: On how many minutes you want to spread
the job
* *max_execution_delay_hours*: On how many hours you want to spread the
job
* *start_on_minutes*: At which minute should be the first run
* *start_on_hours*: At which hour should be the first run
* *start_on_day_of_week*: At which day of week should be the first run
* *periodicity_minutes*: Desired job run interval (in minutes)
* *periodicity_hours*: Desired job run interval (in hours)
* *periodicity_days*: Desired job run interval (in days)

Classes defined
+++++++++++++++

....

schedule_simple_${job_id}_{kept, repaired, not_ok, reached}
....

schedule_simple_stateless
^^^^^^^^^^^^^^^^^^^^^^^^^

Trigger a repaired outcome when a job should be run (without checks)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This bundle will define a condition
`schedule_simple_${job_id}_{kept,repaired,not_ok,ok,reached}` * _ok or
_kept for when there is nothing to do * _repaired if the job should run
* _not_ok and _reached have their usual meaning No effort is done to
check if a run has already been done for this period or not. If the
agent is run twice, the job will be run twice, and if the agent is not
run, the job will no be run.

Parameters
++++++++++

* *job_id*: A string to identify this job
* *agent_periodicity*: Agent run interval (in minutes)
* *max_execution_delay_minutes*: On how many minutes you want to spread
the job
* *max_execution_delay_hours*: On how many hours you want to spread the
job
* *start_on_minutes*: At which minute should be the first run
* *start_on_hours*: At which hour should be the first run
* *start_on_day_of_week*: At which day of week should be the first run
* *periodicity_minutes*: Desired job run interval (in minutes)
* *periodicity_hours*: Desired job run interval (in hours)
* *periodicity_days*: Desired job run interval (in days)

Classes defined
+++++++++++++++

....

schedule_simple_${job_id}_{kept, repaired, not_ok, reached}
....

Service
~~~~~~~

service_action
^^^^^^^^^^^^^^

Trigger an action on a service using the approriate tool

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The `service_*` methods manage the services running on the system.

Parameters
++++++++++

Service name

The name of the service is the name understood by the service manager,
except for the `is-active-process` action, where it is the regex to
match against the running processes list.

Action

The action is the name of an action to run on the given service. The
following actions can be used:

* `start`
* `stop`
* `restart`
* `reload` (or `refresh`)
* `is-active` (or `status`)
* `is-active-process` (in this case, the ``service'' parameter is the
regex to match againt process list)
* `enable`
* `disable`
* `is-enabled`

Other actions may also be used, depending on the selected service
manager.

Implementation
++++++++++++++

These methods will detect the method to use according to the platform.
You can run the methods with an `info` verbosity level to see which
service manager will be used for a given action.

WARNING: Due to compatibility issues when mixing calls to systemctl and
service/init.d, when an init script exists, we will not use systemctl
compatibility layer but directly service/init.d.

The supported service managers are:

* systemd (any unkown action will be passed directly)
* upstart
* smf (for Solaris)
* service command (for non-boot actions, any unkown action will be
passed directly)
* /etc/init.d scripts (for non-boot actions, any unkown action will be
passed directly)
* SRC (for AIX) (for non-boot actions)
* chkconfig (for boot actions)
* update-rc.d (for boot actions)
* chitab (for boot actions)
* links in /etc/rcX.d (for boot actions)
* Windows services

Examples
++++++++

....
# To restart the apache2 service
service_action("apache2", "restart");
service_restart("apache2");
....

Parameters
++++++++++

* *service_name*: Name of the service
* *action*: Action to trigger on the service (start, stop, restart,
reload, …)

Classes defined
+++++++++++++++

....

service_action_${service_name}_{kept, repaired, not_ok, reached}
....

service_check_disabled_at_boot
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check if a service is set to not start at boot using the appropriate
method

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_check_disabled_at_boot_${service_name}_{kept, repaired, not_ok, reached}
....

service_check_running
^^^^^^^^^^^^^^^^^^^^^

Check if a service is running using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Process name

Classes defined
+++++++++++++++

....

service_check_running_${service_name}_{kept, repaired, not_ok, reached}
....

service_check_running_ps
^^^^^^^^^^^^^^^^^^^^^^^^

Check if a service is running using ps

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_regex*: Regular expression used to select a process in ps
output

Classes defined
+++++++++++++++

....

service_check_running_${service_regex}_{kept, repaired, not_ok, reached}
....

service_check_started_at_boot
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check if a service is set to start at boot using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_check_started_at_boot_${service_name}_{kept, repaired, not_ok, reached}
....

service_disabled
^^^^^^^^^^^^^^^^

Force a service not to be enabled at boot

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_disabled_${service_name}_{kept, repaired, not_ok, reached}
....

service_enabled
^^^^^^^^^^^^^^^

Force a service to be started at boot

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d,
Windows, SRC, SMF, etc…)

Classes defined
+++++++++++++++

....

service_enabled_${service_name}_{kept, repaired, not_ok, reached}
....

service_ensure_disabled_at_boot
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Force a service not to be enabled at boot

*WARNING*: This generic method is deprecated. Use
link:#_service_disabled_at_boot[service_disabled_at_boot] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_ensure_disabled_at_boot_${service_name}_{kept, repaired, not_ok, reached}
....

service_ensure_running
^^^^^^^^^^^^^^^^^^^^^^

Ensure that a service is running using the appropriate method

*WARNING*: This generic method is deprecated. Use
link:#_service_started[service_started] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_ensure_running_${service_name}_{kept, repaired, not_ok, reached}
....

service_ensure_running_path
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a service is running using the appropriate method,
specifying the path of the service in the ps output, or using Windows
task manager

*WARNING*: This generic method is deprecated. Use
link:#_service_started_path[service_started_path] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d,
Windows, etc…)
* *service_path*: Service with its path, as in the output from `ps'

Classes defined
+++++++++++++++

....

service_ensure_running_${service_name}_{kept, repaired, not_ok, reached}
....

service_ensure_started_at_boot
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Force a service to be started at boot

*WARNING*: This generic method is deprecated. Use
link:#_service_enabled[service_enabled] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d,
Windows, SRC, SMF, etc…)

Classes defined
+++++++++++++++

....

service_ensure_started_at_boot_${service_name}_{kept, repaired, not_ok, reached}
....

service_ensure_stopped
^^^^^^^^^^^^^^^^^^^^^^

Ensure that a service is stopped using the appropriate method

*WARNING*: This generic method is deprecated. Use
link:#_service_stopped[service_stopped] instead.

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service

Classes defined
+++++++++++++++

....

service_ensure_stopped_${service_name}_{kept, repaired, not_ok, reached}
....

service_reload
^^^^^^^^^^^^^^

Reload a service using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_service_action[service_action] for documentation.

Parameters
++++++++++

* *service_name*: Name of the service

Classes defined
+++++++++++++++

....

service_reload_${service_name}_{kept, repaired, not_ok, reached}
....

service_restart
^^^^^^^^^^^^^^^

Restart a service using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_service_action[service_action] for documentation.

Parameters
++++++++++

* *service_name*: Name of the service

Classes defined
+++++++++++++++

....

service_restart_${service_name}_{kept, repaired, not_ok, reached}
....

service_restart_if
^^^^^^^^^^^^^^^^^^

Restart a service using the appropriate method if the specified class is
true, otherwise it is considered as not required and success classes are
returned.

*WARNING*: This generic method is deprecated. Use
link:#_service_restart[service_restart] with a condition

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_service_action[service_action] for documentation.

Parameters
++++++++++

* *service_name*: Name of the service
* *trigger_class*: class(es) which will trigger the restart of Service
``(package_service_installed|service_conf_changed)'' by example

Classes defined
+++++++++++++++

....

service_restart_${service_name}_{kept, repaired, not_ok, reached}
....

service_start
^^^^^^^^^^^^^

Start a service using the appropriate method

*WARNING*: This generic method is deprecated. This is an action that
should not be used in the general case. If you really want to call the
start method, use link:#_service_action[service_action]. Otherwise,
simply call link:#_service_started[service_started]

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_service_action[service_action] for documentation.

Parameters
++++++++++

* *service_name*: Name of the service

Classes defined
+++++++++++++++

....

service_start_${service_name}_{kept, repaired, not_ok, reached}
....

service_started
^^^^^^^^^^^^^^^

Ensure that a service is running using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d, etc…)

Classes defined
+++++++++++++++

....

service_started_${service_name}_{kept, repaired, not_ok, reached}
....

service_started_path
^^^^^^^^^^^^^^^^^^^^

Ensure that a service is running using the appropriate method,
specifying the path of the service in the ps output, or using Windows
task manager

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name (as recognized by systemd, init.d,
Windows, etc…)
* *service_path*: Service with its path, as in the output from `ps'

Classes defined
+++++++++++++++

....

service_started_${service_name}_{kept, repaired, not_ok, reached}
....

service_status
^^^^^^^^^^^^^^

This generic method defines if service should run or be stopped

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service name
* *status*: Desired state for the user - can be `Stopped' or `Running'

Classes defined
+++++++++++++++

....

service_status_${service_name}_{kept, repaired, not_ok, reached}
....

service_stop
^^^^^^^^^^^^

Stop a service using the appropriate method

*WARNING*: This generic method is deprecated. This is an action that
should not be used in the general case. If you really want to call the
stop method, use link:#_service_action[service_action]. Otherwise,
simply call link:#_service_stopped[service_stopped]

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

See link:#_service_action[service_action] for documentation.

Parameters
++++++++++

* *service_name*: Name of the service

Classes defined
+++++++++++++++

....

service_stop_${service_name}_{kept, repaired, not_ok, reached}
....

service_stopped
^^^^^^^^^^^^^^^

Ensure that a service is stopped using the appropriate method

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *service_name*: Service

Classes defined
+++++++++++++++

....

service_stopped_${service_name}_{kept, repaired, not_ok, reached}
....

Sharedfile
~~~~~~~~~~

sharedfile_from_node
^^^^^^^^^^^^^^^^^^^^

This method retreives a file shared from another Rudder node

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method retreives a file shared from a Rudder node using a unique
file identifier.

The file will be downloaded using CFEngine protocol and copied into a
new file. The destination path must be the complete absolute path of the
destination file.

See link:#_sharedfile_to_node[sharedfile_to_node] for a complete
example.

_INFO_: Please note that this method must be used on an agent that is
connected to Rudder relay or server (>=4.1)

Parameters
++++++++++

* *source_uuid*: which node to take the file from
* *file_id*: unique name that was used to identify the file on the
sender
* *file_path*: where to put the file content

Classes defined
+++++++++++++++

....

sharedfile_from_node_${file_id}_{kept, repaired, not_ok, reached}
....

sharedfile_to_node
^^^^^^^^^^^^^^^^^^

This method shares a file with another Rudder node

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method shares a file with another Rudder node using a unique file
identifier.

Read the Rudder documentation for a
https://docs.rudder.io/reference/current/usage/advanced_configuration_management.html#_share_files_between_nodes[high
level overview of file sharing between nodes].

The file will be kept on the policy server and transmitted to the
destination node’s policy server if it is different. It will be kept on
this server for the destination node to download as long as it is not
replaced by a new file with the same id or remove by expiration of the
TTL.

Parameters
++++++++++

This section describes the generic method parameters.

target_uuid
+++++++++++

The node you want to share this file with. The uuid of a node is visible
in the Nodes details (in the Web interface) or by entering
`rudder agent info` on the target node.

file_id

This is a name that will be used to identify the file in the target
node. It should be unique and describe the file content.

file_path

The local absolute path of the file to share.

ttl

The TTL can be:

* A simple integer, in this case it is assumed to be a number of
_seconds_
* A string including units indications, the possible units are:
* _days_, _day_ or _d_
* _hours_, _hour_, or _h_
* _minutes_, _minute_, or _m_
* _seconds_, _second_ or _s_

The ttl value can look like _1day 2hours 3minutes 4seconds_ or can be
abbreviated in the form _1d 2h 3m 4s_, or without spaces _1d2h3m4s_ or
any combination like _1day2h 3minute 4seconds_ Any unit can be skipped,
but the decreasing order needs to be respected.

file_id

This is a name that will be used to identify the file once stored on the
server. It should be unique and describe the file content.

Example:
++++++++

We have a node _A_, with uuid `2bf1afdc-6725-4d3d-96b8-9128d09d353c`
which wants to share the `/srv/db/application.properties` with node _B_
with uuid `73570beb-2d4a-43d2-8ffc-f84a6817849c`.

We want this file to stay available for one year for node _B_ on its
policy server.

The node _B_ wants to download it into
`/opt/application/etc/application.properties`.

They have to agree (i.e. it has to be defined in the policies of both
nodes) on the id of the file, that will be used during the exchange,
here it will be `application.properties`.

To share the file, node _A_ will use:

....
sharedfile_to_node("73570beb-2d4a-43d2-8ffc-f84a6817849c", "application.properties", "/srv/db/application.properties", "356 days")
....

To download the file, node _B_ will use
link:#_sharedfile_from_node[sharedfile_from_node] with:

....
sharedfile_from_node("2bf1afdc-6725-4d3d-96b8-9128d09d353c", "application.properties", "/opt/application/etc/application.properties")
....

_INFO_: Please note that this method must be used on a Rudder agent
(>=4.1) that is connected to Rudder relay or server (>=4.1)

Parameters
++++++++++

* *target_uuid*: which node to share the file with
* *file_id*: unique name that will be used to identify the file on the
receiver
* *file_path*: path of the file to share
* *ttl*: time to keep the file on the policy server in seconds or in
human readable form (see long description)

Classes defined
+++++++++++++++

....

sharedfile_to_node_${file_id}_{kept, repaired, not_ok, reached}
....

Sysctl
~~~~~~

sysctl_value
^^^^^^^^^^^^

Enforce a value in sysctl (optionaly increase or decrease it)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Enforce a value in sysctl

Behaviours
++++++++++

Checks for the current value defined for the given key If it is not set,
this method attempts to set it in the file defined as argument If it is
set, and corresponds to the desired value, it will success If it is set,
and does not correspond, the value will be set in the file defined,
sysctl configuration is reloaded with `sysctl --system` and the
resulting value is checked. If it is not taken into account by sysctl
because its overriden in another file or its an invalid key, the method
returns an error

Prerequisite
++++++++++++

This method requires an /etc/sysctl.d folder, and the `sysctl --system`
option. It does not support Debian 6 or earlier, Centos/RedHat 6 or
earlier, SLES 11 or earlier, Ubuntu 12_04 or earlier, AIX and Solaris.

Parameters

`key` : the key to enforce/check `value` : the expected value for the
key `filename` : filename (without extension) containing the key=value
when need to be set, within /etc/sysctl.d. This method adds the correct
extension at the end of the filename Optional parameter: `min`: The
value is the minimal value we request. the value is only changed if the
current value is lower than `value` `max`: The value is the maximal
value we request: the value is only changed if the current value is
higher than `value` `default` (default value): The value is strictly
enforced.

Comparision is numerical if possible, else alphanumerical So 10 > 2, but
Test10 < Test2

Examples
++++++++

To ensure that swappiness is disabled, and storing the configuration
parameter in 99_rudder.conf

....
 sysctl_value("vm.swappiness", "99_rudder", "0", "")
....

To ensure that the UDP buffer is at least 26214400

....
 sysctl_value("net.core.rmem_max", "99_rudder", "26214400", "min")
....

Parameters
++++++++++

* *key*: The key to enforce
* *value*: The desired value
* *filename*: File name where to put the value in /etc/sysctl.d (without
the .conf extension)
* *option*: Optional modifier on value: Min, Max or Default (default
value)

Classes defined
+++++++++++++++

....

sysctl_value_${key}_{kept, repaired, not_ok, reached}
....

User
~~~~

user_absent
^^^^^^^^^^^

Remove a user

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method ensures that a user does not exist on the system.

Parameters
++++++++++

* *login*: User login

Classes defined
+++++++++++++++

....

user_absent_${login}_{kept, repaired, not_ok, reached}
....

user_create
^^^^^^^^^^^

Create a user

*WARNING*: This generic method is deprecated. Please split into calls to
other user_* methods: link:#_user_present[user_present]
link:#_user_fullname[user_fullname] link:#_user_home[user_home]
link:#_user_primary_group[user_primary_group]
link:#_user_shell[user_shell] and link:#_user_locked[user_locked]

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user’s home directory.

Parameters
++++++++++

* *login*: User login
* *description*: User description
* *home*: User’s home directory
* *group*: User’s primary group
* *shell*: User’s shell
* *locked*: Is the user locked ? true or false

Classes defined
+++++++++++++++

....

user_create_${login}_{kept, repaired, not_ok, reached}
....

user_fullname
^^^^^^^^^^^^^

Define the fullname of the user, user must already exists.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user.

Parameters
++++++++++

* *login*: User’s login
* *fullname*: User’s fullname

Classes defined
+++++++++++++++

....

user_fullname_${login}_{kept, repaired, not_ok, reached}
....

user_group
^^^^^^^^^^

Define secondary group for a user

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a user is within a group

Behaviour
+++++++++

Ensure that the user belongs in the given secondary group
(non-exclusive)

Parameters

`user` : the user login `group_name`: secondary group name the user
should belong to (non-exclusive)

Examples
++++++++

To ensure that user `test` belongs in group `dev`

....
 user_group("test", "dev")
....

Note that it will make sure that user test is in group dev, but won’t
remove it from other groups it may belong to

Parameters
++++++++++

* *user*: User login
* *group_name*: Secondary group name for the user

Classes defined
+++++++++++++++

....

user_group_${user}_{kept, repaired, not_ok, reached}
....

user_home
^^^^^^^^^

Define the home of the user. User must already exists.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user, nor the home directory. entry
example: /home/myuser The home given will be set, but not created.

Parameters
++++++++++

* *login*: User’s login
* *home*: User’s home

Classes defined
+++++++++++++++

....

user_home_${login}_{kept, repaired, not_ok, reached}
....

user_locked
^^^^^^^^^^^

Ensure the user is locked. User must already exist.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user. Note that locked accounts will be
marked with ``!'' in /etc/shadow, which is equivalent to "*". To unlock
a user, apply a user_password method.

Parameters
++++++++++

* *login*: User’s login

Classes defined
+++++++++++++++

....

user_locked_${login}_{kept, repaired, not_ok, reached}
....

user_password_clear
^^^^^^^^^^^^^^^^^^^

Ensure a user’s password. as used in the UNIX /etc/shadow file.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

User must exists, password will appear in clear text in code. An empty
password will lead to an error and be notified.

Parameters
++++++++++

* *login*: User login
* *password*: User clear password

Classes defined
+++++++++++++++

....

user_password_clear_${login}_{kept, repaired, not_ok, reached}
....

user_password_hash
^^^^^^^^^^^^^^^^^^

Ensure a user’s password. Password must respect `$id$salt$hashed` format
as used in the UNIX /etc/shadow file.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

User must exists, password must be pre-hashed. Does not handle empty
password accounts. See UNIX /etc/shadow format. entry example:
`$1$jp5rCMS4$mhvf4utonDubW5M00z0Ow0`

An empty password will lead to an error and be notified.

Parameters
++++++++++

* *login*: User login
* *password*: User hashed password

Classes defined
+++++++++++++++

....

user_password_hash_${login}_{kept, repaired, not_ok, reached}
....

user_present
^^^^^^^^^^^^

Ensure a user exists on the system.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user’s home directory. Primary group
will be created and set with default one, following the useradd default
behaviour. As in most UNIX system default behavior user creation will
fail if a group with the user name already exists.

Parameters
++++++++++

* *login*: User login

Classes defined
+++++++++++++++

....

user_present_${login}_{kept, repaired, not_ok, reached}
....

user_primary_group
^^^^^^^^^^^^^^^^^^

Define the primary group of the user. User must already exist.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user.

Parameters
++++++++++

* *login*: User’s login
* *primary_group*: User’s primary group

Classes defined
+++++++++++++++

....

user_primary_group_${login}_{kept, repaired, not_ok, reached}
....

user_shell
^^^^^^^^^^

Define the shell of the user. User must already exist.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user. entry example: /bin/false

Parameters
++++++++++

* *login*: User’s login
* *shell*: User’s shell

Classes defined
+++++++++++++++

....

user_shell_${login}_{kept, repaired, not_ok, reached}
....

user_status
^^^^^^^^^^^

This generic method defines if user is present or absent

Compatible with nodes running Rudder 5.0 or higher.

Parameters
++++++++++

* *user*: User name
* *status*: Desired state for the user - can be `Present' or `Absent'

Classes defined
+++++++++++++++

....

user_status_${user}_{kept, repaired, not_ok, reached}
....

user_uid
^^^^^^^^

Define the uid of the user. User must already exists, uid must be
non-allowed(unique).

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

This method does not create the user.

Parameters
++++++++++

* *login*: User’s login
* *uid*: User’s uid

Classes defined
+++++++++++++++

....

user_uid_${login}_{kept, repaired, not_ok, reached}
....

Variable
~~~~~~~~

variable_dict
^^^^^^^^^^^^^

Define a variable that contains key,value pairs (a dictionnary)

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *value*: The variable content in JSON format

Classes defined
+++++++++++++++

....

variable_dict_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_dict_from_file
^^^^^^^^^^^^^^^^^^^^^^^

Define a variable that contains key,value pairs (a dictionnary) from a
JSON file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

See link:#_variable_dict_from_file_type[variable_dict_from_file_type]
for complete documentation.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *file_name*: The absolute local file name with JSON content

Classes defined
+++++++++++++++

....

variable_dict_from_file_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_dict_from_file_type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable that contains key,value pairs (a dictionnary) from a
JSON, CSV or YAML file

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive).

This method will load data from various file formats (yaml, json, csv).

CSV parsing
+++++++++++

The input file must use CRLF as line delimiter to be readable (as stated
in RFC 4180).

Examples
++++++++

....
# To read a json file with format autodetection
variable_dict_from_file_type("prefix", "var", "/tmp/file.json", "");
# To force yaml reading on a non file without yaml extension
variable_dict_from_file_type("prefix", "var", "/tmp/file", "YAML");
....

If `/tmp/file.json` contains:

....
{
  "key1": "value1"
}
....

You will be able to access the `value1` value with
`${prefix.var[key1]}`.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *file_name*: The file name to load data from
* *file_type*: The file type, can be ``JSON'', ``CSV'', ``YAML'' or
``auto'' for autodection based on file extension, with a fallback to
JSON (default is ``auto'')

Classes defined
+++++++++++++++

....

variable_dict_from_file_type_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_dict_from_osquery
^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable that contains key,value pairs (a dictionnary) from an
osquery query

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

This method will define a dict variable from the output os an osquery
query. The query will be executed at evera agent run, and its result
will be usable as a standard dict variable.

Setup
+++++

This method requires the presence of https://osquery.io/[osquery] on the
target nodes. It won’t install it automatically. Check the correct way
of doing so for your OS.

Building queries
++++++++++++++++

To learn about the possible queries, read the
https://osquery.io/schema/[osquery schema] for your osquery version.

You can test the queries before using them with the `osqueryi` command,
see the example below.

Examples
++++++++

....
# To get the number of cpus on the machine
variable_dict_from_osquery("prefix", "var1", "select cpu_logical_cores from system_info;");
....

It will produce the dict from the output of:

....
osqueryi --json "select cpu_logical_cores from system_info;"
....

Hence something like:

....
[
 {"cpu_logical_cores":"8"}
]
....

To access this value, use the `${prefix.var1[0][cpu_logical_cores]}`
syntax.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *query*: The query to execute (ending with a semicolon)

Classes defined
+++++++++++++++

....

variable_dict_from_osquery_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_dict_merge
^^^^^^^^^^^^^^^^^^^

Define a variable resulting of the merge of two other variables

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

The resulting variable will be the merge of the two parameters, which
means it is built by:

* Taking the content of the first variable
* Adding the content of the second variable, and replacing the keys that
were already there

It is only a one-level merge, and the value of the first-level key will
be completely replaced by the merge.

This method will fail if one of the variables is not defined. See
link:#_variable_dict_merge_tolerant[variable_dict_merge_tolerant] if you
want to allow one of the variables not to be defined.

Usage
^^^^^

If you have a `prefix.variable1` variable defined by:

....
{ "key1": "value1", "key2": "value2", "key3": { "keyx": "valuex" } }
....

And a `prefix.variable2` variable defined by:

....
{ "key1": "different", "key3": "value3", "key4": "value4" }
....

And that you use:

....
variablr_dict_merge("prefix", "variable3, "prefix.variable1", "prefix.variable2")
....

You will get a `prefix.variable3` variable containing:

....
{
  "key1": "different",
  "key2": "value2",
  "key3": "value3",
  "key4": "value4"
}
....

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *first_variable*: The first variable, which content will be overriden
in the resulting variable if necessary (written in the form
variable_prefix.variable_name)
* *second_variable*: The second variable, which content will override
the first in the resulting variable if necessary (written in the form
variable_prefix.variable_name)

Classes defined
+++++++++++++++

....

variable_dict_merge_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_dict_merge_tolerant
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable resulting of the merge of two other variables,
allowing merging undefined variables

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name[key]}` with each name replaced with the
parameters of this method.

See link:#_variable_dict_merge[variable_dict_merge] for usage
documentation. The only difference is that this method will not fail if
one of the variables do not exist, and will return the other one. If
both are undefined, the method will still fail.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *first_variable*: The first variable, which content will be overriden
in the resulting variable if necessary (written in the form
variable_prefix.variable_name)
* *second_variable*: The second variable, which content will override
the first in the resulting variable if necessary (written in the form
variable_prefix.variable_name)

Classes defined
+++++++++++++++

....

variable_dict_merge_tolerant_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_iterator
^^^^^^^^^^^^^^^^^

Define a variable that will be automatically iterated over

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The generated variable is a special variable (slist in cfengine
speaking) that is automatically iterated over. When you call a generic
method with this variable as a parameter, n calls will be made, one for
each items of the variable. Note: there is a limit of 10000 items

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *value*: The variable content
* *separator*: Regular expression that is used to split the value into
items ( usually: , )

Classes defined
+++++++++++++++

....

variable_iterator_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_iterator_from_file
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable that will be automatically iterated over

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

The generated variable is a special variable (slist in cfengine
speaking) that is automatically iterated over. When you call a generic
method with this variable as a parameter, n calls will be made, one for
each items of the variable. Note: there is a limit of 10000 items Note:
empty items are ignored

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *file_name*: The path to the file
* *separator_regex*: Regular expression that is used to split the value
into items ( usually: )
* *comments_regex*: Regular expression that is used to remove comments (
usually: #.*?(?=) )

Classes defined
+++++++++++++++

....

variable_iterator_from_file_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string
^^^^^^^^^^^^^^^

Define a variable from a string parameter

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *value*: The variable content

Classes defined
+++++++++++++++

....

variable_string_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_default
^^^^^^^^^^^^^^^^^^^^^^^

Define a variable from another variable name, with a default value if
undefined

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *source_variable*: The source variable name
* *default_value*: The default value to use if source_variable is not
defined

Classes defined
+++++++++++++++

....

variable_string_default_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_escaped
^^^^^^^^^^^^^^^^^^^^^^^

Define a variable from another string variable and escape regular
expression characters in it.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${<variable_name>_escaped}` where is the composed complete name of the
variable you want to escape.

Please note that the variable you want to escape must be defined before
this method evaluation.

Example:
++++++++

With a variable defined by the generic method `variable_string`, named
`my_prefix.my_variable` and valued to:

....
 something like [] that
....

Passing `my_prefix.my_variable` as `variable_name` parameter to this
method will result in a variable named `my_prefix.my_variable_escaped`
and valued to:

....
something\ like\ \[\]\ that
....

Parameters
++++++++++

* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name

Classes defined
+++++++++++++++

....

variable_string_escaped_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_from_augeas
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Use Augeas binaries to call Augtool commands and options to get a node
label’s value.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Augeas is a tool that provides an abstraction layer for all the
complexities that turn around editing files with regular expressions.
It’s a tree based hierarchy tool, that handle system configuration files
where you can securely modify your files. To do so you have to provide
the path to the node label’s value. Augeas uses lenses which are sort of
modules that are in charge of identifying and converting files into tree
and back. This way, you can manipulate at first the tree and then save
your changes into the configuration files on the actual system.

In this method, we introduce using augtool commands and options in order
to get the value of a given node’s label in the parameters, this can be
done by specifying the path to it. The method has in total 5 parameters:
variable prefix, variable name, path, lens and file.

Actually there is two ways you can use this method, either you simply
provide a path to the node’s label as a parameter or you specify a file
associated with a lens, then you put the regular path. When you only
specify the path to the node’s label, your request will includes by
default Augeas charging all the lenses and files, on the other hand, if
you have a specific file, for example, such as a Json file and you want
to associate it to the existing Json lense, then in that case, you need
to fill in addition the file and the lens parameter, this way Augeas
won’t load all its files and lenses except the ones you have specified.
The generic method will get a node label’s value from the agent,
otherwise, if Augeas isn’t installed on the agent, it will produces an
error.

Two uses cases examples:
++++++++++++++++++++++++

Use case 1:
-----------

Let’s consider that you want to obtain the value of the ip address of
the first line in the `/etc/hosts` file by indicating the path to it.
(Note that the `label` and `value` parameters mentioned are naming
examples of `variable prefix` and `variable name`, the path
`/etc/hosts/1/ipaddr` represents the `ipaddr` node label’s value in the
first line in the `/etc/hosts`) .

....
variable_string_from_augeas("label","value","/etc/hosts/1/ipaddr");
....

Use case 2:
-----------

The second case includes two needs of using it, either you want to
prevent Augeas from charging all lenses and files while executing your
request or you want to associate the `Hosts` lens with the `/etc/hosts`
file then get for example the same node value of the first use case.

....
variable_string_from_augeas("label","value","/etc/hosts/1/ipaddr","Hosts","/etc/hosts");
....

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *path*: The path to the file and node label
* *lens*: The lens specified by the user in case he wants to load a
specified lens associated with its file
* *file*: The file specified by the user in case he wants to load a
specified file associated with its lens

Classes defined
+++++++++++++++

....

variable_string_from_augeas_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_from_command
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable from a command output

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *command*: The command to execute

Classes defined
+++++++++++++++

....

variable_string_from_command_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_from_file
^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable from a file content

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *file_name*: The path of the file

Classes defined
+++++++++++++++

....

variable_string_from_file_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_from_math_expression
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Define a variable from a mathematical expression

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

To use the generated variable, you must use the form
`${variable_prefix.variable_name}` with each name replaced with the
parameters of this method.

Be careful that using a global variable can lead to unpredictable
content in case of multiple definition, which is implicitly the case
when a technique has more than one instance (directive). Please note
that only global variables are available within templates.

Usage
+++++

This function will evaluate a mathematical expression that may contain
variables and format the result according to the provided formatt
string.

The formatting string uses the standard POSIX printf format.

Supported mathematical expressions
++++++++++++++++++++++++++++++++++

All the mathematical computations are done using floats.

The supported infix mathematical syntax, in order of precedence, is:

* `(` and `)` parentheses for grouping expressions
* `^` operator for exponentiation
* `*` and `/` operators for multiplication and division
* `%` operators for modulo operation
* `+` and `-` operators for addition and subtraction
* `==` ``close enough'' operator to tell if two expressions evaluate to
the same number, with a tiny margin to tolerate floating point errors.
It returns 1 or 0.
* `>=` ``greater or close enough'' operator with a tiny margin to
tolerate floating point errors. It returns 1 or 0.
* `>` ``greater than'' operator. It returns 1 or 0.
* `<=` ``less than or close enough'' operator with a tiny margin to
tolerate floating point errors. It returns 1 or 0.
* `<` ``less than'' operator. It returns 1 or 0.

The numbers can be in any format acceptable to the C `scanf` function
with the `%lf` format specifier, followed by the `k`, `m`, `g`, `t`, or
`p` SI units. So e.g. `-100` and `2.34m` are valid numbers.

In addition, the following constants are recognized:

* `e`: 2.7182818284590452354
* `log2e`: 1.4426950408889634074
* `log10e`: 0.43429448190325182765
* `ln2`: 0.69314718055994530942
* `ln10`: 2.30258509299404568402
* `pi`: 3.14159265358979323846
* `pi_2`: 1.57079632679489661923 (pi over 2)
* `pi_4`: 0.78539816339744830962 (pi over 4)
* `1_pi`: 0.31830988618379067154 (1 over pi)
* `2_pi`: 0.63661977236758134308 (2 over pi)
* `2_sqrtpi`: 1.12837916709551257390 (2 over square root of pi)
* `sqrt2`: 1.41421356237309504880 (square root of 2)
* `sqrt1_2`: 0.70710678118654752440 (square root of 1/2)

The following functions can be used, with parentheses:

* `ceil` and `floor`: the next highest or the previous highest integer
* `log10`, `log2`, `log`
* `sqrt`
* `sin`, `cos`, `tan`, `asin`, `acos`, `atan`
* `abs`: absolute value
* `step`: 0 if the argument is negative, 1 otherwise

Formatting options
++++++++++++++++++

The format field supports the following specifiers:

* `%d` for decimal integer
* `%x` for hexadecimal integer
* `%o` for octal integer
* `%f` for decimal floating point

You can use usual flags, width and precision syntax.

Examples
++++++++

If you use:

....
variable_string("prefix", "var", "10");
variable_string_from_math_expression("prefix", "sum", "2.0+3.0", "%d");
variable_string_from_math_expression("prefix", "product", "3*${prefix.var}", "%d");
....

The `prefix.sum` string variable will contain `5` and `prefix.product`
will contain `30`.

Parameters
++++++++++

* *variable_prefix*: The prefix of the variable name
* *variable_name*: The variable to define, the full name will be
variable_prefix.variable_name
* *expression*: The mathematical expression to evaluate
* *format*: The format string to use

Classes defined
+++++++++++++++

....

variable_string_from_math_expression_${variable_name}_{kept, repaired, not_ok, reached}
....

variable_string_match
^^^^^^^^^^^^^^^^^^^^^

Test the content of a string variable

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Test a variable content and report a success if it matched, or an error
if it does not or if the variable could not be found. Regex must respect
PCRE format. Please note that this method is designed to only audit a
variable state. If you want to use conditions resulting from this
generic method, is it recommended to use instead
condition_from_variable_match which is designed for it.

Parameters
++++++++++

* *variable_name*: Complete name of the variable being tested, like
my_prefix.my_variable
* *expected_match*: Regex to use to test if the variable content is
compliant

Classes defined
+++++++++++++++

....

variable_string_match_${variable_name}_{kept, repaired, not_ok, reached}
....

Windows
~~~~~~~

windows_component_absent
^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a specific windows component is absent from the system.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a specific windows component is absent from the system.

Parameters
++++++++++

* *component*: Windows component name

Classes defined
+++++++++++++++

....

windows_component_absent_${component}_{kept, repaired, not_ok, reached}
....

windows_component_present
^^^^^^^^^^^^^^^^^^^^^^^^^

Ensure that a specific windows component is present on the system.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a specific windows component is present on the system.

Parameters
++++++++++

* *component*: Windows component name

Classes defined
+++++++++++++++

....

windows_component_present_${component}_{kept, repaired, not_ok, reached}
....

windows_hotfix_absent
^^^^^^^^^^^^^^^^^^^^^

Ensure that a specific windows hotfix is absent from the system.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a specific windows hotfix is absent from the system.

Parameters
++++++++++

* *hotfix*: Windows hotfix name (ex: KB4033369)

Classes defined
+++++++++++++++

....

windows_hotfix_absent_${hotfix}_{kept, repaired, not_ok, reached}
....

windows_hotfix_present
^^^^^^^^^^^^^^^^^^^^^^

Ensure that a specific windows hotfix is present from the system.

Compatible with nodes running Rudder 5.0 or higher.

Usage
+++++

Ensure that a specific windows hotfix is present from the system.

Parameters
++++++++++

* *hotfix*: Windows hotfix name (ex: KB4033369)
* *package_path*: Windows hotfix package absolute path, can be a .msu
archive or a .cab file

Classes defined
+++++++++++++++

....

windows_hotfix_present_${hotfix}_{kept, repaired, not_ok, reached}
....

:leveloffset!:

← Node-Server communication security Command →