Directives ordering

Configuration in Rudder are based on desired states, describing the expected state of the system. However, there are cases where having order is desirable (like ensuring that a JVM is present before deploying an Application server, or ensuring a user is present before setting it sudoers), even if it will converge over the course of several agent runs.

In Rudder, there is two separated ways to order things, depending the type of Technique". So, before that, we need to explain how Policies are generated on the agent from Directives based on the same Technique.

Policy generation and Directive merge

In Rudder, Policies are generated from Directives, but several Directives based on the same Technique always lead to one Policy on the agent. For unique (non multi-instance) Technique, the one with the highest priority is selected. For multi-instance Technique, the different Directive values are merged into one Policy after having been sorted.

[Tip]Separated Policy Generation in Rudder 4.3
In Rudder 4.3, that limitation is lifted and Technique can be made to generate ONE Policy for each Directive. That capacity is controled by the
`POLICYGENERATION` tag, where the value `merged` is the pre-4.3 default behavior, and values `separated` or `separated-with-param` lead to one Policy per Directive.
See https://www.rudder-project.org/redmine/issues/10625[Don't merge directive from same technique on generation] for more information.

Sorting Directives based on the same Technique

For Directive based on the same Technique, the sort order is based on the Priority value of the Directive. Between two Directive, the one with the highest Priority is the first:

  • for a non multi-instance Technique, it means that it is there is only one that is chosen in the resulting Policies (the others are discared),
  • for a multi-instance Technique, it means that the variables in the Policy will be declared and check in sorting order of Directives (so the first Directive's variables will be declared in first position and check first during an agent run).

If several Directives have the same Priority, the Rule name, and then the Directive name are used for sorting in alphanumeric order.

[Warning]Priority field value and meaning

The Priority field of a Directive used to be a number, from 0 to 10, where 0 means "highest priority". This changed with https://www.rudder-project.org/redmine/issues/11725 but if you knew Rudder before that change, please use "0" whenever the documentation says "highest priority".

Special use case: overriding generic_variable_definition

You can use the merging of Directive to define variable override with the "Generic Variable Definition" Technique.

For example, let say you want to define a DNS variable with default value [default dns] and on some node case, a value [overrided dns]:

  • Create a Directive [1] with high priority: it will be your default case, so set DNS to [default dns].
  • Create an other Directive [2] with lower priority: it will be your specialized case, so set DNS to [overrided dns].

Then, a node with only Directive [1] will have the default value defined, and a node with both Directives will have the overriding one.

It works because on the agent, you can redeclare a variable name and reassign to it a new value: the last one wins (so in our case, the less prioritary).

Sorting Policies

Rudder uses a best-effort method for ordering Policies, based on alphanumeric ordering of the corresponding Rule, then Directive name.

When several Directive were merged, Rudder choose the first (Rule name, Directive name) as the ordering value to use for the resulting Policy.

[Tip]Best practice

You should always start Rules and Directives name by 2 (or 3) digits to be able to easily reorder Policy evaluation if the need happen:

Do not use: "My general security rule" and "Check ssh configuration"

But use: "05. My general security rule" and "40. Check ssh configuration"

Example

  • given three Techniques A, B and C
  • directives A1 and A2 based on Technique A, directives B1 and B2 based on B, directives C1 and C2 based on C
  • all Directives have the same priority,
  • rule R0 having [C1], R1 having [A1, B2] and rule R2 having [A2, B1, C2], all applied on a same node,
  • merging (R0, C1) and (R2, C2) ⇒ [C1, C2] and keep (R0, C1) as Policy order
  • merging (R1, A1) and (R2, A2) ⇒ [A1, A2] and keep (R1, A1) as Policy order,
  • merging (R1, B2) and (R2, B1) ⇒ [B2, B1] (because R1 < R2) and keep (R1, B2) for policy order,
  • so policies are sort: (R0, C1) then (R1, A1) then (R1, B2)
  • resulting ordering of directive’s values will be: [C1, C2] then [A1, A2] then [B1, B2]