V případě aktualizace CMDB čelíme výzvě dat přicházejících z mnoha zdrojů. Níže si ukážeme, jak k dané věci přistoupit z praktického pohledu.
V našem příkladě budeme pracovat s entitou serverů (Machine, OS server). V CMDB budeme chtít udržovat seznam všech serverů, protože jde o zásadní konfigurační položku. Jedná se ale o obecný přístup, který můžeme uplatnit při jakýchkoli aktualizacích dat.
V ideálním světě bychom zajistili jeden aktuální soubor, který bychom importovali a provedli následující:
- Založili nové záznamy pro servery, které se objevily v souboru, ale ještě nebyly v CMDB
- Aktualizovali hodnoty serverů, které byly v souboru i v CMDB
- Smazali záznamy serverů, které jsou v CMDB, ale nejsou v importním souboru.
Všechny tyto tři operace, lze jednoduše nastavit zaškrtnutím odpovídajících vlastností v definici importu. Importní soubor bychom získali použitím infrastrukturní funkce OG_Servers.
Ve skutečnosti tento scénář takto jednoduchý nebývá. Servery se nacházejí v různých sítích, u nichž nejsou nastaveny prostupy pro zajištění skenu infrastruktury. Můžeme používat více domén Active Directory, servery jsou v různých DMZ, vysoce zabezpečených segmentech, v cloudu nebo v sítích sesterských společností, do nichž nemáme vůbec přístup.
V takovém případě budeme mít pravděpodobně více vstupních souborů a u některých serverů se rozhodeme pro manuální aktualizaci dat.
Vytvoříme si proto více importů a v každém z nich nastavíme filtr okruhu záznamů, které budou aktualizovány. Pokud například víme, že v určitém souboru jsou všechny servery z testovací domény, nastavíme filtr importu na vlastnost serveru definující doménu a při vyhodocení, které servery mají být smazány, se vezmou v potaz pouze servery z této domény. Bez nastavení tohoto filtru by se smazaly všechny ostatní servery (i ty mimo testovací doménu), protože nebyly v importním souboru.
Automatické smazání serverů, které nebyly v importním souboru může být problematické, protože se může stát, že soubor není vyplněn správně z důvodu chyby ve skriptu nebo proto, že daný server neodpověděl na dotaz ohledně svoji konfigurace. V prvním případě můžeme využít nastavení importu, které import neprovede, pokud import obsahuje odchylku od očekávaného množství zázamů. Druhý typ problému je vhodné řešit spíše označením záznamů, které nebyly v posledním importu a uvedením data a času posledního importu, v němž byl server nalezen. Takto lze identifikovat záznamy, u kterých bychom měli ověřit, zda nemají být smazány.
Dalším vhodným prvkem je zavedení indikátoru, zda se daný server aktualizuje manuálně. O těchto serverech budeme vědět, že se v importech nikdy neobjeví, a budeme tedy muset zajistit jejich ruční aktualizaci.
Řešení problému importu z více zdrojů
Entitu serverů (nebo jinou entitu, kterou budeme chtít importovat) tedy rozšíříme o následující vlastnosti:
Kód |
Název |
Typ sloupce |
Popis |
manual_update |
Ruční aktualizace |
Ano/Ne |
Vlastnost je nastavována ručně. |
present_in_last_import |
Nalezen v posledním importu |
Ano/Ne |
Vlastnost nastavuje skript běžící po dokončení importu. Pro uživatele je pouze ke čtení. |
last_import_datetime |
Datum a čas posledního importu |
Datum a čas |
Vlastnost nastavuje skript běžící po dokončení importu. Pro uživatele je pouze ke čtení. |
Označení záznamů importem
Označení záznamů ve sloupcích present_in_last_import a last_import_datetime zajistí skript importu (záložka Spustit po dokončení importu):
/*u serverů, které byly v importním souboru (matchování sloupce třídy name a sloupce souboru Name) označit
pole present_in_last_import jako Ano (u ostatních serverů nastavit Ne). U těchto serverů z importního souboru
také nastavit last_import_datetime na aktuální datum a čas.*/
var cl = OG.ClassDef.GetById(OGActualImport.ClassDefId);
var colPres = cl.Columns['present_in_last_import'];
var colLast = cl.Columns['last_import_datetime'];
/* present_in_last_import = Ne */
var sql = 'update datarow' + cl.Id + ' set ' + colPres.DBColumnName + ' = 0' +
' where Id not in (select LastChildDataRowId from ' + OGActualImportDbTable + ' where IsError = 0)';
OG.Sql.RunSql(sql);
/* present_in_last_import = Ano, last_import_datetime = sysdate */
var sql = 'update datarow' + cl.Id +
' set ' + colPres.DBColumnName + ' = 1, ' + colLast.DBColumnName + ' = getdate() ' +
' where Id in (select LastChildDataRowId from ' + OGActualImportDbTable + ' where IsError = 0)';
OG.Sql.RunSql(sql);
Dotazy mapující kvalitu CMDB
Níže uvedené dva dotazy můžeme vložit do stránky mapující kvalitu dat v CMDB.
Dotaz pro identifikaci nově založených záznamů
SELECT m.name, d.Name AS Datasource, m.created, '53-' + convert( varchar, m.id) AS FullId
FROM {{:class.machine:}} m
INNER JOIN DataSource d ON m.createddatasourceid = d.id
WHERE d.referenceid IS NOT NULL and m.status IS NULL
Dotaz pro identifikaci záznamů, u nichž by mělo být prověřeno, zda nemají být smazány
SELECT m.name, m.created, m.last_import_datetime, '53-' + convert( varchar, m.id) AS FullId
FROM {{:class.machine:}} m
WHERE (m.present_in_last_import IS NULL OR m.present_in_last_import = 0) AND (m.manual_update IS NULL OR m.manual_update = 0) AND m.deleted IS NULL
Notifikace o nově založených serverech
Pokud budou identifikovány nové servery a založeny odpovídající záznamy v CMDB, budeme chtít odeslat notifikaci s uvedením serverů, které byly zřízeny.
Vytvoříme si notifikaci, kterou nastavíme k odeslání Po úspěšném spuštění importu.
V notifikaci na záložce Skript uvedeme následující kód.
var data = OG.GetItem('server-notif-data');
if ( OG.IsNull(data))
{
//nacist id datasource
var sql = OG.TextUtils.Format( "select max(id) from DataSource where ReferenceId = {0} and Name like 'Import {0}: %'", OGImport.Id);
var dsId = OG.Sql.RunScalarSql(sql);
//nacist z cl nove zaznamy - maji createddatasourceid, byly vytvoreny po ir.start
var drf = OG.DataRow.GetDataRowFilter(OGImport.ClassDefId);
drf['createddatasourceid'] = dsId;
drf.AddAndCon( OG.DataRow.CreateConLe(OGImport.ClassDef.Columns['created'], OGImportRun.DateTimeStart.AddMinutes(-1)));
//drf.WriteSqlToLog = true;
//projet a vytvorit odkazy na dr
data = 'V importu nebyl nalezen žádný nový server.';
var drl = OG.DataRow.GetDataByFilter(drf);
if ( drl != null && drl.Count > 0)
{
data = '';
for( var i = 0; i < drl.Count; ++i)
{
var dr = drl[i];
data += OG.TextUtils.Format( '<a href="{2}{1}">{0}</a><br />', dr.ShortDescriptionOrFullIdEnvelope, dr.DetailUrl, OG.GetWebUrl()); }
}
OG.SetItem('server-notif-data', data);
}
OGMessage.Body = OGMessage.Body.Replace( '#SERVERY#', data);
Výsledkem bude email se seznamem serverů, které se nově objevily v importu s proklikem z emailu na příslušný záznam v CMDB.