Моніторимо клієнтські ПК Microsoft AD з допомогою Zabbix. Частина 2 — Шаблон, скрипти і LLD

Zabbix має досить великими можливостями з коробки, але цього інколи може не вистачати, і на цей випадок є можливість використовувати цей скрипт для обробки подій(Report problems to script). До самого скрипта повернемося трохи пізніше, поки опишу тільки основну думку, щоб було зрозуміло, що і навіщо ми додаємо в description тригерів. Скрипт парсити тіло листа і шукає рядок MYparsBLOCK:funcname: якщо знаходить, то виконує funcname(), якщо не знаходить, то просто відправляє оповіщення. Найрозумніше додавати це опис тригерів, тому в Actions-Event source –Triggers-operations необхідно додати в default message — {TRIGGER.DESCRIPTION}.

Готуємо template
Необхідно створити шаблон для моніторингу, який буде прикріплюватися до нових хостів, з допомогою правила автореєстрації. (Action-> Event Source->Auto registration->Link to templates: Win_monitor) Я взяв за основу стандартний шаблон zabbix для windows, а також APC Smart UPS Monitoring десь з просторів, викинув з них все зайве і додав, що потрібно мені.

ItemsAgent ping
agent.ping
Average disk queue length
perf_counter[\234(_Total)\1400]
Average disk read queue length
perf_counter[\234(_Total)\1402]
Average disk write queue length
perf_counter[\234(_Total)\1404]
CPU Model
wmi.get[ROOT\cimv2,SELECT Name FROM Win32_Processor]
CPU Utilization
perf_counter[\238(_Total)\6]
APC Smart UPS Monitoring: Driver Caption
wmi.get[ROOT\cimv2,SELECT Caption FROM Win32_PNPEntity WHERE PNPDeviceID LIKE '%VID_051D&PID_0002%' OR Service LIKE '%hidbatt%']
Free disk space on C:
vfs.fs.size[c:,free]
Free disk space on C: (percentage)
vfs.fs.size[c:,pfree]
Free memory
vm.memory.size[free]
Host name of zabbix_agentd running
agent.hostname
Mainboard Model
wmi.get[ROOT\cimv2,SELECT Product FROM Win32_BaseBoard]
System information
system.uname
System uptime
system.uptime
Total disk space on C:
vfs.fs.size[c:,total]
Total memory
vm.memory.size[total]
disk space Used on C:
vfs.fs.size[c:,used]
APC Smart UPS Monitoring: Час роботи від батареї
battery.runtime
APC Smart UPS Monitoring: Дата заміни батареї
battery.mfr.date
APC Smart UPS Monitoring: Заряд батареї
battery.charge
APC Smart UPS Monitoring: Модель UPS
ups.model
APC Smart UPS Monitoring: Навантаження
ups.load
APC Smart UPS Monitoring: Напруга (вхід)
input.voltage
APC Smart UPS Monitoring: Напруга (на вихід)
output.voltage
APC Smart UPS Monitoring: Статус UPS
ups.status
APC Smart UPS Monitoring: Статус біпера
ups.beeper.status
APC Smart UPS Monitoring: Температура батареї
battery.temperature

TriggersFree disk space is less than 1GB on volume C: {HOST.NAME}
{Win_monitor:vfs.fs.size[c:,free].last(0)}<1073741824
Lack of free memory on {HOST.NAME}
{Win_monitor:vm.memory.size[free].avg(30м)}<10000000
APC Smart UPS Monitoring: robot_ Не приходять дані з ДБЖ {HOST.NAME}
{Win_monitor:ups.status.str(Error)}=1 and {Win_monitor:wmi.get[ROOT\cimv2,SELECT Caption FROM Win32_PNPEntity WHERE PNPDeviceID LIKE '%VID_051D&PID_0002%' OR Service LIKE '%hidbatt%'].strlen()}>1
Zabbix agent on {HOST.NAME} is unreachable for 7 days
{Win_monitor:agent.ping.nodata(7d)}=1
APC Smart UPS Monitoring: Батарея не заряджається на {HOST.NAME}
{Win_monitor:battery.charge.max(#120)}<90
APC Smart UPS Monitoring: Виключений біпер на {HOST.NAME}
{Win_monitor:ups.beeper.status.str(disabled)}=1
APC Smart UPS Monitoring: Низький час роботи від батареї на {HOST.NAME}
{Win_monitor:battery.runtime.last(0)}<5 and {Win_monitor:ups.model.str(Smart)}=1


Я вже писав, що реалізація задуму з моніторингом упсів виявилася не такою гладкою, як хотілося б. Упси постійно відвалюються, допомагає перезапуск драйвера за допомогою утиліти devcon, тому додаємо в тригер(description) «robot_ Не приходять дані з ДБЖ {HOST.NAME}» наш блок з функцією nutp. Ну і нікому не потрібні мертві хости в моніторингу, тому тригер «Zabbix agent on {HOST.NAME} is unreachable for 7 days» додаємо функцію remove_offline, яка буде видаляти хости з zabbix:

MYparsBLOCK:nutpt:
 
HIP:{HOST.DNS}
 
MYparsBLOCK:remove_offline:
 
HID:{HOST.NAME}
 


Low-level discovery
Що стосується смартів, то звичайні Items і Triggers нам не підійдуть, оскільки на різних машинах може бути різна кількість смартів. В zabbix є можливість зробити item та trigger prototype, які будуть створюватися для списку об'єктів, отриманих з допомогою low-level discovery rules, детальніше можна почитати тут. Щоб правило працювало, нам потрібно написати скрипт/додаток, яке буде при запуску видавати список хардів в спеціальному форматі JSON. Спочатку я зробив скрипт на powershell, але на частині машин скрипт періодично не встигав виконатися за 30 секунд, з-за того, що сам powershell дуже довго ініціалізується. Довелося відмовитися від powershell і зробити exe програма на c#(я його не знаю, але він здався досить простим, щоб переписати сценарій). Додаток з допомогою smartctl отримує список hdd, прибирає повторювані(за серийникам) і виводить в потрібному нам форматі.

hddscan.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace hdd_scan
{
class Program
{
static string[] smartctl(string arg)
{
Process p = new Process();
p.StartInfo.FileName = "C:\\Program Files\\Zabbix\\extra\\smart\\smartctl.exe";
p.StartInfo.Arguments = arg;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string[] list = output.Split('\n');
p.WaitForExit();
return list;
}

static void Main(string[] args)
{
try
{

string[] hddlist = smartctl("--scan");
Словник<string, string> psarr = new Dictionary<string, string>();
pattern string = @"^(?<1>\/[\w]+)\/(?<xer>[\S]+)\s";
foreach (string hdd in hddlist)
{
var = match Regex.Match(hdd, pattern);
if (match.Success)
{
string shdd = match.Groups["xer"].Value;
string[] tmp = smartctl("-a " + shdd);
foreach (string line in tmp)
{
if (line.Contains("Serial") == true)
{
string[] serials = Regex.Split(line, @"^Serial\sNumber\:\s+");
if (serials.Length < 2) continue;
string serial = serials[1];

if (!psarr.ContainsValue(serial))
{
psarr.Add(shdd, serial);
}
}
}
}
}

//Starting output
int cnt = 0;
Console.WriteLine("{\n");
Console.WriteLine("\t\"data\":[\n\n");
foreach (KeyValuePair<string, string> kvp in psarr)
{
string[] flist = smartctl("-a "+kvp.Key);
string checkstring = "A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.";

//
bool test= false;
for (int i = 0; i < flist.Length; i++)
{
if (flist[i].Contains(checkstring))
{
test = true;
}
}
if (!test)
{
cnt++;
if (cnt > 1)
{
Console.WriteLine("\t\n");
}
Console.WriteLine("\t{\n");
Console.WriteLine("\t\t\"{{#HDDNAME}}\":\"{0}\"\n", kvp.Key);
Console.WriteLine("\t}\n");
}
}

Console.WriteLine("\n\t]\n");
Console.WriteLine("}\n");

}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}


Так, на деяких машинах смарт може бути відключений, тому додамо ще одну функцію firstrun, і розмістимо її в повідомлення правила автореєстрації Action-> Event Source->Auto registration додаємо пункт Send message to ...via script, в тіло розміщуємо:

MYparsBLOCK:firstrun:
 
HIP:{HOST.IP}


В шаблоні створюємо discovey rule — smart.discovery.

Item prototypessmart_{#HDDNAME}_CRC_Error_Count
smart[{#HDDNAME},crc]
smart_{#HDDNAME}_Current_Pending_Sector
smart[{#HDDNAME},pend]
smart_{#HDDNAME}_Health_Status
smart[{#HDDNAME},health]
smart_{#HDDNAME}_Model
smart[{#HDDNAME},model]
smart_{#HDDNAME}_Reallocated_Sector_Ct
smart[{#HDDNAME},realloc]
smart_{#HDDNAME}_Temperature
smart[{#HDDNAME},temp]

Triggers prototypesHDD: Current_Pending_Sector на {#HDDNAME} {HOST.NAME} більше 5
{Win_monitor:smart[{#HDDNAME},pend].last()}>5
HDD: Reallocated_Sector_Ct на {#HDDNAME} {HOST.NAME} більше 5
{Win_monitor:smart[{#HDDNAME},realloc].last()}>5
HDD: Температура жорсткого диска вище 55 градусів на {#HDDNAME} {HOST.NAME}
{Win_monitor:smart[{#HDDNAME},temp].last()}>55
HDD: зафіксовано зростання CRC_Error_Count на {#HDDNAME} {HOST.NAME}
{Win_monitor:smart[{#HDDNAME},crc].change()}>0
HDD: зафіксовано зростання Current_Pending_Sector на {#HDDNAME} {HOST.NAME}
{Win_monitor:smart[{#HDDNAME},pend].change()}>0 and {Win_monitor:smart[{#HDDNAME},pend].last()}>6
HDD: зафіксовано зростання Reallocated_Sector_Ct на {#HDDNAME} {HOST.NAME}
{Win_monitor:smart[{#HDDNAME},realloc].change()}>0 and {Win_monitor:smart[{#HDDNAME},realloc].last()}>6


В description прототипів додаємо функцію hddsmart, вона буде додавати модель HDD в тіло повідомлення тригера, щоб було зрозуміло, про який саме харді йде мова, т. к. smartctl використовує в якості імені sda, sdb і т. п.

MYparsBLOCK:hddsmart:
 
HIP:{HOST.DNS}:KKEY:smart[{#HDDNAME},model]


Більшість параметрів агент не розуміє, тому в конфігурації клієнта обов'язково потрібно прописати всі UserParameter.

UserParameter
UserParameter=battery.charge,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.charge
 
UserParameter=battery.charge.low,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.charge.low
 
UserParameter=battery.charge.warning,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.charge.warning
 
UserParameter=battery.mfr.date"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.mfr.date
 
UserParameter=battery.runtime,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.runtime
 
UserParameter=battery.runtime.low,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.runtime.low
 
UserParameter=battery.temperature,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.temperature
 
UserParameter=battery.type,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.type
 
UserParameter=battery.voltage,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.voltage
 
UserParameter=battery.voltage.nominal,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost battery.voltage.nominal
 
UserParameter=input.sensitivity,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost input.sensitivity
 
UserParameter=input.transfer.high,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost input.transfer.high
 
UserParameter=input.transfer.low,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost input.transfer.low
 
UserParameter=input.voltage,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost input.voltage
 
UserParameter=output.current,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost output.current
 
UserParameter=output.frequency,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost output.frequency
 
UserParameter=output.voltage,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost output.voltage
 
UserParameter=output.voltage.nominal,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost output.voltage.nominal
 
UserParameter=ups.beeper.status,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.beeper.status
 
UserParameter=ups.delay.shutdown,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.delay.shutdown
 
UserParameter=ups.delay.start,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.delay.start
 
UserParameter=ups.firmware,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.firmware
 
UserParameter=ups.firmware.aux,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.firmware.aux
 
UserParameter=ups.load"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.load
 
UserParameter=ups.mfr,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.mfr
 
UserParameter=ups.mfr.date"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.mfr.date
 
UserParameter=ups.model,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.model
 
UserParameter=ups.productid,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.productid
 
UserParameter=ups.serial,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.serial
 
UserParameter=ups.status,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.status
 
UserParameter=ups.test.result,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.test.result
 
UserParameter=ups.timer.reboot,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.timer.reboot
 
UserParameter=ups.timer.shutdown,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.timer.shutdown
 
UserParameter=ups.timer.start,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.timer.start
 
UserParameter=ups.vendorid,"c:\Program Files (x86)\NUT\bin\upsc.exe" primary@localhost ups.timer.vendorid
 
UserParameter=smart[*],"C:\Program Files\Zabbix\cmd\smart.cmd" "$1" $2
 
UserParameter=smart.discovery, "C:\Program Files\Zabbix\cmd\hdd_scan.exe"
 

smart.cmd
@echo off
rem use smart.cmd <disk> < parameter> smart.cmd sda health
cd "C:\Program Files\Zabbix\cmd"
if %2==health ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" -H %1 | grep result | awk "{print $6}") 
if %2==model ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" -i %1 | grep "Device Model" | awk -F"Device Model:" "{print $2}")
if %2==realloc ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" --attributes %1 | grep Reallocated_S | awk "{print $10}")
if %2==crc ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" --attributes %1 | grep CRC | awk "{print $10}")
if %2==pend ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" --attributes %1 | grep Pend | awk "{print $10}")
if %2==temp ("C:\Program Files\Zabbix\extra\smart\smartctl.exe" --attributes %1 | grep Temperature_Celsius | awk "{print $10}")



Alert скрипт
Власне сам скрипт, який буде відправляти листи і виконувати наші функції:

#!/usr/bin/python env
# -*- coding: utf-8 -*-
#/var/lib/zabbixsrv/alertscripts/mail.py
import string
re import
import subprocess
import sys
import time
import os

# функція для відправки листів, шукаємо готову, переробляємо для себе
def send_mail(recipient, subject, body):
import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate
encoding='utf-8'
SMTP_SERVER = 'smtp'
SENDER_NAME = u 'Zabbix Alert'
session = None
msg = MIMEText(body, 'plain', encoding)
msg['Subject'] = Header(subject, encoding)
msg['From'] = Header(SENDER_NAME, encoding)
msg['To'] = recipient
msg['Date'] = formatdate()
try:
session = smtplib.SMTP(SMTP_SERVER)
session.sendmail(SENDER_NAME, recipient, msg.as_string())
except as Exception e:
raise e
finally:
# close session
if session:
session.quit()

# Zabbix не повинен чекати виконання скрипта, тому робимо так, щоб скрипт працював у тлі.(шукаємо готовий приклад, переробляємо для себе) 
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
os.chdir("/")
os.umask(0)
os.setsid()
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
for f in sys.stdout, sys.stderr: f.flush()
si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
#Додаємо в оповіщення модель харда 
def hddsmart():
m=re.search('MYparsBLOCK\:\S+\:\s+HIP\:(?P<hostip>\S+)\:KKEY\:(?P<kkey>\S+)',a3)
hostip,kkey= m.group('hostip') m.group('kkey')
p = subprocess.Popen('zabbix_get -s '+hostip+' -k '+kkey, shell=True,stdout=subprocess.PIPE)
bb = a3[0:string.find(a3,'MYparsBLOCK')] + 'HDD:' + p.stdout.read()
send_mail(sys.argv[1],a2,bb)
#Підготовка списку машин на видалення. Видаляти будемо через api в окремому скрипті
def remove_offline():
if 'PROBLEM:' in a2:
m=re.search('MYparsBLOCK\:\S+\:\s+HID\:(?P<hostid>\S+)',a3)
hostid = m.group('hostid') + '\n'
hidf=open('/var/log/zabbixsrv/2del_ids', 'a')
hidf.write(hostid)
hidf.close
send_mail(sys.argv[1],a2,a3[0:string.find(a3,'MYparsBLOCK')])

# Костиль, який повертає до життя драйвер для упса. Перезапускаємо девайс за допомогою утиліти microsoft devcon.
def nutpt():
if 'PROBLEM:' in a2:
m=re.search('MYparsBLOCK\:\S+\:\s+HIP\:(?P<hostip>\S+)',a3)
hostip = m.group('hostip')
log = "
i = 0
while i < 5:
p = subprocess.Popen("""zabbix_get -s %s -k 'system.run[net stop "Network UPS Tools"]'"""%(hostip), shell=True,stdout=subprocess.PIPE)
log +=p.stdout.read()
time.sleep(10)
p = subprocess.Popen("""zabbix_get -s %s -k system.run['cd "C:\Program Files\Zabbix\cmd\"&devcon.exe restart USB\VID_051D*']"""%(hostip), shell=True,stdout=subprocess.PIPE)
log +=p.stdout.read()
time.sleep(30)
p = subprocess.Popen("""zabbix_get -s %s -k 'system.run[net start "Network UPS Tools"]'"""%(hostip), shell=True,stdout=subprocess.PIPE)
log +=p.stdout.read()
i += 1
p = subprocess.Popen("""zabbix_get -s %s -k 'ups.status'"""%(hostip), shell=True,stdout=subprocess.PIPE)
if 'Error' not in p.stdout.read():
i = 8
if i <> 8:
send_mail(sys.argv[1],a2,log)
#набір дій при автореєстрації клієнта. Поки це тільки включення smart з допомогою smartctl.exe --scan-open
def firstrun():
m=re.search('MYparsBLOCK\:\S+\:\s+HIP\:(?P<hostip>\S+)',a3)
hostip = m.group('hostip')
p = subprocess.Popen("""zabbix_get -s %s -k system.run['cd "C:\Program Files\Zabbix\extra\smart\"&smartctl.exe --scan-open']"""%(hostip), shell=True,stdout=subprocess.PIPE)
log = p.stdout.read()
send_mail(sys.argv[1],a2,log)

daemonize(stdout='/var/log/zabbixsrv/script_out.log', stderr='/var/log/zabbixsrv/script_err.log')
try:
a1,a2,a3 = sys.argv[1],sys.argv[2],sys.argv[3]
#debug(рядок нижче при необхідності можна розкоментувати ) 
#os.system('echo "' + a1+' '+a2+' '+a3 +'" >> /var/log/zabbixsrv/script_dbg.log')
if 'MYparsBLOCK' in a3:
eval(re.search('MYparsBLOCK\:(?P<myfunc>\S+)\:',a3).group('myfunc'))() # запуск функції отриманої з тригера
else:
send_mail(sys.argv[1],a2,a3)

except:
#print sys.exc_info()
send_mail('admin@domain.local', 'Error in script', str(sys.exc_info()))


Майте на увазі, що якщо одержувачів кілька, то і функція виконується кілька разів. Для чого це актуально(наприклад модель HDD), а для чого то може бути навіть шкідливим, тому це обов'язково треба врахувати при налаштуванні Actions.

Скрипт для видалення неактивних хостів
#!/usr/bin/python
#
import os
from pyzabbix import ZabbixAPI, ZabbixAPIException
try:
os.rename ('/var/log/zabbixsrv/2del_ids','/var/log/zabbixsrv/klist_pr')
except:
pass
user='apirobot'
pwd='*******'
url = 'https://127.0.0.1/zabbix/'
zh = ZabbixAPI(url)
zh.session.verify = False
zh.login(user=user, password=pwd)

f = open('/var/log/zabbixsrv/klist_pr')


for hnm in f:
try:
hid = zh.host.get(filter={"host":hnm.replace('\n',")},output=['hostid'])[0]['hostid']
#zh.host.delete(hostid = hid) - API change
zh.host.delete(int(hid))
except:
pass
f.close()
os.remove('/var/log/zabbixsrv/klist_pr')


Для роботи скрипта потрібен обліковий запис з правами на видалення машин. Я запускаю скрипт по крону під іншим аккаунтом, оскільки тут зберігається пароль у відкритому вигляді.

Підключаємо агенти з dns-імені
По дефолту агенти реєструються так, що zabbix підключається до них по ip. Мене це не влаштовує, тому пишемо скрипт, який це поправить, а заодно і повідомить про проблеми lookup. За основу взяв якийсь скрипт з прикладів pyzabbix і трохи переробив.

use_fqdn.py
#!/usr/bin/python
#
# -*- coding: utf-8 -*-

import socket
from getpass import getpass
from pyzabbix import ZabbixAPI, ZabbixAPIException


zapi = ZabbixAPI(server='https://127.0.0.1/zabbix/')
zapi.session.verify = False
zapi.login('apirobot', '*******')

body = "
err = "

def send_mail(recipient, subject, body):

import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate
encoding='utf-8'
SMTP_SERVER = 'smtp'
SENDER_NAME = u'zabbix@domain.local'
MAIL_ACCOUNT = 'zabbix@domain.local'
session = None
msg = MIMEText(body, 'plain', encoding)
msg['Subject'] = Header(subject, encoding)
msg['From'] = Header(SENDER_NAME, encoding)
msg['To'] = recipient
msg['Date'] = formatdate()
try:
session = smtplib.SMTP(SMTP_SERVER)
session.sendmail(MAIL_ACCOUNT, recipient, msg.as_string())
except as Exception e:
raise e
finally:
# close session
if session:
session.quit()


# Loop through all hosts interfaces, getting only "main" interfaces of type "agent"
for in h zapi.hostinterface.get(output=["dns","ip","useip"],selectHosts=["host"],filter={"main":1,"type":1}):
#print h
# Make sure the hosts are named according to their FQDN
#
if len(h['dns']) == 0:
try:
zapi.hostinterface.update(interfaceid=h['interfaceid'], dns = socket.gethostbyaddr(h['хост'][0]['host'])[0])
except:
body += ('FQDN_UPD_ERR:' + h['хост'][0]['host']) + '\n'
try:
a = socket.gethostbyaddr(h['хост'][0]['host'])[2][0]
b = socket.gethostbyaddr(h['dns'])[2][0]
if (a != b):
body += ('Warning: %s has dns "%s"' % (h['хост'][0]['host'], h['dns'])) + '\n'

except:
body += ('DNS_LOOKUP_ERR:' + h['хост'][0]['host']) + '\n'

# Make sure they are using hostnames to connect rather than IPs (could also be filtered in the get request)
if h['useip'] == '1':
body += ('%s is using IP instead of hostname. Fixing.' % h['хост'][0]['host']) + '\n'
try:
zapi.hostinterface.update(interfaceid=h['interfaceid'], useip=0)
except ZabbixAPIException as e:
#print(e)
err += str(e)+'\n'
err += '\n'
continue

body += '\nZabbix Errors:' + err
if len(body) > 16:
send_mail('admin@domain.local','check agents',body)


Постскриптум
Всі скрипти, шаблони та інші необхідні файли викладені на github.

Моніторимо клієнтські ПК Microsoft AD з допомогою Zabbix. Частина 1 — Автовстановлення

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.