前情提要

需要了解的概念,初尝试,脚本有待完善。

低级自动发现(LLD)

参考连接: https://www.zabbix.com/documentation/5.0/manual/discovery/low_level_discovery

自动发现(LLD)Low-level discovery 提供了一种在计算机上为不同实体自动创建监控项,触发器和图形的方法。例如,Zabbix可以在你的机器上自动开始监控文件系统或网络接口,而无需为每个文件系统或网络接口手动创建监控项。此外,可以配置Zabbix根据定期执行发现后的得到实际结果,来移除不需要的监控项。

在Zabbix中,支持六种类型的发现项目:

  • 系统文件的发现;
  • 网络接口的发现;
  • CPU和CPU内核的发现
  • SNMP OID的发现
  • 使用ODBC SQL查询的发现
  • Windows服务的发现

用户可以自己定义发现类型,只要它们遵循特定的JSON协议。

zabbix trapper

zabbix获取数据时有时会出现超时,如果一些数据需要执行比较长的时间才能获取的话,那么zabbix会出现异常,考虑到这种情况,zabbix增加了Trapper功能,客户端自己提交数据给zabbix。

trapper是被监控主机主动发送数据给zabbix server,与主动模式的区别是不需要安装客户端;trapper方式发送数据是以主机名处理,不是IP地址,所以主机名要唯一。在配置监控项时候Type of information项要选择text,否者会报not support错误.

tapper工作模式中,使用zabbix监控类型zabbix trapper(可以称为zabbix捕捉器),在zabbix服务器上必须有一个捕捉项目,然后需要配合zabbix_sender把数据推送给zabbix服务器

zabbix_sender

[root@Zabbix-Server ~]# cd /app/zabbix/bin/
[root@Zabbix-Server bin]# ./zabbix_sender 
usage: zabbix_sender [-Vhv] {[-zpsI] -ko | [-zpI] -T -i <file> -r} [-c <file>]
参数说明:
  -c --config <file>              # 配置文件绝对路径    
  -z --zabbix-server <server>     # zabbix server的IP地址    
  -p --port <server port>         # zabbix server端口.默认10051    
  -s --host <hostname>            # 主机名,zabbix客户端zabbix_agentd.conf配置文件中定义的 Hostname(不是服务器的hostname),不是客户端主机的ip地址    
  -I --source-address   # <IP address> 源IP    
  -k --key <key>                # 监控项的key    
  -o --value <key value>        #  key值    
  -i --input-file <input file>  # 从文件里面读取hostname、key、value 一行为一条数据,使用空格作为分隔符,如果主机名带空格,那么请使用双引号包起来    
  -T --with-timestamps          # 一行一条数据,空格作为分隔符: <hostname> <key> <timestamp> <value>,配合 --input-file option,timestamp为unix时间戳    
  -r --real-time            # 将数据实时提交给服务器    
  -v --verbose              # 详细模式, -vv 更详细

自动注册

Zabbix Active agent可以实现自动注册,进而服务器对其进行监控。通过这种方式,无需在服务器上进行手动配置便可直接启动对新host的监控。

当以前未知的active agent要求检查时,会发生自动注册。

这样功能可以非常方便的自动监控新的Cloud节点。一旦在Cloud中有一个新节点,Zabbix将自动启动host的性能和可用性数据的收集。

Active agent自动注册还支持对被添加的主机进行被动检查的监控。当active agent要求检查时,前提是在配置文件中已定义好了“ListenIP”或“ListenPort”配置参数,这些参数将发送到服务器。(如果指定了多个IP地址,则将被发送到第一个服务器。)

服务器在添加新的自动注册主机时,使用接收到的IP地址和端口配置agent。如果没有接收到IP地址值,则使用传入连接的IP地址。如果没有接收到端口值,则使用10050。

以下情况下,自动注册会自动运行:

  • 主机元数据信息发生变化
  • 手动添加主机,元数据信息有缺失
  • 手动切换主机,由另一台新的proxy监控
  • 同一台host的自动注册由新的proxy发出

配置

指定服务器

请确保在 配置文件中 指定了Zabbix server- zabbix_agentd.conf

ServerActive=10.0.0.1

如果你没有在zabbix_agentd.conf中特别定义Hostname, 则服务器将使用agent的系统主机名命名主机。Linux中的系统主机名可以通过运行'hostname'命令获取。

修改配置文件后需要重启agent

zabbix前端配置

在Zabbix前端页面,点击配置 → 动作,选择自动注册 为事件源,然后单击创建动作:

  • 在动作选项卡,定义动作名称
  • 可选指定条件。如果要使用“主机元数据”条件,请参阅下一节。
  • 在“操作”选项卡中,需要添加关联操作,如“添加主机”,“添加到主机组”(例如,发现的主机),“链接到模板”等。

使用主机元数据

当agent程序向服务器发送自动注册请求时,会发送其主机名。在某些情况下(例如,Amazon云端节点),Zabbix Server单单通过主机名区分主机。这时可以选择主机元数据将其他信息从agent发送到服务器。

主机元数据在agent配置文件 - zabbix_agentd.conf中配置。在配置文件中指定主机元数据有两种方式:

HostMetadata
HostMetadataItem

使用主机元数据来区分Linux和Windows主机。

假设你希望主机由Zabbix server自动注册,你的网络上有active Zabbix agents(请参阅上面的“配置”部分),你的网络上有Windows主机和Linux主机,你有“Template OS Linux”和“Template OS Windows” 模板,Zabbix页面可以使用。 在主机注册时,你希望将Linux / Windows模板正确的应用在正在注册的主机。默认情况下,只有主机名在自动注册时会发送到服务器,但这还不够。为了确保将正确的模板应用于主机,你应该使用主机元数据。

前端配置

第一步是配置前端,创建2个动作,第一个动作:

  • 名称:Linux主机自动注册
  • 条件:主机元数据,如 HostMetadata=Linux
  • 动作:链接到模板:Template OS Linux

在这种情况下,您可以跳过“添加主机”的操作。链接到模板需要首先添加主机,服务器会自动执行“添加主机”的操作。

第二个动作:

  • 名称:Windows主机自动注册
  • 条件:主机元数据,如Windows
  • 操作:链接到模板:Template OS Windows

AGENT配置

第二部进行Agent配置,添加下行至agent配置文件中:

HostMetadataItem=system.uname  # 可以指定例如指定值为 Linux

这样,您可以确保主机元数据包含“Linux”或“Windows”,具体取决于运行代理的主机。 在这种情况下主机元数据的示例:

Linux: Linux server3 3.2.0-4-686-pae #1 SMP Debian 3.2.41-2 i686 GNU/Linux
Windows: Windows WIN-0PXGGSTYNHO 6.0.6001 Windows Server 2008 Service Pack 1 Intel IA-32

在对配置文件进行任何更改后,请不要忘记重新启动agent。

宏变量

Zabbix 根据以下优先级来解析宏:

  1. 主机级别的宏 (首先检查);
  2. 为主机的第一级别模板定义的宏(即直接链接到主机的模板),按照模板 ID 来排序;
  3. 为主机的第二级别模板定义的宏,按照模板 ID 来排序;
  4. 为主机的第三级别模板定义的宏,按照模板ID来排序等;
  5. 全局宏 (最后检查)。

用户宏可被用于

{$MACRO}
  • 监控项名称;
  • 监控项键值参数;
  • 触发器名称和描述;
  • 触发器表达式参数和常量(详细查阅下文的 示例)
  • 许多其他位置 (详细查阅 位置支持的宏)

常见的全局和主机宏

{MACRO}
  • 在几个地方使用全局宏; 然后在所涉及的地方调整或者配置值
  • 充分利用内部模板的属性来使用宏:密码,端口号,文件名,正则表达式等等

宏函数

关于宏函数可用于自定义宏值的方法,在下面的示例中说明,其中包含的 “log line” 作为接收值:

描述说明参数受支持于
regsub (<pattern>,<output>)通过正则表达式匹配提取的子字符串(区分大小写)。pattern - 匹配的正则表达式 output - 输出的选项。 1 - 9 占位符支持被正则表达式匹配的组placeholders are supported for captured groups. 如果参数 pattern 是一个不正确的正则表达式,那么将返回 “UNKNOWN” 。{ITEM.VALUE} {ITEM.LASTVALUE}
iregsub (<pattern>,<output>)通过正则表达式匹配提取的子字符串(区分大小写)。pattern - 匹配的正则表达式 output - 输出得选项 1 - 9 placeholders are supported for captured groups
如果参数 pattern 是一个不正确的正则表达式,那么将返回 “UNKNOWN” 。
{ITEM.VALUE} {ITEM.LASTVALUE}
接收值输出
123Log line{{ITEM.VALUE}.regsub(^[0-9]+, Problem)}Problem
123 Log line{{ITEM.VALUE}.regsub("^([0-9]+)", "Problem")}Problem
123 Log line{{ITEM.VALUE}.regsub("^([0-9]+)", Problem ID: \1)}Problem ID: 123
Log line{{ITEM.VALUE}.regsub(".*", "Problem ID: \1")}Problem ID:
MySQL crashed errno 123{{ITEM.VALUE}.regsub("^([A-Z]+).*([0-9]+)", " Problem ID: \1_\2 ")}Problem ID: MySQL_123
123 Log line{{ITEM.VALUE}.regsub("([1-9]+", "Problem ID: \1")}*UNKNOWN* (invalid regular expression)

自动发现(LLD)

Old revisionsBacklinksExport to PDFBack to top

概述

有一种自动发现(LLD)函数中使用的宏类型为:

{#MACRO} 

它是一个在LLD规则中使用的宏,并返回文件系统名称、网络接口和 SNMP OIDs。

这些宏可以用于创建监控项、触发器和图形原型。然后,当发现真实的文件系统、网络接口等,这些宏将被替换为真实的值,并且以这些值来创建真实的监控项、触发器和图形。

这些宏还用于在虚拟机自动发现中创建主机和主机组原型

可支持的位置

LLD 宏可以用在:

  • 用于监控项原型中:

    • names
    • key parameters
    • units
    • SNMP OIDs
    • IPMI sensor fields
    • calculated item formulas
    • SSH and Telnet scripts
    • database monitoring SQL queries
    • descriptions (从 2.2.0 开始支持)
  • 用于触发器原型中:

    • names
    • expressions
    • URLs (从 3.0.0 开始支持)
    • descriptions (从 2.2.0 开始支持)
    • event tag names and values (从 3.2.0 开始支持)
  • 用于图形原型中:

    • names
  • 用于主机原型中 (从 2.2.0 开始支持):

    • names
    • visible names
    • host group prototype names
    • (详细查阅 全部列表)

在上述所有位置,LLD 宏都可以在用户宏上下文中使用。

一些自动发现(LLD)宏在 Zabbix 中是已经预先内置的,例如 {#FSNAME}、 {#FSTYPE}、{#IFNAME}、 {#SNMPINDEX}、 {#SNMPVALUE} 这些宏。然而,当你在创建自定义自动发现规则的时候,遵守这些宏名称不是强制性的。所以,你可以使用任何其他的 LLD 宏名称并引用该名称。

参考链接

discovery item

discovery 的格式为 json格式,可以使用以下脚本来创建json

以用户密码过期监控为例:

#!/bin/bash
# Bing 2021-03-27
# This script is used to monitor the number of days a specified user's password has expired

# 脚本当前路径
ct_path=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
config_conf="$1"

if [ ! ${config_conf} = 'expired.conf' ];then
    echo "请传入正确配置文件,expired.conf"
    exit 1
fi

# 用户密码过期天数监控
function account_expire(){
    user_name=$1
    expire_day=$2
    end_year=`chage -l ${user_name} | head -2 | tail -1 | awk -F: '{print $2}' | awk -F',' '{print $2}' | awk '{print $1}'`
    if [ "${end_year}" == "" ];then
        exit 1
    fi 
    end_mounth=`chage -l ${user_name} | head -2 | tail -1 | awk -F: '{print $2}' | awk -F',' '{print $1}' | awk '{print $1}'`
    
    case ${end_mounth} in
        'Jan') end_mounth=1;;
        'Feb') end_mounth=2;;
        'Mar') end_mounth=3;;
        'Apr') end_mounth=4;;
        'May') end_mounth=5;;
        'Jun') end_mounth=6;;
        'Jul') end_mounth=7;;
        'Aug') end_mounth=8;;
        'Sep') end_mounth=9;;
        'Oct') end_mounth=10;;
        'Nov') end_mounth=11;;
        'Dec') end_mounth=12;;
    esac
    
    end_day=`chage -l ${user_name} | head -2| tail -1 | awk -F: '{print $2}'| awk -F',' '{print $1}'| awk '{print $2}'`
    end_date_s=`/bin/date -d "${end_year}"-"${end_mounth}"-"${end_day}" +%s`
    star_date_s=`/bin/date +%s`
    let diffday=(${end_date_s}-${star_date_s})/86400
    echo $diffday
}


for i in `cat $config_conf|grep -v "^#"|grep -v "^$"`;do
    description=`echo $i|awk -F'|' '{print $1}'`
    contactGp=`echo $i|awk -F'|' '{print $2}'`
    contactTp=`echo $i|awk -F'|' '{print $3}'`
    account_name=`echo $i|awk -F'|' '{print $4}'`
    check_user=`id ${account_name} 2>/dev/null`
    if [ -z "${check_user}" ];then
        echo "用户不存在"
        continue 
    fi
    condition=`echo $i|awk -F'|' '{print $5}'`
    expire_day=`echo $i|awk -F'|' '{print $6}'`
    severity=`echo $i|awk -F'|' '{print $7}'`
    if [ -z "$severity" ];then
        severity=5
    else
        severity=$severity
    fi
    #username=`echo $i|awk -F'|' '{print $7}'`
    #username=`echo $i|awk -F'|' '{print $8}'`
    summary="$(echo ${description}_${contactGp}_${contactTp}_${account_name}_${condition}_${expire_day})"
    aaa=$(account_expire $account_name $expire_day)
    if [ -z $aaa ];then
        continue
    fi
    echo `hostname` "ACCOUNT[${summary}_${severity}]" ${aaa}
    echo `hostname` "ACCOUNT[${summary}_${severity}]" ${aaa} >>${ct_path}/logs/account_expire.log
done


/opt/zabbix/agent/bin/zabbix_sender -vv -c /opt/zabbix/agent/conf/zabbix_agentd.conf -i ${ct_path}/logs/account_expire.log
echo "============================================">>${ct_path}/logs/account_expire_sender.log
echo `date "+%Y-%m-%d %H:%M:%S"`>>${ct_path}/logs/account_expire_sender.log
cat ${ct_path}/logs/account_expire.log >>${ct_path}/logs/account_expire_sender.log
cat /dev/null >${ct_path}/logs/account_expire.log

数据send 脚本

#!/bin/sh

PATH=/usr/bin:$PATH
LANG=zh_CN.UTF-8
LC_ALL=zh_CN.UTF-8
export PATH LANG LC_ALL

os=`uname`
currentUTC=`date +%y-%m-%d' '%H:%M:%S`
DIRNAME=`dirname $0`
CONFNAME=$DIRNAME/$1
logdir="$DIRNAME/logs"
[ -d ${logdir} ]||mkdir -p ${logdir}
logpath1="account_item.log"

if [ ! -f "$DIRNAME/$1" ]
then
    exit 0
fi

function logrotate {
    DIRNAME=`dirname $0`
    backup_size=20000000
    backupcount=5
    OS=`uname`
    logdir="$DIRNAME/logs"
    logfile="$DIRNAME/logs/$1"
    [ -d ${logdir} ]||mkdir -p ${logdir}
    [ -f ${logpath} ]||touch ${logpath}
    if [ -f "$logfile" ];then
        filesize=`ls -lrt ${logfile}|awk '{print $5}'`
        if [[ "i$filesize" == "i" ]]; then
            echo "error $logfile not found!!"
            return 1
        fi
        gzip_count=`which gzip >/dev/null && echo 1 || echo 0`
        if [ ${filesize} -gt ${backup_size} ];then
            index=${backup_count}
            while [ ${index} -gt 1 ];do
                if [[ "$gzip_count" == "1" ]];then
                    if [[ ${index} -eq 2 && -f ${logfile}.1 ]];then
                        gzip "${logfile}.1"
                    fi
                    new_logfile="${logfile}.${index}.gz"
                    old_logfile="${logfile}.$((${index} -1)).gz"
                else
                    new_logfile="${logfile}.${index}"
                    old_logfile="${logfile}.$((${index} -1))"
                fi
                if [ -f ${old_logfile} ];then
                    mv -f "${old_logfile}" "${new_logfile}"
                fi
                index=`expr ${index} - 1`
            done
            cp -f "${logfile}" "${logfile}.1"
            cat /dev/null > ${logfile}
        fi
        fi
    chown -R zabbix.zabbix ${logdir}
    chmod -R 755 ${logdir}
}


function Severity_switch {

    case $1 in
        eq)
            formular='小于'
        ;;
        ne)
            formular='小于'
        ;;
        ge)
            formular='小于'
        ;;
        le)
            formular='小于'
        ;;
        gt)
            formular='小于'
        ;;
        lt)
            formular='小于'
        ;;
        *)
            echo "Unknown number formula,check the proc.conf"
        ;;
    esac
}

logrotate ${logpath1}
num=`cat $CONFNAME|grep -v '^#'|grep -v '^$'|awk -F'|' '{print $1"|"$2"|"$3"|"$4"|"$5"|"$6"|"$7}'|sort |uniq|wc -l`
i=1

echo -n  '{"data":['
cat $CONFNAME|grep -v '^#'|grep -v '^$'|awk -F'|' '{print $1"|"$2"|"$3"|"$4"|"$5"|"$6"|"$7}'|sort |uniq|\
while read LINE
do
    description=`echo $LINE|awk -F'|' '{print $1}'`
    contactGp=`echo $LINE|awk -F'|' '{print $2}'`
    contactTp=`echo $LINE|awk -F'|' '{print $3}'`
    account_name=`echo $LINE|awk -F'|' '{print $4}'`
    condition=`echo $LINE|awk -F'|' '{print $5}'`
    expire_day=`echo $LINE|awk -F'|' '{print $6}'`
    severity=`echo $LINE|awk -F'|' '{print $7}'`
    if [ -z "$severity" ];then
        severity=5
    else
        severity=$severity
    fi
    #username=`echo $i|awk -F'|' '{print $7}'`
    #username=`echo $i|awk -F'|' '{print $8}'`
    #username=`echo $i|awk -F'|' '{print $9}'`
    summary="${description}_${contactGp}_${contactTp}_${account_name}_${condition}_${expire_day}"
    echo "$currentUTC" "$LINE" >>${logdir}/${logpath1}
    if [ $i -lt ${num} ]
    then
        echo -n "{\"{#SENSOR}\":\"${summary}\","
        echo -n "\"{#DESCRIPTION}\":\"${description}\","
        echo -n "\"{#CONTACTGP}\":\"${contactGp}\","
        echo -n "\"{#CONTACTTP}\":\"${contactTp}\","
        echo -n "\"{#ACCOUNTNAME}\":\"${account_name}\","
        Severity_switch $(echo $condition|tr '[A-Z]' '[a-z]')
        echo -n "\"{#FORMULAR}\":\" $formular\","
        echo -n "\"{#EXPIREDAY}\":\"${expire_day}\","
        echo -n "\"{#SEVERITY}\":\"${severity}\"},"
    else
        echo -n "{\"{#SENSOR}\":\"${summary}\","
        echo -n "\"{#DESCRIPTION}\":\"${description}\","
        echo -n "\"{#CONTACTGP}\":\"${contactGp}\","
        echo -n "\"{#CONTACTTP}\":\"${contactTp}\","
        echo -n "\"{#ACCOUNTNAME}\":\"${account_name}\","
        Severity_switch $(echo $condition|tr '[A-Z]' '[a-z]')
        echo -n "\"{#FORMULAR}\":\" $formular\","
        echo -n "\"{#EXPIREDAY}\":\"${expire_day}\","
        echo -n "\"{#SEVERITY}\":\"${severity}\"}"
    fi
    i=`expr $i + 1`
done
echo -n ']}'
exit 0

模板 找不到了有空在传。。。。。