1. Případová studie: Baseline záznamu - postup řešení

    Článek: AN0002414Aktualizováno:: 09.03.2020

    Vytvoření kopie třídy

    V naší původní třídě serverů (machine) budeme evidovat aktuální hodnoty. Schválené hodnoty (baseline) budeme evidovat v nové třídě. Tu jednoduše vytvoříme pomocí zkopírování třídy v detailu třídy Machine. Tato funkce vytvoří třídu stejné struktury, ale bez dat. Pravidla a tlačítka třídy jsou po zkopírování deaktivována, což nám vyhovuje. Pokud děláme kopii třídy, která má předka, což je i případ třídy machine, po zkopírování, tato třída žádného předka nemá. Pokud bychom tedy do baseline chtěli ukládat i hodnoty ze sloupců třídy předka, udělali bychom i kopii předka a obě zkopírované třídy propojili do hierarchie. Předkem třídy serverů je třída Konfiguračních položek, která ale neobsahuje položky, které by nás zajímali z pohledu baseline, takže toto nemusíme provádět.

    Zkopírovaná třída má nový kód, který si upravíme např. na machine_baseline. Změníme také název třídy, abychom ji odlišili od původní třídy serverů.

    Abychom věděli, který záznam baseline patří ke kterému záznamu třídy serverů, vytvoříme ve zkopírované třídě baseline sloupec id-original a budeme do něj ukládat Id třídy machine.

    Tlačítko pro přenos hodnot do třídy baseline

    Přenos dat do třídy baseline proběhne po stisknutí tlačítka administrátorem serverů. Ve třídě serverů tedy vytvoříme tlačítko, které budeme zobrazovat v detailu záznamu. Nastavíme jeho zobrazení pro role System administrator. Tlačítko se tak nebude zobrazovat rolím, které mají sice do třídy serverů také přístup, ale baseline by neměli určovat. Tlačítko bude typu Skript. Veškerý kód bychom mohli dát přímo do tlačítka, ale kvůli znovupoužitelnosti kódu, ho rozdělíme.

    Kód v tlačítku typu Skript:

    //#block baseline

    //ulozit zaznam
    if ( OGDataDetailForm.Save(false))
    {
    CreateCopyToBaseline( OGModel, OGDataParent, OGActualDataRowId, 'machine_baseline');
    OGForm.SetSuccess(OG.MessageLoc.GetText(OGModel.Id, 'ci_baseline_update'));
    }

    V tlačítku uvádíme blok skriptu baseline, s nímž budeme dále ve skriptu pracovat. Po stisku tlačítka záznam uložíme, zavoláme funkci CreateCopyToBaseline a nakonec zobrazíme hlášení o úspěšné aktualizaci baseline. Hlášení nebudeme zadávat natvrdo do kódu, ale vytvoříme si pro něj zvláštní objekt (menu Správa - Lokalizace - Hlášení). Výhodou bude, že stejné hlášení budeme moci použít u různých tříd, budeme ho moci aktualizovat na jednom místě a uživateli se zobrazí jazyková verze dle jeho nastavení.

    Funkci CreateCopyToBaseline vytvoříme v bloku skriptu. Pokud budeme mít víc tříd, ve kterých budeme udržovat baseline, v každé z nich použíjeme na tlačítku výše uvedený jednoduchý kód a vlastní logika kopírování baseline bude použita vždy jedna a ta samá.

    Kód v bloku skriptu baseline (v bloku skriptu je definována i funkce CheckDifferentData, kterou použijeme níže):

    function CreateCopyToBaseline( model, dataParent, actualDataRowId, classDefBLCode)
    {
    //Skript zkopíruje hodnoty záznamu ze třídy dataParent do odpovídajícího záznamu ve třídě classDefBLCode
    var clBL = model.ClassDefs[classDefBLCode];
    var dr = OG.DataRow.GetDataById(dataParent.Id, actualDataRowId);

    //nacist aktualni zaznam z baseline nebo vytvorit novy
    var f = OG.DataRow.GetDataRowFilter(clBL.Id);
    f['id-original'] = actualDataRowId;
    var drBLl = OG.DataRow.GetDataByFilter(f);
    var drBL = null;
    if ( drBLl.Count == 0)
    {
    drBL = OG.DataRow.CreateNew(clBL.Id);
    drBL['id-original'] = dr.Id;
    }
    else
    {
    drBL = drBLl[0];
    }

    //nakopirovat sloupce
    var colIds = clBL.Columns.GetIds();
    for( var i = 0; i < colIds.Count; ++i)
    {
    //najit sloupce v obou tridach
    var colBL = clBL.Columns.GetById(colIds[i]);
    var col = dataParent.Columns[colBL.Code];

    //jen pokud jsou oba sloupce a nejsou systemove
    if ( col != null && colBL != null && !col.IsSystemColumn)
    {
    drBL[colBL.Id] = dr[col];
    }
    }

    //ulozit
    OG.DataRow.SaveData(drBL);
    }

    function CheckDifferentData(columnCode, actualDataRow, dataRows)
    {
    //jen pro stavajici zaznam
    if ( actualDataRow['sourcetype'] == 1 && dataRows.Count == 2)
    {
    //najit druhy zaznam
    var drBS = ( dataRows[0]['sourcetype'] == 1 ? dataRows[1] : dataRows[0]);

    //porovnat hodnoty sloupce
    return actualDataRow[columnCode] != drBS[columnCode];
    }

    return false;
    }

    Dotaz porovnávající skutečné hodnoty ve třídě machine a schválené hodnoty ve třídě baseline

    V dotazu vybíráme hodnoty z obou tříd. V klauzuli SELECT máme typ záznamu (skutečné hodnoty nebo baseline), odkaz na záznam ve třídě machine a sloupce, které nás zajímají z pohledu baseline.

    SELECT 1 AS SourceType, 'cs-CZ::Stávající~en-US::Actual' AS Source, m.id AS machine___machine, m.[virtual-server-cpu] AS CPU, m.[virtual-server-ram] AS RAM, m.vcpu AS vCPU, m.vram AS vRAM, pc.name AS Patch_category, m.[dhcp-reservation] AS DHCP_reservation, m2.name AS Current_node, m3.name AS Failover_node
    FROM {{:class.machine:}} m
    LEFT JOIN {{:class.machine:}} m2 ON m.[current-node] = m2.id
    LEFT JOIN {{:class.machine:}} m3 ON m.[failover-node] = m3.id
    LEFT JOIN {{:class.patch-category:}} pc ON m.[patch-category] = pc.id
    WHERE m.deleted IS NULL

    UNION ALL

    SELECT 2, 'cs-CZ::Baseline~en-US::Baseline', mb.[id-original], mb.[virtual-server-cpu], mb.[virtual-server-ram], mb.vcpu, mb.vram, pc.name, mb.[dhcp-reservation], m2.name, m3.name
    FROM {{:class.machine_baseline:}} mb
    LEFT JOIN {{:class.machine:}} m2 ON mb.[current-node] = m2.id
    LEFT JOIN {{:class.machine:}} m3 ON mb.[failover-node] = m3.id
    LEFT JOIN {{:class.patch-category:}} pc ON mb.[patch-category] = pc.id
    WHERE mb.deleted IS NULL<-code>

    Master-detail relace ve třídě Machine

    Vytvoříme master-detail relaci na dotaz z předchozího bodu. Budeme zobrazovat typ záznamu (Stávající / Baseline) a hodnoty v polích, které chceme sledovat.

    Pravidla formátování v dotazu

    Pro každý sloupec, který v baseline sledujeme, vytvoříme v dotazu odpovídající pravidlo typu Nastavit formátování - Před zobrazením záznamu v seznamu. Níže uvedené pravidlo se týká sloupce cpu. V pravidle uvedeme do Skriptu pro podmínku následující kód (blok skriptu a funkci, kterou v něm voláme).

    //#block baseline
    //CheckDifferentData('cpu', OGActualDataRow, OGDataRows);

      //pouze záznamy pro aktuální záznam
      if ( OGActualDataRow['sourcetype'] == 1 && OGDataRows.Count == 2)
      {
        //fnajdi druhý záznam
        var drBS = ( OGDataRows[0]['sourcetype'] == 1 ? OGDataRows[1] : OGDataRows[0]);

        //porobnej hodnoty ve sloupcích
        var b = OGActualDataRow['cpu'] != drBS['cpu'];
        if (b)
        {
          //vytvoř a ulož objekt baselineChange s hodnotou true
          OG.SetItem( 'baselineChange', true);
        }

        return b;
      }

    return false;

    Dále v pravidle nastavíme např. barvu pozadí, která se bude aplikovat, pokud bude podmínka splněna.

    Text hlášení

    Opět vytvoříme hlášení v menu Správa - Lokalizace - Hlášení.

    Skript zobrazující hlášení na třídě

    Ve skriptu využíváme fakt, že pravidlo před zobrazováním záznamu běží před událostí OnPrerender. V pravidle si tedy můžeme vytvořit pomocí funkce OG.GetItem objekt baselineChange, který vložíme do stránky, a v detailu třídy ho pak načteme pomocí metody OG.SetItem. Pokud má objekt hodnotu true, zobrazíme hlášení.

    function OnPreRender()
    {
      //zkontrolovat, zda existuje odchylka od baseline
      if (OG.GetItem( 'baselineChange'))
      {
        OGForm.SetInfo(OG.MessageLoc.GetText(OGModel.Id, 'ci_baseline_deviation'));
      }
    };

×