[SolusVM2][OpenVZ] Hooks

You can use hooks in SolusVM 2 to automatically run custom scripts before or after specific events take place. Hooks should be set under this directory: /usr/local/solus/hooks/, they can be written using Bash, PHP, Python or else.

 
Basically what it does is whenever there is an event it sends in stdin a json snap with the event and the action (e.g.: new installation, os reinstall, restart, etc) to all files under the hooks’ folder.
 
Example of JSON code:
{  "action": "server-restart",  "stage": "pre",  "data": {    "uuid": "915b5ca2-ff02-45ab-ba73-2e90793e6819",    "virtualization_type": "vz"  }}

Documentation

 
You can for example create a notification hook, if the server is restarted and send an mail:
#!/bin/bashset -xEeuo pipefail# Read JSON from stdinjson_data=$(cat /dev/stdin)# Extract relevant informationaction=$(echo "$json_data" | jq -r '.action')stage=$(echo "$json_data" | jq -r '.stage')server_name=$(echo "$json_data" | jq -r '.data.hostname')  # Use UUID as server name (you can customize this)server_ip=$(echo "$json_data" | jq -r '.data.network.blocks[0].ip')  # Extract the IPv4 addressif [[ "$action" == "server-restart" && "$stage" == "post" ]]; then    # Construct email message    subject="Server Restart Notification: $server_name"    body="The Server $server_ip was restarted"    echo "$body" | mail -s "$subject" [email protected]fi

Alternatively, you can also use Event handler from the GUI, in a way for example that when an event is triggered(e.g. restart) an email is sent.


When debugging it, the sequence of events goes as so:

When a VM is reinstalled:

server-reinstall / pre
server-create / pre
server-network-create / pre
server-network-create / post
server-create / post
server-reinstall / post
When a VM is reinstalled:

server-create / pre
server-network-create / pre
server-network-create / post
server-create / post
When a VM is removed:

server-delete / pre
server-network-delete / pre
server-network-delete / post
server-delete / post

Following is how the post events of server-create and server-reinstall looks like:

{  "action": "server-create",  "stage": "post",  "data": {    "virtualization_type": "vz",    "uuid": "4148968f-5fab-49a8-84c7-3bcb045a21f6",    "os_template": "almalinux-9-x86_64",    "disk_path": "/vz/private/72/0",    "disk_size": 80,    "xml": "<domain type='vzct'>\n    <name>4148968f-5fab-49a8-84c7-3bcb045a21f6</name>\n    <uuid>4148968f-5fab-49a8-84c7-3bcb045a21f6</uuid>\n    <memory unit='b'>6442450944</memory>\n    <currentMemory unit='b'>6442450944</currentMemory>\n    <vcpu placement='static'>2</vcpu>\n    <os>\n        <type>exe</type>\n        <init>/sbin/init</init>\n    </os>\n    <clock sync='localtime'/>\n    <devices>\n        <disk type='file' device='disk'>\n            <driver name='vzct' type='ploop'/>\n            <source file='/vz/private/72/0'/>\n            <target dev='sda' bus='virtio'/>\n            <boot order='1'/>\n                    </disk>\n                    <interface type='bridge'>\n                <target dev='sol-72'/>\n                <mac address='12:34:00:0e:b7:42'/>\n                <source bridge='br-routed'/>\n                <virtualport type='openvswitch'/>\n                <model type='virtio'/>\n                <guest dev='eth0' />\n                                    <ip family='IPv4' address='X.X.X.X' prefix='32'/>\n                            </interface>\n                            <graphics port='-1' autoport='yes' listen='127.0.0.1' passwd='MetRz9kPH' type='vnc'/>\n            </devices>\n</domain>\n",    "should_start": true,    "network": {      "bridge": {        "type": "routed",        "name": "br-routed"      },      "interface": "sol-72",      "mac_address": "12:34:00:0e:b7:42",      "isolation_rules": [        "arp",        "dhcp",        "cloud_init",        "portmapper"      ],      "blocks": [        {          "type": "IPv4",          "ip": "X.X.X.X",          "gateway": "Y.Y.Y.Y",          "name_servers": [            "8.8.8.8",            "8.8.4.4"          ],          "net_mask": "255.255.255.255",          "subnet": "",          "cidr": "32"        }      ],      "vlan": {        "is_enabled": false,        "tag": 0,        "mode": "",        "trunks": null      }    },    "limits": {      "disk_iops": {        "limit": 1,        "unit": "iops",        "is_enabled": false      },      "disk_bandwidth": {        "limit": 1,        "unit": "Bps",        "is_enabled": false      },      "network_incoming_bandwidth": {        "limit": 1,        "unit": "Mbps",        "is_enabled": false      },      "network_outgoing_bandwidth": {        "limit": 1,        "unit": "Mbps",        "is_enabled": false      },      "network_incoming_traffic": {        "limit": 1,        "unit": "GiB",        "is_enabled": false      },      "network_outgoing_traffic": {        "limit": 1,        "unit": "GiB",        "is_enabled": false      },      "network_reduce_bandwidth": {        "limit": 1,        "unit": "Kbps",        "is_enabled": false      }    },    "hostname": " myvps98032.example.com",    "root_password": "eK9v8s7!MyKJi1@4",    "cpu_units": 1000,    "cpu_limit": 100,    "io_priority": 4,    "swap": 6442450944,    "public_ssh_keys": [],    "netfilter": "full",    "tun_tap": false,    "ppp": false  }}{  "action": "server-reinstall",  "stage": "post",  "data": {    "virtualization_type": "vz",    "uuid": "4148968f-5fab-49a8-84c7-3bcb045a21f6",    "os_template": "almalinux-9-x86_64",    "disk_path": "/vz/private/72/0",    "disk_size": 80,    "xml": "<domain type='vzct'>\n    <name>4148968f-5fab-49a8-84c7-3bcb045a21f6</name>\n    <uuid>4148968f-5fab-49a8-84c7-3bcb045a21f6</uuid>\n    <memory unit='b'>6442450944</memory>\n    <currentMemory unit='b'>6442450944</currentMemory>\n    <vcpu placement='static'>2</vcpu>\n    <os>\n        <type>exe</type>\n        <init>/sbin/init</init>\n    </os>\n    <clock sync='localtime'/>\n    <devices>\n        <disk type='file' device='disk'>\n            <driver name='vzct' type='ploop'/>\n            <source file='/vz/private/72/0'/>\n            <target dev='sda' bus='virtio'/>\n            <boot order='1'/>\n                    </disk>\n                    <interface type='bridge'>\n                <target dev='sol-72'/>\n                <mac address='12:34:00:0e:b7:42'/>\n                <source bridge='br-routed'/>\n                <virtualport type='openvswitch'/>\n                <model type='virtio'/>\n                <guest dev='eth0' />\n                                    <ip family='IPv4' address='X.X.X.X' prefix='32'/>\n                            </interface>\n                            <graphics port='-1' autoport='yes' listen='127.0.0.1' passwd='MetRz9kPH' type='vnc'/>\n            </devices>\n</domain>\n",    "should_start": true,    "network": {      "bridge": {        "type": "routed",        "name": "br-routed"      },      "interface": "sol-72",      "mac_address": "12:34:00:0e:b7:42",      "isolation_rules": [        "arp",        "dhcp",        "cloud_init",        "portmapper"      ],      "blocks": [        {          "type": "IPv4",          "ip": "X.X.X.X",          "gateway": "Y.Y.Y.Y",          "name_servers": [            "8.8.8.8",            "8.8.4.4"          ],          "net_mask": "255.255.255.255",          "subnet": "",          "cidr": "32"        }      ],      "vlan": {        "is_enabled": false,        "tag": 0,        "mode": "",        "trunks": null      }    },    "limits": {      "disk_iops": {        "limit": 1,        "unit": "iops",        "is_enabled": false      },      "disk_bandwidth": {        "limit": 1,        "unit": "Bps",        "is_enabled": false      },      "network_incoming_bandwidth": {        "limit": 1,        "unit": "Mbps",        "is_enabled": false      },      "network_outgoing_bandwidth": {        "limit": 1,        "unit": "Mbps",        "is_enabled": false      },      "network_incoming_traffic": {        "limit": 1,        "unit": "GiB",        "is_enabled": false      },      "network_outgoing_traffic": {        "limit": 1,        "unit": "GiB",        "is_enabled": false      },      "network_reduce_bandwidth": {        "limit": 1,        "unit": "Kbps",        "is_enabled": false      }    },    "hostname": " myvps98032.example.com",    "root_password": "eK9v8s7!MyKJi1@4",    "cpu_units": 1000,    "cpu_limit": 100,    "io_priority": 4,    "swap": 6442450944,    "public_ssh_keys": [],    "netfilter": "full",    "tun_tap": false,    "ppp": false  }}

Case of usage:

In my case of usage, I had to setup a VM routing for a specific requirement. So I wrote the following script that takes in consideration if it’s:
– a new VM Creation
– or a reinstallation of a Linux OS.

 

In both cases we only need to verify a “post” && “server-create” event.

Using the argument: vzctl exec UUID CMD.

The script will be set in: /usr/local/solus/hooks/gateway_hook.sh

 

This requires basic file management, so I wrote it in bash and used JQ (JSON Query utility for Bash CLI scripts).

#!/bin/bashset -xEeuo pipefail# This Hook serves in setting up a routing gateway for the VMs# Read JSON from stdinjson_data=$(cat /dev/stdin)# Debug stdin input#logger -t 'SolusVM2' "$json_data" | jq# Check for desired actions using jqaction=$(echo "$json_data" | jq -r '.action')stage=$(echo "$json_data" | jq -r '.stage')logger -t 'SolusVM2' "[Custom Hook] Detected action: $action"if [[ "$action" == "server-create" && "$stage" == "post" ]]; then  									# VM ID	VMID=$(echo "$json_data" | jq -r '.data.uuid')	logger -t 'SolusVM2' "[Custom Hook] Run from /usr/local/solus/hooks/gateway_hook.sh | UUID: $VMID "	# Check the distribution ID_LIKE debian or rhel	DISTRO=$(vzctl exec $VMID cat /etc/os-release)	if echo $DISTRO | grep -q 'debian'; then		# Debian or Ubuntu		vzctl exec $VMID '  	echo "#!/bin/bash  	ip route add 169.254.0.0/16 dev eth0 scope link metric 1003  	ip route add <CLUSTER_GATEWAY> dev eth0 scope link  	ip route add default via <CLUSTER_GATEWAY> dev eth0" > /etc/network/if-up.d/zup  	chmod +x /etc/network/if-up.d/zup  	'	elif echo $DISTRO | grep -q 'rhel'; then		# AlmaLinux, CentOS, Fedora, Rocky Linux		vzctl exec $VMID '  	echo "169.254.0.0/16 dev eth0 scope link metric 1003  	<CLUSTER_GATEWAY> dev eth0 scope link  	default via <CLUSTER_GATEWAY> dev eth0" > /etc/sysconfig/network-scripts/route-eth0  	'	fi		logger -t 'SolusVM2' "Hook ended on $VMID"	fi

P.S.: The use of logger may be useless because all the execution process is found under: /var/log/solus/agent.log. But I think it organizes better the messages output.

 
You can also for example execute a package update using yum/apt depending on the OS after the installation of a new OS.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *