A hook is an executable file that Shell-operator runs when some event occurs. It can be a script or a compiled program written in any programming language. For illustrative purposes, we will use bash scripts. An example with a hook in the form of a Python script is available here: 002-startup-python.
The hook receives the data and returns the result via files. Paths to files are passed to the hook via environment variables.
At startup Shell-operator initializes the hooks:
-
The recursive search for hook files is performed in the working directory. You can specify it with
--working-dircommand-line argument or with theSHELL_OPERATOR_WORKING_DIRenvironment variable (the default path is/hooks).- The executable files found in the path are considered hooks.
-
The found hooks are sorted alphabetically according to the directories’ and hooks’ names. Then they are executed with the
--configflag to get bindings to events in JSON format. -
Shell-operator subscribes to events using received bindings.
Shell-operator runs the hook with the --config flag. In response the hook should print out its event binding configuration to stdout:
{
"onStartup": ORDER,
"schedule": [
{SCHEDULE_PARAMETERS},
{SCHEDULE_PARAMETERS}
],
"onKubernetesEvent": [
{ON_KUBERNETES_EVENT_PARAMETERS},
{ON_KUBERNETES_EVENT_PARAMETERS}
]
}
Event binding is an event type (onStartup, schedule, and onKubernetesEvent) plus parameters required for a subscription.
The execution at the Shell-operator’ startup.
Syntax:
{
"onStartup": ORDER
}
Parameters:
ORDER — the execution order (when added to the queue, the hooks will be sorted in the specified order, and then alphabetically). The value should be an integer.
Scheduled execution. You can bind a hook to any number of schedules.
Syntax:
{
"schedule": [
{
"name": "Every 20 minutes",
"crontab": "0 */20 * * * *",
"allowFailure": true|false,
},
{
"crontab": "* * * * * *,
"allowFailure": true|false,
},
...
]
}
Parameters:
name — is an optional identifier. It is used to distinguish between multiple schedules during runtime. For more information see binding context.
crontab – is a mandatory schedule with a regular crontab syntax (with additional features).
allowFailure — if ‘true’, Shell-operator skips the hook execution errors. If ‘false’ or the parameter is not set, the hook is restarted after a 5 seconds delay in case of an error.
Run a hook on a Kubernetes object changes.
Syntax:
{
"onKubernetesEvent": [
{
"name": "Monitor labeled pods in cache tier",
"kind": "Pod",
"event": [ "add", "update", "delete" ],
"selector": {
"matchLabels": {
"myLabel": "myLabelValue",
"someKey": "someValue",
...
},
"matchExpressions": [
{
"key": "tier",
"operation": "In",
"values": ["cache"],
},
...
],
},
"namespaceSelector": {
"matchNames": ["somenamespace", "proj-production", "proj-stage"],
"any": true|false,
},
"jqFilter": ".metadata.labels",
"allowFailure": true|false,
},
{"name":"monitor Pods", "kind": "pod", ...},
...
{...}
]
}
Parameters:
-
nameis an optional identifier. It is used to distinguish different bindings during runtime. For more info see binding context. -
kindis the case-insensitive type of a monitored Kubernetes object from the list:- namespace
- cronjob
- daemonset
- deployment
- job
- pod
- replicaset
- replicationcontroller
- statefulset
- endpoints
- ingress
- service
- configmap
- secret
- persistentvolumeclaim
- storageclass
- node
- serviceaccount
-
event— the list of monitored events (add, update, delete). By default all events will be monitored. -
selector— standard selector of objects (examples of use). If the selector is not set, then all objects are selected. -
namespaceSelector— specifies the filter for selecting namespaces. If you omit it, the events from all namespaces will be monitored. -
jqFilter— an optional parameter that specifies additional event filtering with jq syntax. The hook will be triggered only when the properties of an object are changed after the filter is applied. See example 102-monitor-namespaces. -
allowFailure— if ‘true’, Shell-operator skips the hook execution errors. If ‘false’ or the parameter is not set, the hook is restarted after a 5 seconds delay in case of an error.
Example:
{
"onKubernetesEvent": [
{
"name": "Trigger on labels changes of Pods with myLabel:myLabelValue in any namespace",
"kind": "pod",
"event": ["update"],
"selector": {
"matchLabels": {
"myLabel": "myLabelValue"
}
},
"namespaceSelector": {
"any": true
},
"jqFilter": ".metadata.labels",
"allowFailure": true
}
]
}
Note: Shell-operator requires a ServiceAccount with the appropriate RBAC permissions. See examples with RBAC: monitor-pods and monitor-namespaces.
Events may happen at any time, so the working queue for hooks is provided in the Shell-operator:
-
Adding events to the queue:
onStartuphooks are added to the queue during initialization,onKubernetesEventhooks are added to the queue when events occur in Kubernetes,schedulehooks are added according to the schedule.
-
Queue handler executes hooks strictly sequentially. If hook fails with an error (non-zero exit code), Shell-operator restarts it (every 5 seconds) until success. In case of an erroneous execution of some hook, when other events occur, the queue will be filled with new tasks, but their execution will be blocked.
- You can change this behavior for a specific hook by adding
allowFailure: trueto the binding configuration (not available foronStartuphooks).
- You can change this behavior for a specific hook by adding
-
Several metrics are available for monitoring the activity of a queue: queue size, number of execution errors for specific hooks, etc. See METRICS for more details.
When an event associated with a hook is triggered, Shell-operator executes the hook without arguments and sets the following environment variables:
-
BINDING_CONTEXT_PATH— a path to a file containing data about an event that was triggered (binding context); -
WORKING_DIR— a path to a hooks directory (see an example — using libraries viaWORKING_DIR).
Binding context is the information about the event that led to the hook execution.
The BINDING_CONTEXT_PATH environment variable contains the path to a file with JSON-array of structures with the following fields:
bindingis a string from thenameparameter. If the parameter has not been set in the binding configuration, thenscheduleoronKubernetesEventbinding types are used. For a hook executed at startup, the binding type is alwaysonStartup.
There are some extra fields for onKubernetesEvent-type events:
resourceEvent— the event type is identical to the values in theeventparameter: “add”, “update” or “delete”.resourceNamespace,resourceKind,resourceName— the information about the Kubernetes object associated with an event.
For example, if you have the following binding configuration of a hook:
{
"schedule": [
{
"name": "incremental",
"crontab": "0 2 */3 * * *",
"allowFailure": true
} ]
}... then at 12:02 it will be executed with the following binding context:
[{ "binding": "incremental"}]The following tools for debugging and fine-tuning of Shell-operator and hooks are available:
- Analysis of logs of a Shell-operator’s pod (enter
kubectl logs -f po/POD_NAMEin terminal), - The environment variable can be set to
RLOG_LOG_LEVEL=DEBUGto include the detailed debugging information into logs, - You can run the Shell-operator with the
--debug=yesflag to obtain even more detailed debugging information and save it to logs, - You can view the contents of the working queue via the HTTP request
/queue(queueendpoint):kubectl port-forward po/shell-operator 9115:9115 curl localhost:9115/queue