V této případové studii si popíšeme řešení zajišťující odeslání notifikací všem kontaktním osobám uvedeným u serverů, které jsou dotčené akcí zaznamenou do Provozního deníku.
Požadavky
Řešení má následujicí rysy:
Každý server může mít u sebe definováno N kontaktů - viz obrazovka níže.
V Provozním deníku popisujeme akci, která je plánována a která se může odkazovat na N serverů nebo skupin serverů. Příklad záznamu v Provozním deníku odkazujícím se na několik serverů a skupinu serverů je na obrázku níže.
Skupina serverů nám slouží jako množina obsahující definované servery. Pokud se změna týká všech serverů skupiny, můžeme jednoduše vybrat skupinu místo dohledávání všech jednotlivých serverů. Příklad skupiny serverů je níže.
Po vytvoření záznamu v Provozním deníku má dojít k odeslání emailů na všechny kontakty serverů uvedených v Provozním deníku přímo nebo v rámci jejich členství v uvedených skupinách serverů. Pokud se změna týká více serverů, u kterých je jako kontakt uveden ten samý uživatel, dostane daný uživatel pouze jeden email uvádějící všechny servery, kvůli nimž tento email dostal.
Příklad textu emailu vidíme na obrázku níže
V případě serverů, které fungují jako cluster, chceme poslat notifikace i kontaktům uvedeným u všech nódů, které jsou členy tohoto clusteru, a také všem virtuálním serverům nebo clusterovým službám běžícím na clusteru. Vztah clusteru, clusterových služeb, nódů a virtuálních serverů je vysvětlen v článku popisujícím typy serverů z pohledu Configuration management a zobrazuje ho i následující obrázek.
Řešení
Vztahy klíčových entit zachycuje následující Entity-relationship diagram.
Řešení spočívá v pouhých dvou objektech:
- pravidle Po uložení nového záznamu ve třídě Provozní deník (operations log), které zajistí prohledání kontaktů všech dotčených serverů a odeslání notifikací
- vlastní notifikaci, která definuje strukturu emailu
Pravidlo typu Skript volající notifikaci:
var clMachine = OGDataParent.Model.ClassDefs['machine'];
var clMachineGroup = OGDataParent.Model.ClassDefs['machine_group'];
//machines - pro kontrolu duplicitniho prochazeni
var idMachines = OG.CreateIntList();
//uzivatele - aby kazdy byl vlozen jen jednou
var htPersons = OG.CreateHashtable(); //key PersonId, value person
var htPersonsMachines = OG.CreateHashtable(); //key PersonId, value kolekce machines
var idPersons = OG.CreateIntList();
ProcessServers( OGActualDataRow.GetDR('ci'));
AddServers_MemberOf_VirtualOn();
SendEmails();
//-------------------------------------------------
function ProcessServers( drlCi)
{
if (!OG.IsNull(drlCi))
{
for( var i = 0; i < drlCi.Count; ++i)
{
var drCi = drlCi[i];
if ( drCi.ChildClassDefId == clMachine.Id)
{
var drMachine = OG.DataRow.GetDataById(clMachine.Id, drCi.ChildDataRowId);
ProcessMachine(drMachine);
}
else if ( drCi.ChildClassDefId == clMachineGroup.Id)
{
var drf = OG.DataRow.GetDataRowFilter(clMachine.Id);
drf['machine_group'] = drCi.ChildDataRowId;
var drlM = OG.DataRow.GetDataByFilter(drf);
for( i2 = 0; i2 < drlM.Count; ++i2)
{
ProcessMachine(drlM[i2]);
}
}
}
}
}
//najit servery, ktere odkazuji na idMachines ve sloupci member_of nebo virtual_on
function AddServers_MemberOf_VirtualOn()
{
var drf = OG.DataRow.GetDataRowFilter(clMachine.Id);
var sql = 'dr' + clMachine.Id + '.' + clMachine.Columns['member-of'].DBColumnName + ' in (' + OG.TextUtils.ConvertIntToSeparatedString(idMachines, ',', '') + ')';
var c1 = OG.DataRow.CreateConSql(sql);
sql = 'dr' + clMachine.Id + '.' + clMachine.Columns['virtual-on'].DBColumnName + ' in (' + OG.TextUtils.ConvertIntToSeparatedString(idMachines, ',', '') + ')';
var c2 = OG.DataRow.CreateConSql(sql);
drf.AddOrCon(c1, c2, true);
var drlM = OG.DataRow.GetDataByFilter(drf);
for( i2 = 0; i2 < drlM.Count; ++i2)
{
ProcessMachine(drlM[i2]);
}
}
//projit machine, jen pokud jiz nebyl prochazen
function ProcessMachine(drMachine)
{
//jen pokud server jeste nebyl zpracovan - aby se to nezacyklilo
if (!OG.IsNull(drMachine) && !idMachines.Contains(drMachine.Id))
{
idMachines.Add(drMachine.Id);
AddToPersonsToServer(drMachine['machine_contacts'], drMachine);
}
}
//projet osoby a ke kazde pridat machine
function AddToPersonsToServer(addPersons, drMachine)
{
if (!OG.IsNull(addPersons))
{
for( var i = 0; i < addPersons.Count; ++i)
{
var p = addPersons[i];
if (!idPersons.Contains(p.Id))
{
idPersons.Add(p.Id);
htPersons[p.Id] = p;
htPersonsMachines[p.Id] = OG.DataRow.CreateNewList();
}
htPersonsMachines[p.Id].Add(drMachine);
}
}
}
//odeslat emaily - kazdenu useru jen jeho servery
function SendEmails()
{
var nAll = OG.Notification.GetAll().GetByModelId( OGDataParent.Model.Id, false);
var n = nAll.GetDefaultByCode(OGDataParent.Model.Id, 'operations_log');
for( var i = 0; i < idPersons.Count; ++i)
{
var p = htPersons[idPersons[i]];
var machines = htPersonsMachines[idPersons[i]];
var machinesEI = machines.ToEntityInfoList();
machinesEI.SortByDisplayName();
//vytvorit email
var m = OG.Email.CreateMessage();
m.AddTo(p);
m.AssignEmailForDataRow = OGActualDataRow;
m.SendEmailAsOne = false; //odeslat kazdemu svuj email
var p2 = OG.Person.GetById(p.Id);
if ( OG.IsNull(p2.NotificationLanguageId))
{
m.Notification = n;
}
else
{
m.Notification = nAll.GetByCodeLanguage( 'operations_log', p2.NotificationLanguageId);
}
//vlozit servery
var ids = OG.CreateIntList();
var s = '';
for( im = 0; im < machinesEI.Count; ++im)
{
//kontrola aby byl server v seznamu jen jednou
if (!ids.Contains(machinesEI[im].Id))
{
ids.Add(machinesEI[im].Id);
if ( im > 0)
{
s += ', ';
}
s += machinesEI[im].DisplayName;
}
}
m.AddVariable( 'servers', s);
//odeslat email
OG.Email.Send(m);
}
}
Notifikace používaná skriptem: