在前面的文章
让这两个系统“交朋友”的想法很久以前就诞生了,无需安装额外的软件或脚本。 快速谷歌搜索产生了许多可能的解决方案,这一切都归结为将脚本(Pyha、Bash、Python 等)上传到服务器,您会很高兴。 我想实现“开箱即用”的监控 - 无需外部脚本,也无需在具有监控和 PBX 的服务器上安装其他软件。
我总共花了4个工作日来完成这个任务,但结果是值得的。 通过 AMI 接口、低级别检测、触发器以及最重要的是连接 PBX 和所有其他设置,现在大约需要 15 分钟。
Zabbix 4.4已经可用,Asterisk版本100大约有13个。 有些 PBX 带有 FreePBX Web 界面,有些带有裸控制台、一堆技巧并通过拨号方案进行集成。
从 PBX 接收数据
需要解决的第一个也是要点是获取有关对等点和 SIP 注册的数据。 为此,PBX 具有 AGI、AMI、ARI 和 SSH 控制台接口。 由于显而易见的原因,我没有考虑额外的模块。
首先我们需要弄清楚这些agi、ami、ari是什么......
- AGI - 在拨号方案中使用脚本。 主要用于通话管理。
- AMI - 可以提供所有必要的信息,通过端口 5038 工作,类似于 Telnet。 适合我们!
- ARI——现代、时尚、JSON。 有很多可能性,数据格式对于 Zabbix 来说是可以理解的,但对我来说没有主要的事情:你无法控制 sip 注册。 另一个缺点是,对于同行来说,只有在线/离线两种状态,尽管状态有更多,并且在诊断时将它们考虑在内是有用的。
- SSH 可以做所有事情,但有时由于“安全原因”而不允许使用。 考虑的因素可能不同,我就不多说了。
然而,尽管存在种种缺点,ARI 仍能满足 90% 的监控需求。
Zabbix 和 Telnet - 我的失望
我很了解 AMI;有一次,我通过远程办公室、呼叫管理等实现了与部门对话中的丢失跟踪。 使用 Telnet,一切都非常清晰:打开连接、发送命令并读取响应。 我就是这么做的,但结果却令我失望。
Zabbix 中的 Telnet 与 Linux 控制台中的不一样,它更简单一些,并且是针对登录/密码等标准授权量身定制的。 如果授权逻辑不同,并且没有请求登录名/密码对,则会发生错误。 在尝试绕过授权要求徒劳之后,查看 Telnet 模块的源代码很有用。
我意识到,除非有传统的登录和密码请求,否则我不会继续前进。 只是为了好玩,我从代码中删除了与授权相关的所有内容并重新组装了所有内容。 作品! 但它不符合要求。 前进…
让我们回到搜索
我再次重新阅读了 ARI 文档,运行了额外的测试 - 这里没有 sip 注册。 有宴会,有谈话,有马裤,但没有登记。 在某些时候我什至想,我们真的需要秃鹫注册吗?
有趣的是,此时用户收到了另一个请求,但出局电话出现了问题。 问题是 sip 注册被冻结,只需重新启动模块即可解决。
asterisk -rx "sip reload"
如果能够通过网络访问 AMI,那就太棒了:我想,这将解决所有问题。 我开始朝这个方向挖掘,从字面上看,第一条搜索线通向官方 Asterisk 文档,该文档说我的任务有一个选项 网络功能 在文件中 /etc/asterisk/manager.conf,需要在部分中设置为 YES [一般]
之后,通过表单的常规网络请求
使用 FreePBX 界面时,您无法通过 Web 启用此选项;您需要通过控制台更改 manager.conf 文件来启用它。 当通过网络进行配置更改时,FreePBX 不会删除它。
我已经使用各种类型的 Asterisk 集成工作了很长时间,但我从未在任何地方看到过这个功能。 令我惊讶的是,没有人描述这种与 PBX 交互的方法。 查找有关该主题的信息甚至特别有用:几乎没有任何信息,或者它用于完全不同的任务。
WEB AMI - 什么样的野兽?
添加一个选项 网络功能 归档 管理器配置文件 提供通过网络对 ATS 管理的完全访问。 通过常规 AMI 可用的所有命令现在都在网络上,您可以通过套接字侦听来自 PBX 的事件。 操作原理与控制台AMI没有什么不同。 激活此选项后,您可以通过以下地址联系 PBX:
然后我想:“这就是解决办法! 现在一切都准备好了! 容易尿尿的柠檬汁”,但现在高兴还为时过早。 要获取我们需要的信息,使用 GET 请求和必要的操作就足够了 行动,作为响应返回 xml,其中包含所有注册及其状态的列表。 这一切都很棒,但是您需要授权才能记住 cookie 中的会话。 当你在浏览器中测试时,你不会考虑这个过程。
授权流程
首先我们解决地址
https://ats:8089/mxml?action=login&username=zabbix&secret=zabbix
Host: ats:8089
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
答:
GET: HTTP/1.1 200 OK
Server: Asterisk/13.29.2
Date: Thu, 18 Jun 2020 17:41:19 GMT
Cache-Control: no-cache, no-store
Content-type: text/xml
Set-Cookie: mansession_id="6f5de42c"; Version=1; Max-Age=600
Pragma: SuppressEvents
Content-Length: 146
<ajax-response>
<response type="object" id="unknown">
<generic response="Success" message="Authentication accepted"/>
</response>
</ajax-response>
在那里工作你需要 mansession_id="6f5de42c”,即授权 cookie 本身。
您只需检查内容即可找到答案”认证已接受” 接下来,对于对 PBX 服务器的所有调用,我们需要向请求添加授权 cookie。
https://ats:8089/mxml?action=SIPpeers
Host: ats:8089
Connection: close
Cookie: mansession_id="6f5de42c"
请阅读如何获取授权 cookie 并在其他请求中使用它:“
为了在 Zabbix 中创建跟踪元素,我将使用自动检测。
自动检测
要自动检测注册并跟踪对等状态,您需要联系以下地址:
作为响应,PBX 向我们返回一个 XML 响应:
<ajax-response>
<response type="object" id="unknown">
<generic response="Success" eventlist="start" message="Registrations will follow"/>
</response>
...
<response type="object" id="unknown">
<generic event="RegistryEntry" host="login.mtt.ru" port="5060" username="111111" domain="login.mtt.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
<response type="object" id="unknown">
<generic event="RegistryEntry" host="voip.uiscom.ru" port="5060" username="222222" domain="voip.uiscom.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
<response type="object" id="unknown">
<generic event="RegistryEntry" host="voip.uiscom.ru" port="5060" username="333333" domain="voip.uiscom.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
...
</ajax-response>
响应中存在大量垃圾,因此在预处理时我们通过模板进行过滤 XPath的: //响应/通用[@host]
然后乐趣就开始了。 要使用检测并动态创建元素,响应必须采用 JSON 格式。 自动检测不支持 XML。
要将 XML 转换为 JSON,我必须使用自动替换,为此我用 JS 编写了一个脚本
有趣的一点:在ATS响应中,所有参数都用单引号括起来,并且在应用模板之后 //响应/通用[@host] 它们被双倍取代。
为了创建元素,我们使用 XML 响应(现在是 JSON)中的变量。
SIP注册处
对于 sip 注册,我们使用三个变量: 用户名, 主持人, 端口。 我对元素的名称很满意 [电子邮件保护]:5060,我还没有发现任何需要使用全部五个变量的情况。
接收有关所有注册信息的主要元素, Asterisk - AMI SIPshowregistry。 它每分钟发出一次 GET 请求
当测试多达 100 个相关元素时,我没有注意到负载,但对于 1700 个元素,这会给处理器带来明显的 15 秒负载。 如果您有大量依赖元素,请记住这一点。
作为“分散”负载或为元素设置不同轮询频率的选项,您可以将处理逻辑分别移动到每个元素。
我不将收到的信息存储在主元素中。 首先,我认为没有必要这样做,其次,如果响应超过 64K,那么 Zabbix 就会将其切断。
由于我们对依赖元素使用完整的 XML 响应,因此我们需要在预处理中获取该元素的值。 通过 XPath的 这样做是这样的:
string(//response/generic[@event="RegistryEntry"][@username="{#SIP_REGISTRY_USERNAME}"][@host="{#SIP_REGISTRY_HOST}"][@port="{#SIP_REGISTRY_PORT}"]/@状态)
对于注册状态,我没有使用文本状态,而是使用 JavaScript 将它们转换为数字形式:
switch(value) {
case 'Registered':
return 1;
case 'Unregistered':
return 0;
default:
return -1;
}
SIP 对等体
与 SIP 注册类比,Asterisk 有一个主要元素 - AMI SIPshowregistry,并添加了依赖项。
这将创建两个依赖元素:
- 文本形式的对等状态
- 设备响应时间 - 如果状态正常,则写入设备响应时间,否则“-1”
元素本身的路径稍微简单一些 XPath的:
string(//响应/通用[@objectname="{#SIP_PEER_OBEJECTNAME}"]/@status)
对于第二个元素,我使用 JavaScript 来分隔 响应时间 来自对等状态,因为它们存储在一起:
if(value.substring(0,2) == 'OK'){
return value.match(/(d+)/gm);
}
else {
return -1;
}
结论
开箱即用的解决方案可能很复杂并且不能立即清晰。 提高不同系统之间的灵活性和可移植性