Hooks are an optional but useful Razor object. Hooks provide a way to run arbitrary scripts when certain events occur during a node's lifecycle. The behavior and structure of a hook are defined by a hook type.

The two primary components for hooks are:

Configuration — A JSON document for storing data on a hook. Configurations have an initial value and can be updated by hook scripts.

Event scripts — Scripts that run when a specified event occurs. Event scripts must be named according to the handled event.

Creating hooks

The hook object created by this command sets its initial configuration to the JSON document:

{
"example1": 7,
"example2": "rhubarb"
}

Each time an event script for a hook runs, it has an opportunity to modify the hook's configuration. These changes to the configuration are preserved by the Razor server. The server also makes sure that hooks don't modify their configurations concurrently in order to avoid data corruption.

The delete-hook command is used to remove a hook.

Hook configuration

Hook scripts can use the hook object's configuration.

The hook type specifies the configuration data that it accepts in configuration.yaml. That file must define a hash:

For each event that the hook type handles, it must contain a script with the event's name. That script must be executable by the Razor server. All hook scripts for a certain event are run in an indeterminate order when that event occurs.

Event scripts

The general protocol is that hook event scripts receive a JSON object on
their stdin, and might return a result by printing a JSON object to their
stdout.

The properties of the input object vary by event, but they always
contain a hook property:

The configuration object is initialized from the hash described in
the hook's configuration.yaml and the properties set by the current
values of the hook object's configuration. With the create-hook command
above, the input JSON would be:

The script might return data by producing a JSON object on its stdout to
indicate changes that should be made to the hook's configuration. The
updated configuration is used on subsequent invocations of any
event for that hook. The output must indicate which properties to
update, and which ones to remove:

The Razor server ensures that invocations of hook scripts are
serialized. For any hook, events are processed one-by-one to allow for
transactional safety around the changes any event script might make.

Node events

Most events are directly related to a node. The JSON input to the event
script has a node property that contains the representation of the
node in the same format the API produces for node details.

Error handling

The hook script must exit with exit code 0 if it succeeds; any other exit
code is considered a failure of the script.

Whether the failure of a script
has any other effects depends on the event. A failed execution can still
make updates to the hook and node objects by printing to stdout in the same
way as a successful execution.

To report error details, the script should produce a JSON object with an
error property on its stdout in addition to exiting with a non-zero exit
code. If the script exits with exit code 0, the error property is still
recorded, but the event's severity isn't an error. The error
property should itself contain an object whose message property is a
human-readable message; additional properties can be set. For example:

Sample hook

Here is an example of a basic hook called counter that counts the
number of times Razor registers a node.

This example creates a
corresponding directory for the hook type, counter.hook, inside the
hooks directory. You can store the current count as a configuration entry
with the key count. Thus the configuration.yaml file might look like
this:

count:
description: "The current value of the counter"
default: 0

To make sure a script runs whenever a node is bound to a policy, create a
file called node-bound-to-policy and place it in the counter.hook
folder. Then write this script, which reads in the current configuration
value, increments it, then returns some JSON to update the configuration on
the hook object:

Note that this script uses jq, a bash
JSON manipulation framework. This must be on the $PATH in order for
execution to succeed.

Next, create the hook object, which stores the configuration:

razor create-hook --name counter --hook-type counter

Since the configuration is absent from this creation call, the default value
of 0 in configuration.yaml is used. Alternatively, this could be set using
--configuration count=0 or --c count=0.

The hook is now ready to use. You can query the existing hooks in a system via
razor hooks. To query the current value of the hook's configuration,
razor hooks counter will show count initially set to 0. When a node gets
bound to a policy, the node-bound-to-policy script is triggered,
yielding a new configuration value of 1.

Assign dynamic hostnames using hooks

You can use a hook to create more advanced dynamic hostnames than the simple incremented pattern — $\{id\}.example.com — from the hostname property on a policy.

Before you begin

Ruby must be installed in $PATH for the hook script to succeed. By default, Ruby is installed as required with Puppet Enterprise. If Ruby isn't installed, add it to one of the paths specified in the hook_execution_path class parameter of the pe_razor class.

This type of hook calculates the correct hostname and returns that hostname as metadata on the node. To do so, it uses a basic counter system that stores the number of nodes bound to a given policy.

This hook is intended to be extended for cases where an external system needs to be contacted to determine the correct hostname. In such a scenario, the new value is still returned as metadata for the node.

(Optional) If multiple policies require their own counter, create multiple instances of
this hook with different policy and/or hostname-pattern hook configurations.

Running the create-hook command kicks off this sequence of events:

The counter for the policy starts at 1.

When a node boots, the node-bound-to-policy event is triggered.

The policy's name from the event is then passed to the hook as input.

The hook matches the node's policy name to the hook's policy name.

If the policy matches, the hook calculates a rendered hostname-pattern:

It replaces ${count} with the current value of the counter hook
configuration.

It left-pads the ${count} with padding zeroes. For example, if the hook
configuration's padding equals 3, a count of 7 will be rendered as
007.

It replaces ${policy} with the name of its policy.

The hook returns the rendered hostname-pattern as the node metadata
of hostname and returns the incremented value for the counter that was used, so
that the next execution of the hook uses the next value.

Viewing the hook's activity log

To view the status of the hook's executions, see razor hooks $name log: