...

вторник, 24 июня 2014 г.

Пишем скрипты для Cisco AXL

Фирма, в которой я работаю, для IP-телефонии использует в том числе и Cisco Unified Communications Manager (CUCM). В один прекрасный момент мне понадобилось автоматически отслеживать состояние телефонов — а именно, зарегистрированы ли они, находятся ли они в Hunt Group и т.п. Несколько часов усиленного гуглежа, собирание скудной информации по кусочкам, и начали появляться более-менее работоспособные скрипты. Ими я и поделюсь в этой статье. Версия моего CUCM — 7.1.5, IP-адрес предполагается 10.0.0.10. Скрипты будут на PHP, но можно запросто переписать на любой другой язык.



Первым делом, необходимо включить сервис AXL:

1. Переходим в раздел Cisco Unified Serviceability (справа вверху), затем переходим в Tools → Service Activation и включаем Cisco AXL Web Service.

2. Убеждаемся, что у нашего пользователя имеется роль Standard AXL API Access.

3. Проверить это можно, попробовав открыть страницу http://ift.tt/1wqOnS7. Если у вас откроется WSDL-документ (XML-документ, описывающий предоставляемые AXL функции), значит, всё хорошо и можно идти дальше.

getFunctions




Для взаимодействия с AXL воспользуемся языком PHP и стандартным классом SoapClient. Настроим клиент на вышеупомянутый URL и запросим список имеющихся функций с помощью стандартной функции __getFunctions():

$hostname = '10.0.0.10';
$client = new SoapClient("https://$hostname:8443/realtimeservice/services/RisPort?wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://$hostname:8443/realtimeservice/services/RisPort",
'login'=>'LOGIN',
'password'=>'PASSWORD',
));

$response = $client->__getFunctions();
print_r($response);




Получаем прототипы доступных функций:

[0] => list(SelectCmDeviceResult $SelectCmDeviceResult, string $StateInfo) SelectCmDevice(string $StateInfo, CmSelectionCriteria $CmSelectionCriteria)
[1] => list(string $StateInfo, SelectCtiItemResult $SelectCtiItemResult) SelectCtiItem(string $StateInfo, CtiSelectionCriteria $CtiSelectionCriteria)
[2] => ArrayOfColumnValues ExecuteCCMSQLStatement(string $ExecuteSQLInputData, ArrayOfGetColumns $GetColumns)
[3] => ArrayOfServerInfo GetServerInfo(ArrayOfHosts $Hosts)
[4] => list(SelectCmDeviceResultSIP $SelectCmDeviceResultSIP, string $StateInfo) SelectCmDeviceSIP(string $StateInfo, CmSelectionCriteriaSIP $CmSelectionCriteriaSIP)


getServerInfo




Самый простой прикладной запрос — информация о сервере:

// Здесь и далее описание SOAP-клиента будем опускать

$response = $client->getServerInfo();
print_r($response);




Результат:

[HostName] => CUCM1
[os-name] => VOS
[os-version] => 2.6.9-78.ELsmp
[os-arch] => i386
[java-runtime-version] => 1.6.0_24-b07
[java-vm-vendor] => Sun Microsystems Inc.
[call-manager-version] => 7.1.5.33900-10
[Active_Versions] => hwdata-0.146.33.EL-11 : ...


SelectCmDevice




Теперь займемся собственно телефонами. Для этого нужно составить SOAP-запрос. К примеру, мы хотим получить информацию о телефонах 501 и 502. Обратите внимание на индексы массива $items:

// Тут было описание SOAP-клиента

$items = array();
$items['SelectItem[0]']['Item'] = "501";
$items['SelectItem[1]']['Item'] = "502";

$response = $client->SelectCmDevice("", array(
"SelectBy" => "DirNumber", // тут можно указать "Name", тогда в массиве $items нужно указывать "SEPaabbccxxyyzz", и т.д.
"Status" => "Any",
"SelectItems" => $items
));

$devices = $response['SelectCmDeviceResult']->CmNodes[1]->CmDevices;
print_r($devices);




Результат


[0] => stdClass Object
(
[Name] => SEPAABBCC112233
[IpAddress] => 10.0.0.101
[DirNumber] => 501-Registered
[Class] => Phone
[Model] => 564
[Product] => 451
[BoxProduct] => 0
[Httpd] => Yes
[RegistrationAttempts] => 0
[IsCtiControllable] => 1
[LoginUserId] =>
[Status] => Registered
[StatusReason] => 0
[PerfMonObject] => 2
[DChannel] => 0
[Description] => 501 (Ivanov)
[H323Trunk] => stdClass Object
(
[ConfigName] =>
[TechPrefix] =>
[Zone] =>
[RemoteCmServer1] =>
[RemoteCmServer2] =>
[RemoteCmServer3] =>
[AltGkList] =>
[ActiveGk] =>
[CallSignalAddr] =>
[RasAddr] =>
)

[TimeStamp] => 1403127103
)

[1] => stdClass Object
(
[Name] => SEPAABBCC112234
[IpAddress] => 10.0.0.102
[DirNumber] => 502-Registered
[Class] => Phone
[Model] => 30016
[Product] => 30041
[BoxProduct] => 0
[Httpd] => Yes
[RegistrationAttempts] => 1
[IsCtiControllable] => 1
[LoginUserId] =>
[Status] => Registered
[StatusReason] => 0
[PerfMonObject] => 2
[DChannel] => 0
[Description] => 502 (Petrov)
[H323Trunk] => stdClass Object
(
[ConfigName] =>
[TechPrefix] =>
[Zone] =>
[RemoteCmServer1] =>
[RemoteCmServer2] =>
[RemoteCmServer3] =>
[AltGkList] =>
[ActiveGk] =>
[CallSignalAddr] =>
[RasAddr] =>
)

[TimeStamp] => 1403531108
)



PerfmonCollectCounterData




В следующем примере будем определять состояние телефонных линий — а именно, свободны ли линии. Если линия занята (т.е. происходит набор номера либо разговор), то значение равно 1. Если свободна — то 0. Для этого обращаемся к другому WSDL-документу:

$hostname = "10.0.0.10";
$client = new SoapClient("https://$hostname:8443/perfmonservice/services/PerfmonPort?wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://$hostname:8443/perfmonservice/services/PerfmonPort",
'login'=>'LOGIN',
'password'=>'PASSWORD',
));

$collection = "Cisco Lines";

$response = $client->PerfmonCollectCounterData($hostname, $collection);
print_r($response);




Результат


[0] => stdClass Object
(
[Name] => \\10.0.0.10\Cisco Lines(12345678-abcd-dead-beef-0987654321ff:501)\Active
[Value] => 0
[CStatus] => 1
)

[1] => stdClass Object
(
[Name] => \\10.0.0.10\Cisco Lines(12345678-abcd-dead-beef-0987654321ff:502)\Active
[Value] => 1
[CStatus] => 1
)





Тут мы обращаемся к коллекции «Cisco Lines», но можно запросить данные из других коллекций. Список коллекций можно получить с помощью такого запроса:

$response = $client->PerfmonListCounter($hostname);


ExecuteCCMSQLStatement




Я был немного удивлен, когда узнал, что CUCM поддерживает SQL-запросы к своим внутренним данным. В общем, это тоже возможно. Полный список таблиц можно получить, набрав такую команду в SSH-консоли CUCM:

admin: run sql select tabname from systables



Галопом по Европам, выполняем запрос, находятся ли телефоны в Hunt Group. Опять же, обратите внимание на структуру массива $items, это довольно неочевидно:

$hostname = '10.0.0.10';
$client = new SoapClient("https://$hostname:8443/realtimeservice/services/RisPort?wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://$hostname:8443/realtimeservice/services/RisPort",
'login'=>'LOGIN',
'password'=>'PASSWORD',
));

$items = array();
$items[] = array('Name'=>'hlog');
$items[] = array('Name'=>'description');

$response = $client->ExecuteCCMSQLStatement("SELECT h.hlog, d.description FROM device AS d INNER JOIN devicehlogdynamic AS h ON d.pkid = h.fkdevice", $items);
print_r($response);




Результат


[1] => stdClass Object
(
[Name] => description
[Value] => 501 (Ivanov)
)

[2] => stdClass Object
(
[Name] => hlog
[Value] => t
)

[3] => stdClass Object
(
[Name] => description
[Value] => 502 (Petrov)
)

[4] => stdClass Object
(
[Name] => hlog
[Value] => f
)





Таким образом, Иванов находится в Hunt Group (в пуле операторов), а Петров — нет.

Веб-приложение для мониторинга




Соединив все эти примеры, я получил вполне работоспособное веб-приложение, позволяющее наблюдать за состоянием пула операторов в реальном времени. Если вам интересно, то можно посмотреть исходники на моем GitHub. Любые пожелания и критика приветствуются.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий