3
0
mirror of https://github.com/rvalitov/zabbix-php-fpm.git synced 2023-11-05 03:30:27 +01:00

Fix for issue #12 (#13)

## Fix (all problems specified in issue #12)
- **More robust method to discover sockets** (when PHP pool uses sockets). Script performs automatic checks of socket files (the file exists and is really a socket).
- **More robust method to discover host and port** (when PHP pool uses TCP connection).
- **Support of pools when PHP daemon listens on any network interface**. This mode is activated when in PHP pool configuration the `listen` command specifies only a port, without a host IP, for example:
```
listen = 9000
```
- **Correct discovery of pools in some cases.** The script performs analysis of all processes that belong to the pool. Previously, we checked only the first process, as a result if a pool somehow had multiple processes (for example Memcached, Redis, PostgreSQL) then discovery could capture wrong data. Now this problem is fixed.
- **Improved detection of pools**. We use better expressions in `grep` now. Previously special characters in pool names could lead to script failures. Besides such approach is a more robust method to fix #10.

## New functionality
- **Debug mode** of the discovery script helps to investigate problems that may happen
This commit is contained in:
Ramil Valitov 2019-12-19 14:02:16 +03:00 committed by GitHub
parent 805ef87655
commit 2210d3bbd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 34 deletions

View File

@ -157,11 +157,11 @@ chmod +x /etc/zabbix/zabbix_php_fpm_discovery.sh
chmod +x /etc/zabbix/zabbix_php_fpm_status.sh
```
#### 1.3. Root previliges
Automatic detection of pools requires root previliges. You can achieve it using one of the methods below.
#### 1.3. Root privileges
Automatic detection of pools requires root privileges. You can achieve it using one of the methods below.
##### 1.3.1 Root previliges for Zabbix Agent
This method sets root previliges for Zabbix Agent, i.e. the Zabbix Agent will run under `root` user, as a result all user scripts will also have the root access rights.
##### 1.3.1 Root privileges for Zabbix Agent
This method sets root privileges for Zabbix Agent, i.e. the Zabbix Agent will run under `root` user, as a result all user scripts will also have the root access rights.
Edit Zabbix agent configuration file `/etc/zabbix/zabbix_agentd.conf`, find `AllowRoot` option and enable it:
@ -179,8 +179,8 @@ Edit Zabbix agent configuration file `/etc/zabbix/zabbix_agentd.conf`, find `All
AllowRoot=1
```
##### 1.3.2 Grant previliges to the PHP-FPM autodiscovery script only
If you don't want to run Zabbix Agent as root, then you can configure the previliges only to our script. In this case you need to have `sudo` installed:
##### 1.3.2 Grant privileges to the PHP-FPM auto discovery script only
If you don't want to run Zabbix Agent as root, then you can configure the privileges only to our script. In this case you need to have `sudo` installed:
```console
apt-get install sudo
@ -305,15 +305,15 @@ If you use a custom status path, then configure it in the macros section of the
The setup is finished, just wait a couple of minutes till Zabbix discovers all your pools and captures the data.
# Testing and Troubleshooting
## Check autodiscovery
First test that autodiscovery of PHP-FPM pools works on your machine. Run the following command:
## Check auto discovery
First test that auto discovery of PHP-FPM pools works on your machine. Run the following command:
```console
bash /etc/zabbix/zabbix_php_fpm_discovery.sh
root@server:/etc/zabbix#bash /etc/zabbix/zabbix_php_fpm_discovery.sh
```
**Important:** please make sure that you use `bash` in the command above, not `sh` or other alternatives, otherwise you may get a script syntax error message.
The output should be a valid JSON with a list of pools and their sockets, something like below:
The output should be a valid JSON with a list of pools and their sockets, something like below (you may want to use [online JSON tool](https://jsonformatter.curiousconcept.com/) for pretty formatting of the response):
```json
{
@ -334,17 +334,32 @@ The output should be a valid JSON with a list of pools and their sockets, someth
}
```
If this script does not display the list, then it will show you the list of utilities that are missing on your system and must be installed. We require the following utilities to be installed:
For further investigation you can run the script above with `debug` option to get more details, example:
```console
root@server:/etc/zabbix#bash /etc/zabbix/zabbix_php_fpm_discovery.sh debug
Debug mode enabled
Success: found socket /var/lib/php7.3-fpm/web1.sock for pool web1, raw process info: php-fpm7. 5094 web1 11u unix 0x00000000dd9ea858 0t0 104495372 /var/lib/php7.3-fpm/web1.sock type=STREAM
Success: found socket /var/lib/php7.3-fpm/web4.sock for pool web4, raw process info: php-fpm7. 5096 web4 11u unix 0x00000000562748dd 0t0 104495374 /var/lib/php7.3-fpm/web4.sock type=STREAM
Success: found socket /run/php/php7.3-fpm.sock for pool www, raw process info: php-fpm7. 5098 www-data 11u unix 0x00000000ef5ef2fb 0t0 104495376 /run/php/php7.3-fpm.sock type=STREAM
Resulting JSON data for Zabbix:
{"data":[{"{#POOLNAME}":"web1","{#POOLSOCKET}":"/var/lib/php7.3-fpm/web1.sock"},{"{#POOLNAME}":"web4","{#POOLSOCKET}":"/var/lib/php7.3-fpm/web4.sock"},{"{#POOLNAME}":"www","{#POOLSOCKET}":"/run/php/php7.3-fpm.sock"}]}
```
- awk
- ps
- grep
- sort
- head
- lsof
- jq
Any warning or error messages will be displayed here.
If some pools are missing, then check that they do really exist and are running, for example, using command:
**Note:** having a warning messages does not necessarily mean that you have a error here, because different OS may provide data about processes differently. So, if you don't see any error messages here, then the script works fine.
The script can show you the list of utilities that are missing on your system and must be installed. We require the following utilities to be installed:
- `awk`
- `ps`
- `grep`
- `sort`
- `head`
- `lsof`
- `jq`
If some pools are missing, then you can manually check that they do really exist and are running, for example, using command:
```console
ps aux | grep "php-fpm"

View File

@ -1,6 +1,7 @@
#!/bin/bash
#Ramil Valitov ramilvalitov@gmail.com
#https://github.com/rvalitov/zabbix-php-fpm
#This script scans local machine for active PHP-FPM pools and returns them as a list in JSON format
S_PS=`type -P ps`
S_GREP=`type -P grep`
@ -39,31 +40,107 @@ if [[ ! -f $S_JQ ]]; then
exit 1
fi
mapfile -t PS_LIST < <( $S_PS ax | $S_GREP "php-fpm: pool " | $S_GREP -v grep )
DEBUG_MODE=""
if [[ ! -z $1 ]] && [[ $1 == "debug" ]]; then
DEBUG_MODE="1"
echo "Debug mode enabled"
fi
# Prints a string on screen. Works only if debug mode is enabled.
function PrintDebug(){
if [[ ! -z $DEBUG_MODE ]] && [[ ! -z $1 ]]; then
echo $1
fi
}
mapfile -t PS_LIST < <( $S_PS ax | $S_GREP -F "php-fpm: pool " | $S_GREP -F -v "grep" )
POOL_LIST=`printf '%s\n' "${PS_LIST[@]}" | $S_AWK '{print $NF}' | $S_SORT -u`
POOL_FIRST=0
echo -n "{\"data\":["
#We store the resulting JSON data for Zabbix in the following var:
RESULT_DATA="{\"data\":["
while IFS= read -r line
do
POOL_PID=`printf '%s\n' "${PS_LIST[@]}" | $S_GREP "php-fpm: pool $line$" | $S_HEAD -1 | $S_AWK '{print $1}'`
POOL_PID=`printf '%s\n' "${PS_LIST[@]}" | $S_GREP -F -w "php-fpm: pool $line" | $S_HEAD -1 | $S_AWK '{print $1}'`
if [[ ! -z $POOL_PID ]]; then
POOL_SOCKET=`$S_LSOF -p $POOL_PID 2>/dev/null | $S_GREP -e unix -e TCP | $S_HEAD -1 | $S_AWK '{print $9}'`
#We search for socket or IP address and port
#Socket example:
#php-fpm7. 25897 root 9u unix 0x000000006509e31f 0t0 58381847 /run/php/php7.3-fpm.sock type=STREAM
#IP example:
#php-fpm7. 1110 defualt 0u IPv4 15760 0t0 TCP localhost:8002 (LISTEN)
if [[ ! -z $POOL_SOCKET ]]; then
if [[ $POOL_FIRST == 1 ]]; then
echo -n ","
#php-fpm7. 1110 default 0u IPv4 15760 0t0 TCP localhost:8002 (LISTEN)
#Check all matching processes, because we may face a redirect (or a symlink?), examples:
#php-fpm7. 1203 www-data 5u unix 0x000000006509e31f 0t0 15068771 type=STREAM
#php-fpm7. 6086 www-data 11u IPv6 21771 0t0 TCP *:9000 (LISTEN)
#php-fpm7. 1203 www-data 8u IPv4 15070917 0t0 TCP localhost.localdomain:23054->localhost.localdomain:postgresql (ESTABLISHED)
#More info at https://github.com/rvalitov/zabbix-php-fpm/issues/12
PrintDebug "Started analysis of pool $line, PID $POOL_PID"
#Extract only important information:
POOL_PARAMS_LIST=`$S_LSOF -p $POOL_PID 2>/dev/null | $S_GREP -w -e "unix" -e "TCP"`
FOUND_POOL=""
while IFS= read -r pool
do
if [[ ! -z $pool ]]; then
if [[ -z $FOUND_POOL ]]; then
PrintDebug "Checking process: $pool"
POOL_TYPE=`echo "${pool}" | $S_AWK '{print $5}'`
POOL_SOCKET=`echo "${pool}" | $S_AWK '{print $9}'`
if [[ ! -z $POOL_TYPE ]] && [[ ! -z $POOL_SOCKET ]]; then
if [[ $POOL_TYPE == "unix" ]]; then
#We have a socket here, test if it's actually a socket:
if [[ -S $POOL_SOCKET ]]; then
FOUND_POOL="1"
PrintDebug "Success: found socket $POOL_SOCKET"
else
PrintDebug "Error: specified socket $POOL_SOCKET is not valid"
fi
elif [[ $POOL_TYPE == "IPv4" ]] || [[ $POOL_TYPE == "IPv6" ]]; then
#We have a TCP connection here, check it:
CONNECTION_TYPE=`echo "${pool}" | $S_AWK '{print $8}'`
if [[ $CONNECTION_TYPE == "TCP" ]]; then
#The connection must have state LISTEN:
LISTEN=`echo ${pool} | $S_GREP -F -w "(LISTEN)"`
if [[ ! -z $LISTEN ]]; then
#Check and replace * to localhost if it's found. Asterisk means that the PHP listens on
#all interfaces.
POOL_SOCKET=`echo -n ${POOL_SOCKET/*:/localhost:}`
FOUND_POOL="1"
PrintDebug "Success: found TCP connection $POOL_SOCKET"
else
PrintDebug "Warning: expected connection state must be LISTEN, but it was not detected"
fi
else
PrintDebug "Warning: expected connection type is TCP, but found $CONNECTION_TYPE"
fi
else
PrintDebug "Unsupported type $POOL_TYPE, skipping"
fi
else
PrintDebug "Warning: pool type or socket is empty"
fi
else
PrintDebug "Pool already found, skipping process: $pool"
fi
else
PrintDebug "Error: failed to get process information. Probably insufficient privileges. Use sudo or run this script under root."
fi
echo -n "{\"{#POOLNAME}\":"
echo -n "$line" | $S_JQ -aR .
echo -n ",\"{#POOLSOCKET}\":"
echo -n "$POOL_SOCKET" | $S_JQ -aR .
echo -n "}"
done <<< "$POOL_PARAMS_LIST"
if [[ ! -z $FOUND_POOL ]]; then
JSON_POOL=`echo -n "$line" | $S_JQ -aR .`
JSON_SOCKET=`echo -n "$POOL_SOCKET" | $S_JQ -aR .`
if [[ $POOL_FIRST == 1 ]]; then
RESULT_DATA="$RESULT_DATA,"
fi
RESULT_DATA="$RESULT_DATA{\"{#POOLNAME}\":$JSON_POOL,\"{#POOLSOCKET}\":$JSON_SOCKET}"
POOL_FIRST=1
else
PrintDebug "Error: failed to discover information for pool $line"
fi
else
PrintDebug "Error: failed to find PID for pool $line"
fi
done <<< "$POOL_LIST"
echo -n "]}"
RESULT_DATA="$RESULT_DATA]}"
PrintDebug "Resulting JSON data for Zabbix:"
echo -n $RESULT_DATA

View File

@ -1,13 +1,13 @@
#!/bin/bash
#Ramil Valitov ramilvalitov@gmail.com
#https://github.com/rvalitov/zabbix-php-fpm
#Script gets status of PHP-FPM pool
S_FCGI=`type -P cgi-fcgi`
S_GREP=`type -P grep`
if [[ ! -f $S_FCGI ]]; then
echo "Utility 'cgi-fcgi' not found. Please, install it first."
echo "In Debian you should install a package libfcgi0ldbl"
exit 1
fi