Почему появилась эта статья


В мире администрирования linux есть два замечательных проекта, OpenVZ и Zabbix.
OpenVZ — система виртуализации на уровне операционной системы для ОС linux, благодаря низкому потреблению ресурсов и другим плюшкам обрела огромную популярность.
Zabbix — система мониторинга «всего», стремительно вытесняет постаревший и обросший надстройками nagios с пьедестала почета.

Тем не менее, на просторах интернета не нашлось ни одного решения что бы нормально их подружить, а именно:
1) Один агент на физический сервер.
2) Мониторинг и UBC и дискового пространства всех VE.
3) Гибкость решения.



И так, основные проблемы:
1) UBC массив текста, который нужно парсить.
Решается как не странно парсером.

2) Количество виртуальных систем на физической машине динамически меняется, поэтому очень сложно привязать к чему-то данные.
Решается отсылкой в теле уведомления vzid виртуальной системы и hostname физической.

3) Zabbix_agent будет бесполезен, если потребуется снять данные другой системой мониторинга.
Решается использованием SNMP.

Конфиги и комментарии к ним:



Настройка сервера snmpd на сервере OpenVZ:


В конфигурационный файл snmp (как правило — /etc/snmp/snmpd.conf) необходимо добавить строки:

## разрешаем доступ к оидам UBC и VZQUOTA
view systemview included .1.3.6.1.4.1.2021.51
view systemview included .1.3.6.1.4.1.2021.52

## привязываем команды
extend .1.3.6.1.4.1.2021.51 beancounters /bin/cat /proc/user_beancounters
extend .1.3.6.1.4.1.2021.52 vzquota /bin/cat /proc/vz/vzquota


Настройка системы Zabbix:


Скрипт для обработки значений, его нужно поместить в /etc/zabbix/externalscripts/check_ubc_vzquota.sh и не забыть про права на выполнение:

#!/bin/bash

HOST=$1
COMMUNITY=$2
export FILE=/tmp/$HOST.beancounters
RET=0
RET1=0
RET2=0

if [ $# == 0 ]; then
    echo "Usage: $0 hostname community_string"
    exit 1
fi

DATA_TMP=`snmpwalk -v 2c -c $COMMUNITY $HOST .1.3.6.1.4.1.2021.51.4`
if [ "$?" != "0" ]; then
    echo "Unknown snmp error"
    exit 1
fi

DATA=`echo "$DATA_TMP"| perl -ne '/"(.*)"/ ; print "$1\n" ;'`

if [ -f $FILE ]; then
echo "$DATA" | perl -n -e'
use Data::Dumper;
my $file=$ENV{"FILE"};
my $ret=0 ;
my $vid ;
my $resource ;
my $held ;
my $maxheld ;
my $barrier ;
my $limit ;
my $failcnt ;
my %beancounters ;
my %beancounters_old ;
while(<STDIN>){
    my %vmachine;
    if ( /\D*(\d+):.*/ ){ $vid=$1; $beancounters{$vid}=\%vmachine ; }
    if ( /^[\W\d]+([a-z]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*/ ) {
        $resource=$1 ;
        $held=$2 ;
        $maxheld=$3 ;
        $barrier=$4 ;
        $limit=$5 ;
        $failcnt=$6 ;
        ${beancounters{$vid}}{$resource}=[$held , $maxheld , $barrier , $limit ,$failcnt ];
        if ( ($held > $barrier) && ($barrier != 0) ) {
            print "WARNING: Limits on $vid: $resource held->$held , barrier->$barrier ( limit->$limit ) " ;
            $ret=1;
        }
    }
}

# read and parse old data
open(MYINPUTFILE, "<$file");
while(<MYINPUTFILE>){
    my %vmachine;
    if ( /\D*(\d+):.*/ ){ $vid=$1; $beancounters_old{$vid}=\%vmachine ; }
    if ( /^[\W\d]+([a-z]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*/ ) {
        $resource=$1 ;
        $held=$2 ;
        $maxheld=$3 ;
        $barrier=$4 ;
        $limit=$5 ;
        $failcnt=$6 ;
        ${beancounters_old{$vid}}{$resource}=[$held , $maxheld , $barrier , $limit ,$failcnt ];
    }
}

foreach my $vmachine_id (keys %beancounters) {
    foreach my $resource (keys %{$beancounters{$vmachine_id}} ) {
        if ( defined($beancounters{$vmachine_id}{$resource}[4]) && defined($beancounters_old{$vmachine_id}{$resource}[4]) ){
            my $failcnt=$beancounters{$vmachine_id}{$resource}[4];
            my $failcnt_old=$beancounters_old{$vmachine_id}{$resource}[4];
            my $held=$beancounters{$vmachine_id}{$resource}[0];
            my $maxheld=$beancounters{$vmachine_id}{$resource}[1];
            my $barrier=$beancounters{$vmachine_id}{$resource}[2];
            my $limit=$beancounters{$vmachine_id}{$resource}[3];
            if ( $failcnt_old < $failcnt ){
                print "CRITICAL: Incrased failcnt $vmachine_id: $resource from $failcnt_old to $failcnt (held->$held , maxheld->$maxheld , barrier->$barrier , limit->$limit ) " ;
                $ret=2;
            }
        }
    }

}

# if ($ret == 0 ) { print "Ok. \n" ; }
# print Dumper(%beancounters_old) ;
# print "\n";
exit($ret);
'


RET1=$?
fi

echo "$DATA" > $FILE
#####################################################################################
######### quota check
#####################################################################################

DATA=`snmpwalk -v 2c -c $COMMUNITY $HOST .1.3.6.1.4.1.2021.52.4 \
| perl -ne '/"(.*)"/ ; print "$1\n" ;'`

if [ "$?" != "0" ]; then
    echo "Unknown snmp error"
    exit 1
fi

echo "$DATA" | perl -n -e'
my $vid ;
my $ret=0 ;
while(<STDIN>){
    my %vid;
    if ( /\D*(\d+):.*/ ){ $vid=$1; }
    if ( /\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*/ ){
        $resource=$1 ;
        $usage=$2 ;
        $softlimit=$3 ;
        $hardlimit=$4 ;
        $time=$5 ;
        $expire=$6 ;
        if ( $usage >= $softlimit ){
            print "WARNING: VZquota limit exceeded on $vid: $resource usage->$usage, softlimit->$softlimit, hardlimit->$hardlimit, time->$time, expire->$expire " ;
            $ret=1;
        }
    }
}
exit($ret);
'

RET2=$?

#####################################################################################
########### return
#####################################################################################

if [ $RET1 -gt $RET2 ]; then
    RET=$RET1
    else
    RET=$RET2
fi

if [ $RET = 0 ]; then
    echo Ok.
fi
exit $RET

* This source code was highlighted with Source Code Highlighter.

Шаблон для item и trigger в Zabbix (если у вас используется другой community string, необходимо поменять его в теле шаблона в двух местах, в нем прописан public).

<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export version="1.0" date="05.01.11" time="07.22">
 <hosts>
  <host name="snmp_ubc_vzquota">
   <proxy_hostid>0</proxy_hostid>
   <useip>1</useip>
   <dns></dns>
   <ip>127.0.0.1</ip>
   <port>10050</port>
   <status>3</status>
   <useipmi>0</useipmi>
   <ipmi_ip>127.0.0.1</ipmi_ip>
   <ipmi_port>623</ipmi_port>
   <ipmi_authtype>0</ipmi_authtype>
   <ipmi_privilege>2</ipmi_privilege>
   <ipmi_username></ipmi_username>
   <ipmi_password></ipmi_password>
   <groups>
    <group>Templates custom</group>
   </groups>
   <triggers>
    <trigger>
     <description>UBC and VZQUOTA trigger</description>
     <type>0</type>
     <expression>{snmp_ubc_vzquota:check_ubc_vzquota.sh[public].str(Ok.)}=0</expression>
     <url></url>
     <status>0</status>
     <priority>5</priority>
     <comments></comments>
    </trigger>
   </triggers>
   <items>
    <item type="10" key="check_ubc_vzquota.sh[public]" value_type="4">
     <description>UBC and VZQUOTA check1</description>
     <ipmi_sensor></ipmi_sensor>
     <delay>30</delay>
     <history>90</history>
     <trends>365</trends>
     <status>0</status>
     <data_type>0</data_type>
     <units></units>
     <multiplier>0</multiplier>
     <delta>0</delta>
     <formula>0</formula>
     <lastlogsize>0</lastlogsize>
     <logtimefmt></logtimefmt>
     <delay_flex></delay_flex>
     <authtype>0</authtype>
     <username></username>
     <password></password>
     <publickey></publickey>
     <privatekey></privatekey>
     <params></params>
     <trapper_hosts>localhost</trapper_hosts>
     <snmp_community></snmp_community>
     <snmp_oid></snmp_oid>
     <snmp_port>161</snmp_port>
     <snmpv3_securityname></snmpv3_securityname>
     <snmpv3_securitylevel>0</snmpv3_securitylevel>
     <snmpv3_authpassphrase></snmpv3_authpassphrase>
     <snmpv3_privpassphrase></snmpv3_privpassphrase>
     <applications/>
    </item>
   </items>
   <templates/>
   <graphs>
   </graphs>
   <macros/>
  </host>
 </hosts>
 <dependencies/>
</zabbix_export>


* This source code was highlighted with Source Code Highlighter.

Уведомления:

image

Привязываем шаблон к серверу и можно создавать VE для тестов!