Action hooks¶
Action hooks allows you to customize your control plane by injecting custom code at different phase of the lifecycle of your SaaS operations
Action hooks example¶
x-omnistrate-actionhooks:
- scope: CLUSTER
type: INIT
commandTemplate: >
PGPASSWORD={{ $var.postgresqlRootPassword }} psql -U postgres
-h writer {{ $var.postgresqlDatabase }} -c "create extension vector"
As an example, in the above case, we are enabling vector extension for Postgres on cluster initialization.
Example usecases¶
Action hooks can be used for wide variety of use-cases. Here are some examples:
- To enable extensions on cluster creation
- To detect process deadlatches
- To run rebalance command after adding or removing a node
- To run post upgrade action
Action hooks concepts¶
Types of Action hooks¶
- health check
- post-start
- add
- remove
- init
- post-start
- pre-stop
- post-upgrade
If you have a requirement to add action hooks at other stages/operations, please reach out to us at support@omnistrate.com
Action hooks runtime environment¶
Action hooks are run as independent pods to minimize any runtime impact on the other data plane (aka application) resources. Having said that, action hooks can interact with other resources to perform its function.
Action hooks are defined based on when you want to run them, i.e. defining an action on service component doesn’t mean that it will be executed inside that component pod. Instead, it will be run based on the lifecycle of the service component as defined by the action type. In the above example, action hook will be run when cluster resource is first initialized.
Let's say tenant #2 is getting initialized and as you can see action hook is getting run as an indenpendent pod alongside service component pod:
Action hooks programming model¶
We support bash scripts as a runtime environment. Btw, you can also invoke any third-party service/function directly from the action hooks
If you would like to see python based runtime environment or have other suggestion, please reach out to us at support@omnistrate.com with more details on your usecase.
Action hooks variables¶
You can inject any system or dynamic variables into your action hook. For the full list, please see this and this.
Action hooks scope¶
Action hooks are categorized into two scopes:
- Node: for every node of type service component, we will run the associated action hook
- Cluster: for every service component instance, we will run the associated action hook
Action hooks with node scope:
- Health Check
- Post Start
- Add
- Remove
Action hooks with cluster scope:
- Init
- Post Start
- Pre Stop
- Post Upgrade
Action hooks lifecycle¶
In this section, we will discuss how different action hooks types are run for different SaaS operations.
To illustrate it, let's say we are building a service with Cluster resource containing two service components: SC1
and SC2
. Here is how a dependency structure may look like:
Now, if you have to define different action hook types on the Cluster resource, here is how they will get executed for each of the SaaS operations:
-
Provisioning operation: As an example, you can see
init
action hook is run after provisioning of all the service components associated with the Cluster resource.
How to configure action hooks?¶
Use x-omnistrate-actionhooks
compose tag. For more details on compose tags, see this
Alternatively, you can use register action hook API here or follow our intuitive UI to configure your hooks.
More examples¶
Scaling example¶
In this example, we are using action hooks to add a node to MongoDB cluster on scale up:
services:
mongodb-primary:
image: docker.io/omnistrate/mongodb:6.0-3
x-omnistrate-actionhooks:
- scope: NODE
type: ADD
commandTemplate: |
#!/bin/bash
set -ex
# Check if NODE_NAME is not equal to 'mongodb-primary-0'
if [ "$NODE_NAME" != {{ $sys.compute.nodes[0].name }} ]; then
# Run the mongosh command
mongosh "mongodb://{{ $var.mongodbUsername }}:{{ $var.mongodbPassword }}@{{ $sys.compute.nodes[0].name }}:27017/?authMechanism=DEFAULT" --eval "rs.add( { host: '{{ $sys.compute.node.name }}' } )"
fi
Healthcheck example¶
In this example, we are using action hooks to configure deep process liveness check on Couchbase Server.
#!/bin/sh
IP=${IP:=127.0.0.1}
PORT=${PORT:=8091}
QUERY_PORT=${QUERY_PORT:=8093}
USERNAME=${USERNAME:="Administrator"}
PASSWORD=${PASSWORD:="password"}
N1QL_STMT='SELECT name FROM `travel-sample`.inventory.hotel LIMIT 1'
i=1
numbered_echo() {
echo "[$i] $@"
i=$(expr $i + 1)
}
# Check if couchbase server is up
check_db() {
curl --silent --output /dev/null http://$IP:$PORT
echo $?
}
SUCCESS_CODE=200
EXIT_CODE=0
response=""
# Issue POST and extract response
launch_query() {
# final_cmd="curl --silent $QUERY"
numbered_echo "curl --write-out %{http_code} --output /dev/null --silent -u $USERNAME:$PASSWORD http://$IP:$QUERY_PORT/query/service -d \"statement=$N1QL_STMT\""
response=$(curl --write-out %{http_code} --output /dev/null --silent -u $USERNAME:$PASSWORD http://$IP:$QUERY_PORT/query/service -d "statement=$N1QL_STMT")
echo $response
if [ $response -ne $SUCCESS_CODE ]
then
EXIT_CODE=1
echo "Received: $response Expected: $SUCCESS_CODE => Exiting with exit code: $EXIT_CODE"
exit $EXIT_CODE
fi
}
# Wait until cb db is ready
until [[ $(check_db) = 0 ]]; do
numbered_echo "cb db not available yet"
sleep 1
done
numbered_echo "cb db is available"
# LAUNCH QUERY
launch_query
exit $EXIT_CODE