Здравствуйте.
Подскажите пожалуйста, можно ли в iTop’e создать триггер на изменение объекта.
Например, я изменил версию у прикладного ПО, и тут сработал триггер, и уведомил заинтересованных лиц.
Очень надо. Помогите плиз
Вообще ни у кого нет идей?
Конечно есть, не только идеи, но и реализация)
У меня есть модуль, который добавляет новый триггер на обновление объекта. Сделать очень просто. Нужно расширить класс Trigger еще одним триггером TriggerOnObjectUpdate, а потом через один из интерфейсов API Extension, в котором есть функция OnUpdate, вызывать срабатывание триггера.
В конце недели буду рядом с компом, напишу подробнее. А может и модуль выложу.
Владимир, вы тут всех спасаете:)
С не терпением жду конца недели, чтобы узнать об этом триггере
Вот мой модуль (main.custom-trigger.php):
<?php
/**
* Module Custom Triggers
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class TriggerOnObjectUpdate extends TriggerOnObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_onobjupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
//MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class CustomTriggersPlugIn implements iApplicationObjectExtension
{
public function OnIsModified($oObject)
{
return false;
}
public function OnCheckToWrite($oObject)
{
return array();
}
public function OnCheckToDelete($oObject)
{
return array();
}
public function OnDBUpdate($oObject, $oChange = null)
{
// Activate existing on update trigger
$sClass = get_class($oObject);
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectUpdate AS t WHERE t.target_class IN ('$sClassList')"));
while ($oTrigger = $oSet->Fetch())
{
$oTrigger->DoActivate($oObject->ToArgs('this'));
}
}
public function OnDBInsert($oObject, $oChange = null)
{
}
public function OnDBDelete($oObject, $oChange = null)
{
}
}
?>
Сначала добавляется новый триггер TriggerOnObjectUpdate
, затем в методе OnDBUpdate
вызывается функция срабатывания этого триггера. Я почти уверен, что триггер можно добавить и через XML модель данных, как добавляются КЕ.
Этот модуль достаточно древний. Сейчас у триггеров в iTop есть дополнительное поле Фильтр, которое позволяет более точно ограничивать список объектов для срабатывания (например, по значению какого-то атрибута). Но это поле в моем модуле отсутсвует.
Ссылка на модуль в моём Dropbox. Используйте функцию “Скачать как ZIP-файл”.
Добрый день, Владимир.
Ссылку которую Вы приложили не открывается.
Скопировал приложенный вами скрипт в /var/www/itop/core/trigger.class.inc.php, сохранил. В itop’e в списке триггеров он появился, при создании нового задания(триггер&действия), происходит фатальная ошибка:
Ошибка: Failed to issue SQL query: query = INSERT INTO
priv_trigger_onobjupdate
(id
) VALUES (13), mysql_error = Table ‘zk_itop.priv_trigger_onobjupdate’ doesn’t exist, mysql_errno = 1146
Мне нужно таблицу данную создать, или перекомпилировать бд через тулкит?
А так: https://www.dropbox.com/s/mec44kdjar7cnpt/kunin-triggers.zip?dl=0
Это обычный модуль. Папку нужно поместить в /itop/extentions.
Кроме main.custom-trigger.php нужны остальные обязательные файлы модуля.
Владимир, так тоже не работает ссылка:(
с разных сетей пробовал
Беда какая-то. Отправил на почту.
Владимир, привет!
Триггер установил, спасибо!
Далее создал собственно триггер, и уведомления, а теперь возник новый вопрос, как указать, новые и предыдущие значения? Пытался проверить его в действии, изменил название сервера, но в уведомлении пришло предыдущее название, а не новое.
Вот тело моего письма:
<html>
<body>Обновлен объект <b> $this->name()$ </b><br>
Статус:$this->status$<br>
Серийный номер: $this->serialnumber$<br>
Бренд: $this->brand_name$<br>
Модель: $this->model_name$<br>
CPU: $this->cpu$<br>
RAM: $this->ram$<br>
<p>Описание:$this->description$</p>
<hr />
<p> Дополнительная информации по ссылке
$this->hyperlink()$</p>
</body>
</html>
Нашел в модели данных, не сколько атрибутов, косающихся класса CMDBChangeOp, но не знаю как ими правильно пользоваться. Пытался выводит по разному, не не работает
$this->oldvalue$
$this->name(oldvalue)$
$this->newvalue$
prevdata_name
Направление движения верное. Там не совсем очевидно всё с этими изменениями. Для каждого измененного поля создается свой объект изменения, наследующий от CMDBChangeOp. Класс объекта зависит от типа измененного атрибута (стока, число, ссылка и тд). Далее эти объекты выбираются, группируются и выводятся во вкладке История. Использовать их свойства напрямую в теле письма через плейсхолдеры не получится. $this ссылается на сам тикет, но не на CMDBChangeOp. Нужно думать какой-то костыль.
Нашел, что то типа:
SELECT CMDBChangeOp FROM CMDBChangeOp AS CMDBChangeOp WHERE ((`CMDBChangeOp`.`objkey` = :objkey) AND (`CMDBChangeOp`.`objclass` = :objclass))
выполняем запрос (Инструменты админа\выполнение запросов), он выполняется в таком виде, появляется табличка, где требуется указать значения, указываю значения objkey и objclass, и после выполнения запроса itop отваливается, просто висит белый экран в браузере
Замени соответствующую функцию в моем модуле вот на эту:
public function OnDBUpdate($oObject, $oChange = null)
{
// Activate existing on update trigger
$sClass = get_class($oObject);
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectUpdate AS t WHERE t.target_class IN ('$sClassList')"));
if ($oSet->Count() > 0)
{
$aContextArgs = $oObject->ToArgs('this');
if (is_object($oChange)) {
$aChangeLog = array();
$oFilter = new DBObjectSearch('CMDBChangeOp');
$oFilter->AddCondition('objkey', $oObject->GetKey(), '=');
$oFilter->AddCondition('objclass', $sClass, '=');
$oFilter->AddCondition('change', $oChange->GetKey(), '=');
$oChangeOpSet = new DBObjectSet($oFilter);
while($oChangeOp = $oChangeOpSet->Fetch()) {
$aChangelog[] = $oChangeOp->GetDescription();
$aContextArgs['change->userinfo'] = $oChangeOp->Get('userinfo');
$aContextArgs['change->date'] = $oChangeOp->Get('date');
}
$aContextArgs['change->log'] = strip_tags(implode(" ", $aChangelog));
$aContextArgs['change->html(log)'] = "<ul><li>".implode('</li><li>', $aChangelog)."</li></ul>";
}
while ($oTrigger = $oSet->Fetch())
{
$oTrigger->DoActivate($aContextArgs);
}
}
}
Теперь в тексте письма можно выводить изменения:
Дата $change->date$
2015-07-07 14:48:59
Пользователь $change->userinfo$
Владимир Кунин
Изменения строкой $change->log$
:
Дочерние запросы - добавлен объект R-000247. Дочерние запросы - удалён объект 4. В поле “Приоритет” установлено значение “Критический (1)” (предыдущее значение “Высокий (2)”). В поле “Срочность” установлено значение “Высокая” (предыдущее значение “Средняя”). В поле “Источник” установлено значение “Портал” (предыдущее значение “Телефон”). В поле “До выполнения” установлено значение “2015-02-25 19:55:11” (предыдущее значение “2015-02-26 11:55:11”). В поле “Родительский запрос” установлено значение “4” (предыдущее значение “R-000246”).
Изменения списком с html контентом $change->html(log)$
- Дочерние запросы - добавлен объект R-000247.
- Дочерние запросы - удалён объект 4.
- В поле “Приоритет” установлено значение “Критический (1)” (предыдущее значение “Высокий (2)”).
- В поле “Срочность” установлено значение “Высокая” (предыдущее значение “Средняя”).
- В поле “Источник” установлено значение “Портал” (предыдущее значение “Телефон”).
- В поле “До выполнения” установлено значение “2015-02-25 19:55:11” (предыдущее значение “2015-02-26 11:55:11”).
- В поле “Родительский запрос” установлено значение “4” (предыдущее значение “R-000246”).
Это такой же вывод, который используется во вкладке с историей. По отдельности выводить измененные поля не получится, поскольку заранее не известно, какие поля будут изменены, а содержимое письма статическое.
Владимир, это действительно работает!)
Спасибо большое!
Добрый день.
Не совсем пойму, подойдет ли этот модуль мне…
Вопрос: у меня синхронизируется Person из AD и мне нужно получать уведомления при изменении расположения у Person, только при этом изменении.
Нужно это для того, чтобы в том случае, когда сотрудник переезжает в другой кабинет, я узнал об этом по уведомлению, чтобы в дальнейшем сменить расположение привязанных к нему КЕ.
Это реально?
Получилось сделать вот такой фильтр:
SELECT Person AS p JOIN CMDBChangeOpSetAttributeScalar AS ch ON ch.objkey = p.id WHERE ch.attcode='location_id' AND ch.date > DATE_SUB(NOW() , INTERVAL 20 SECOND) AND ch.oldvalue NOT LIKE '0'
Запрос показывает person, у которого изменилось расположение за последние 20 секунд, при условии, что предыдущее расположение не было пустым.
Но как теперь сделать, чтобы срабатывал триггер?
@infalex, ниже по ссылке обновленный модуль. В нем можно указать, при изменении каких полей объекта должен срабатывать триггер.
Большое спасибо, работает отлично.