Variables
General
In Rudder, you can define and use variables via the technique editor or the differents pre-built techniques.
All variables are defined under a prefix
(scope), so to reference a variable you will always need its prefix
and its name
, separated via a .
char.
To call a variable in Rudder we use ${…}
brackets syntax as described below:
For backward compatibility, the syntax $(…) is also supported, but deprecated and not recommanded.
|
// Call to a String or Iterator variable ${<prefix>.<variable name>} // Call to a key in a Dict variable ${<prefix>.<variable dict name>[key][sub-key]}
The prefix will allow you to easily organize your variables and re-use the already taken name defining a new prefix.
Variables are also typed and can be:
* A classic String
* A Dict
, which support key-values and arrays
* Or an Iterator
which is used to loop over things in Rudder.
More over, all variables in Rudder are overridable at execution time, keep in mind that ordering the definition of your variables is important.
Inventory variables
Theses variables have been introduced in Rudder 5.0.13, if you are using a previous version of Rudder, please use System Variables, described in next section |
Informations about current node:
Variable | Description |
---|---|
${node.inventory[hostname]} |
Node hostname |
${node.inventory[localAdministratorAccountName]} |
Node administrator login |
${node.inventory[archDescription]} |
The architecture of the node (like "x86_64") |
${node.inventory[ram]} |
The amount of RAM on the node (in bytes) |
${node.inventory[timezone]} |
The name of the timezone of the node (like "Europe/Paris") |
${node.inventory[os][name]} |
The operating system name (like "Debian") |
${node.inventory[os][fullName]} |
The operating system full name (like "Debian GNU/Linux 9.1 (stretch)") |
${node.inventory[os][version]} |
The operating system version (like "9.1") |
${node.inventory[os][kernelVersion]} |
The kernel version on the node (like "4.9.0-3-amd64") |
${node.inventory[os][servicePack]} |
The operating system service pack (like "4") |
${node.inventory[machine][machineType]} |
The machine type (like "qemu", "physical") |
${node.inventory[machine][manufacturer]} |
The manufacturer of the machine (like "innotek GmbH") |
${rudder.inventory[policyServerId]} |
The Rudder generated id of the node Policy Server |
System Variables
Rudder also provides system variables that contain information about nodes and their policy server. You can use them like user defined parameters.
In the Directive parameters
These variables are only usable in the directive parameters and not in the technique editor, |
Informations about current node:
Variable | Description |
---|---|
${rudder.node.id} |
Rudder id of the node |
${rudder.node.hostname} |
Node hostname |
${rudder.node.admin} |
Node administrator login |
${rudder.node.state} |
The node lifecycle of the node |
${rudder.node.policyMode} |
the effective policy mode of the node |
Informations about a node’s policy server:
Variable | Description |
---|---|
${rudder.node.policyserver.id} |
The Rudder generated id of the Policy Server |
${rudder.node.policyserver.hostname} |
The hostname of the Policy Server |
${rudder.node.policyserver.admin} |
The administrator login of the Policy Server |
Technique parameters
Technique parameters, if any, are also following the same syntax schema, their prefix is the technique_id. This is understandable since they are local to the technique, and so binded to this scope/prefix, that’s why we can accessing their content within a technique either with:
# Without the prefix ${parameter_name} # The complete parameter name ${technique_id.parameter_name}
The complete parameter name is mostly used to access the parameter value from a template or when using method which takes a variable name as argument such as condition_from_variable_match.
Node properties
Node properties can be found in the properties tab of each node in Rudder.
Node properties can be managed using the UI, or Rudder’s API, see https://docs.rudder.io/api/#api-Nodes-updateNodeProperties
Properties can also be defined on the node itself, to override locally properties.
Each property is a key=value pair. The value can be a string or a well-formatted JSON data structure.
Some examples:
datacenter=Paris
datacenter= { "id": "FRA1", "name": "Colo 1, Paris", "location": "Paris, France", "dns_suffix": "paris.example.com" }
Using properties
Node properties can be used almost everywhere in Rudder:
-
in directive parameters
-
in the technique editor
-
in your own techniques and generic methods
To use a property, simply use the variable node.properties with the variable call syntax.
Example with a property named 'datacenter':
${node.properties[datacenter]}
In a mustache template, use:
{{{vars.node.properties.datacenter}}}
Local override
The agent searches for optionnal properties files /var/rudder/local/properties.d/*.json
, and will override existing properties.
As a result, if you have node properties defined server side as
"sysctls_postgresql":{"kernel.shmall":"903330","kernel.shmmax":"3700041320"}
and
"vm":{"vm.dirty_ratio":"10"}
and a local property file /var/rudder/local/properties.d/postgresql_config.json
as
{ "properties": { "sysctls_postgresql": { "kernel.shmmax":"5368709120" } } }
The resulting properties will be:
"sysctls_postgresql":{"kernel.shmmax":"5368709120"}
and
"vm":{"vm.dirty_ratio":"10"}
sysctls_postgresql
has been overriden by local property, and vm
has been left untouched.
Note that it is an override, as the semantic of merging is not deterministic with literal values, and it does not allow to unset values. If you need to merge, please refer to the next paragraph.
Merging properties
If you want to merge server defined properties with local defined properties, rather than override them, you will need to use the generic method variable_dict_merge_tolerant to define which variables you need to merge, and define the local variables in a different namespace than properties.
For instance, if you have defined in the node properties the following properties
"sysctls_postgresql":{"kernel.shmall":"903330","kernel.shmmax":"3700041320"}
and you wish to merge these values on a node with locally defined variable, to change the value of kernel.shmmax and set the value of kernel.shmmni, you can define the file /var/rudder/local/properties.d/postgresql_config.json with the following content
{ "local_properties": { "sysctls_postgresql": { "kernel.shmmax":"5368709120", "kernel.shmmni":"4096" } } }
and use the generic method variable_dict_merge_tolerant
to merge node.properties[sysctls_postgresql]
and node.local_properties[sysctls_postgresql]
, and set the result in merged_properties.sysctls_postgresql (for instance): variable_dict_merge_tolerant("merged_properties", "sysctls_postgresql", "node.properties[sysctls_postgresql]", "node.local_properties[sysctls_postgresql]")
As a result, merged_properties.sysctls_postgresql will contain
"sysctls_postgresql": { "kernel.shmall":"903330", "kernel.shmmax":"5368709120", "kernel.shmmni":"4096" }
Under the hood
On the server, one or more properties files are written for each node in the
/var/rudder/share/<uuid>/rules/cfengine-community/properties.d/
directory.
This directory is then copied to each node by the agent with all other policy files.
In the agent, properties are made available in the node.<namespace>
container that contains the values.
Those values are read from
/var/rudder/cfengine-community/inputs/properties/*.json
. All files are taken
in order and override the previous ones - the last one wins.
The agent searches for optional properties files /var/rudder/local/properties.d/*.json
, and will define variables
or override existing properties.
Each file must contain at least 2 levels of JSON content, the first level is the namespace level and the second level is the key level.
The namespace name must be an ASCII name that doesn’t start with and must
match the following regex:
[a-zA-Z0-9][a-zA-Z0-9]*
For example:
{ "properties": { "datacenter": "Paris", "environment": "production", "customer": "Normation" } }
The merge is a first level merge done at the namespace level. This means that:
-
a key in a namespace is fully overridden by the same key in the same namespace in a later file.
-
a key in a namespace is never overridden by the same key in a different namespace
-
a key that is overridden never retains original data even if it is a data container itself
The result key is available in the node.<namespace>
data variable. A usage
example:
${node.properties[datacenter]}
To get the original data (for debug only) there is the
properties.property_<fileid>
variable. A usage example:
${properties.property__var_rudder_cfengine_community_inputs_properties_d_properties_json[properties][datacenter]}
Node properties expansion in directives
It is possible to use properties defined on nodes to build Directive values in all fields. The resulting values will be computed during policy generation, and can therefore provide unique values for each node or be used in JavaScript expressions.
Properties on nodes are defined using Rudder’s REST API, with the 'Update Node properties' API call. More details in our API documentation.
Properties can also be defined directly on the nodes, by creating properties files
/var/rudder/local/properties.d/*.json/
Usage
In any directive text field, you can access properties defined on nodes using the following syntax:
${node.properties[property_name][key_one][key_two]}
where:
-
property_name
is the name of the property defined via the API -
key_one
andkey_two
are keys in the JSON structure -
the value obtained is the string representation, in compact mode, of the entire node property or sub-structure of the JSON value
-
if the key is not found, an error will be raised that will stop policy generation
-
spaces are authorized around separators ([,],|,}..)
Providing a default value in Directives
You may want to provide a default value to node properties expansion to avoid a policy generation error due to missing node properties. This is also a good case to allow a simple override mechanism for a parameter where only some nodes have a specific value.
You can also use other node properties, or other Rudder parameters as defaults, using the same syntax as above.
Please note that this syntax is not available in Technique Editor. The prefered method in Technique Editor si to use Variable String with Default
generic method, or use a Technique Parameter.
Some examples:
${node.properties[datacenter][id] | default = "LON2" } ${node.properties[datacenter][name] | default = """Co-location with "Hosting Company" in Paris (allows quotes)""" } ${node.properties[datacenter][id] | default = ${rudder.param.default_datacenter} } ${node.properties[netbios_name] | default = ${rudder.node.hostname} } ${node.properties[dns_suffix] | default = ${node.properties[datacenter][dns_suffix] | default = "${rudder.node.hostname}.example.com" } #or even use cfengine variables in the default ${node.properties[my_override] | default = "${cfengine.key}"}
Forcing expansion on the node
In some cases, you will want to use a ${node.properties[key]}
in a directive parameter, but you don’t want to expand it during
policy generation on the Rudder server, but instead let the value be expanded during the agent run on the node. Typically if the value is to be used by a templating
tool, or if the value is known only on the node.
For these cases, you can add the "node" option to the property expression:
${node.properties[datacenter][id] | node }
This will be rewritten during policy generation into:
${node.properties[datacenter][id]}
Which will be considered as a standard variable by the agent, which will replaced this expression by its value if it’s defined, or kept as is if it’s unknown.
The variable content is read from /var/rudder/cfengine-community/inputs/properties.d/properties.json
, and from the optionally defined /var/rudder/local/properties.d/*.json
files.
You can find more information on node properties in node properties documentation.
JavaScript evaluation in Directives
It is possible to use JavaScript expressions to build Directive values. The resulting values will be computed during policy generation, and can therefore provide unique values for each node.
Feature availability
You can disable this feature in the Administration/Settings page, using the Enable script evaluation in Directives parameter.
Usage
All standard JavaScript methods are available, and a Rudder-specific
library, prefixed with rudder.
also provides some extra utilities. This
library is documented below.
For example, to get the first 3 letters of each node’s hostname, you can write:
"${rudder.node.hostname}".substring(0,3)
Limitation of the scripting language
JavaScript expressions are evaluated in a sandboxed JavaScript environment. It has some limitations, such as:
|
Rudder utility library
Standard hash methods
The following methods allow to simply hash a value using standard algorithms:
-
rudder.hash.md5(string)
-
rudder.hash.sha256(string)
-
rudder.hash.sha512(string)
These methods do not use a salt for hashing, and as such are not suitable for distributing passwords for user accounts on UNIX systems. See below for a preferable approach for this.
UNIX password-compatible hash methods
The following methods are specially designed to provided hashes that can be
used as user passwords on UNIX systems (in /etc/shadow
, for example). Use
these if you want to distribute hashes of unique passwords for each of your
nodes, for example.
Two different cases exist: support for generic Unix-like systems (Linux, BSD, …) and support for AIX systems (which use a different hash algorithm).
Available methods are:
-
rudder.password.auto(algorithm, password [, salt])
-
rudder.password.unix(algorithm, password [, salt])
-
rudder.password.aix(algorithm, password [, salt])
The parameters are:
-
algorithm
can be "MD5", "SHA-512", "SHA512", "SHA-256", "SHA256" (case insensitive) -
password
is the plain text password to hash -
salt
is the optional salt to use in the password (we strongly recommend providing this value - see warning below)
The unix
method generates Unix crypt password compatible hashes (for use on
Linux, BSD, etc), while the aix
method generates AIX password compatible
hashes. The auto
method automatically uses the appropriate algorithm for
each node type (AIX nodes will have a AIX compatible hash, others will
have a Unix compatible hash). We recommend always using auto
for simplicity.
For example, to use the first 8 letters of each node’s hostname as a password, you could write:
rudder.password.auto("SHA-256", "${rudder.node.hostname}".substring(0,8), "abcdefg")
Providing a salt
It is strongly recommended to provide a salt to the methods above. If no salt is provided, a random salt is created, and will be recreated at each policy generation, causing the resulting hashes to change each time. This, in turn, will generate an unnecessary "repaired" status for the password component on all nodes at each policy generation. |
JVM requirements
This features is tested only on HotSpot 1.8, OpenJDK 1.8, and IBM JVM 1.8. |
JVM requirements for AIX password hashes
AIX password generation depends on the availability of PBKDF2WithHmacSHA256 and PBKDF2WithHmacSHA512 in the JVM. These algorithms are included by default on HotSpot 1.8 and OpenJDK 1.8 and upward. In the case where your JVM does not support these algorithms, typically on an IBM JDK or a JVM 1.7 version of HotSpot and OpenJDK, the hashing algorithm falls back to SHA1 with PBKDF2WithHmacSHA1, and an error message will be logged. You can also check your JVM editor manual to add support for these algorithms. |
Status and future support
In a future version of Rudder, JavaScript evaluation will be supported in all fields in Directives, including non plain-text fields.
In the meantime, you can already test this functionality out by entering a JavaScript
expression in any Directive field, prefixed by evaljs:
. Please be aware that
this is unsupported and untested, so do this at your own risk.
There is currently no plan to extend this support to the fields in the Technique editor.
Global parameters
Rudder provides a simple way to add common and reusable variables in either plain directives, or techniques created using the technique editor: the parameters.
The parameters enable the user to specify a content that can be put anywhere, using the following syntax:
-
In directives:
${rudder.param.name}
will expand the content of the "name" parameter. -
In the technique editor:
${rudder_parameters.name}
will do the same.
Using this, you can specify common file headers (this is the default parameter, "rudder_file_edit_header"), common DNS or domain names, backup servers, site-specific elements…
In the Technique Editor
These variables are not available on Windows nodes, but only on with the classic Linux/AIX agent and within the Technique Editor .
|
Node-level system properties
These properties are evaluated on the node at run time, and are hence available both in directives parameters and in the technique editor:
Variable | Description | ${sys.arch} |
---|---|---|
Kernel short architecture |
${sys.fqhost} |
Fully qualified hostname, as seen in Rudder |
${sys.uqhost} |
Unqualified hostname |
${sys.host} |
Node’s hostname (according to the kernel) |
${sys.domain} |
Node’s domain as discovered by the agent |
There are also more variables available, all documented in this page.
← Man pages Plugin format →