Feltételes konfigurációs adatok

Ha már vannak ilyen futásidőben kiszámított részeink a konfigurációsfájlban jön az ötlet, hogy hozzunk létre feltételes ágakat. Ez lehetővé tenné, hogy más adatok olvasódjanak be a fejlesztői környezetben és mások az „éles” rendszerben. Az alábbi PSD1 fájlban van két „Conditional” ág: a Conditional_3_Prod akkor érvényesül, ha a benne definiált feltétel (Condition) „igazra” értékelődik ki, ami jelen esetben akkor történik meg, ha a szkriptet a „ProdServer” nevű gépen futtatjuk. Ekkor a korábbi AccessToRestApi adatblokk felülbírálódik az új értékekkel, illetve a ScriptConfig-nak a textvalue adata is, valamint születne egy új adatblokk is, a UniqueToProd:

@{

    # This section is used by this specific script

    ScriptConfig = @{

        textvalue = "SomeText"

        date = {[datetime] "2022.12.01"}

        bool = $true

    }

 

    # This should be shared between other scripts

    AccessToRESTApi = @{

        AppID = 'd24099e5-10cb-4388-8ef4-f1c9f374d50b'

        Token = 'UG93ZXJTaGVsbElzR3JlYXQh'

        ApiURL = 'https://api.myapp.com/rest'

    }

 

    # This is a default setting for all scripts

    LogSettings = @{

        LogFolder = {join-path $PSScriptMyRoot Logs}

        subhive = @{

            subdynamicdata = {[math]::Sqrt(9)}

        }

    }

 

    Conditional_3_Prod = @{

        Condition = {$env:COMPUTERNAME -eq 'ProdServer'}

        AccessToRESTApi = @{

            AppID = 'd24099e5-10cb-4388-1111-f1c9f374d50b'

            Token = 'prodprodprod'

            ApiURL = 'https://apiprod.myapp.com/rest'

        }

 

        ScriptConfig = @{

            textvalue = "ProdText"

        }

 

        UniqueToProd = @{

            ProdValue = "This is the unique value"

        }

    }

 

    Conditional_2_PreProd = @{

        condition = {$true}

        ScriptConfig = @{

            textvalue = "PreProdText"

        }

    }

}

Felvettem még egy feltételes adatblokkot is abból a célból, hogy ezek kiértékelésének sorrendjét tudjam tesztelni. A sorrendiségüket a conditional_sorszám_név elnevezésükben a sorszám határozza meg.

Nézzük a továbbfejlesztett ParseConfig függvényt a példaszkriptben:

# This is a production script

 

#region Functions

function ParseConfig {

param(

    $path = "$($PSScriptFullPath).psd1"

)

    function ResolveDynamicData {

    param([hashtable] $confighive)

       

        foreach($key in $confighive.Clone().Keys){

            if($confighive.$key -is [hashtable]){

                ResolveDynamicData -confighive $confighive.$key

            }

            elseif($confighive.$key -is [scriptblock]){

                $confighive.$key = &(& $confighive.$key)

            }

        }

    }

 

    function MergeHives {

        param(

            [hashtable] $hive,

            [hashtable] $target

        )

 

        $hiveclone = $hive.Clone()

 

        foreach($h in $hiveclone.Getenumerator()){

            if($h.key -match '^Condition'){

                continue

            }

            elseif($h.value -isnot [hashtable] -or !$target.ContainsKey($h.key)){

                $target.($h.key) = $h.value

            }

            else{

                MergeHives -hive $h.value -target $target.($h.key)

            }

        }

    }

 

    $PSConfig = Import-PowerShellDataFile -Path $path

 

    ResolveDynamicData -confighive $PSConfig

 

    $PSConfigClone = $PSConfig.Clone()

 

    foreach($key in ($PSConfigClone.keys -match '^Conditional_' | Sort-Object)){

        if($PSConfigClone.$key.condition){

            MergeHives -hive $PSConfig.$key -target $PSConfig

        }

        $PSConfig.Remove($key)

    }

 

    $PSConfig

}

#endregion

 

#########################################################

#

# Body

#

#########################################################

 

$PSScriptFullPath = $myinvocation.mycommand.path

$PSScriptMyRoot   = $PSScriptRoot

$PSConfig = ParseConfig 

Lett egy új függvény: MergeHives. Ez fésüli össze majd azokat az adatblokkokat, amelyeket egy feltételes blokk érvényre jutásakor be kell illeszteni a konfigurációs hashtáblába. Ez a függvény két hashtábla paramétert vár, az egyik az az adatblokk, amit be kell fésülni ($hive), a másik, ahova az adatokat be kell tölteni ($target). Itt is klónozok, a $hiveclone ágain végig megyek. Ha az ág maga a feltétel (condition), az átlépem, hiszen arra már nincs szükségem mert ide már csak akkor jutok, ha a feltétel igazra értékelődött ki. Ha az ág nem hashtábla vagy a $target-ben még nincs meg az adott ág, akkor egyszerűen beteszem vagy felülírom a $target-be. Ha viszont az ág maga is egy hashtábla, akkor rekurzívan meghívom újra a MergeHives függvényt, immáron ennek az ágnak az adattartalmával és az egyel mélyebb célággal.

A ParseConfig további része most úgy néz ki, hogy szintén a PSD1 fájl importálásával kezdek, majd a szkriptblokkokat feloldom, majd klónozok és a klónban kikeresem az immár kiértékelt feltételes blokkokat a blokk nevének sorrendjében és amennyiben a feltétel igaz, akkor az összefűzéssel beleintegrálom az eredeti $PSConfig-ba.

Ellenőrizzük a működését, elsőként úgy, hogy egyik feltételes ág sem igaz:

PS C:\> . C:\PSTools\Section05-Video3Script.ps1

PS C:\> $PSConfig

 

Name                           Value

----                           -----

AccessToRESTApi                {AppID, Token, ApiURL}

LogSettings                    {subhive, LogFolder}

ScriptConfig                   {date, textvalue, bool}

 

PS C:\> $PSConfig.ScriptConfig.textvalue

SomeText

Ebben a változatban nincsen UniqueToProd adatblokk és a textvalue is az eredeti SomeText értéket tartalmazza.

Most beélesítem a Conditional_3_Prod ágat azzal, hogy a feltételébe egy $true-t teszek, nézzük, mi lesz most a $PSConfig:

PS C:\> . C:\PSTools\Section05-Video3Script.ps1

PS C:\> $PSConfig

 

Name                           Value

----                           -----

ScriptConfig                   {date, textvalue, bool}

LogSettings                    {subhive, LogFolder}

AccessToRESTApi                {AppID, Token, ApiURL}

UniqueToProd                   {ProdValue}

 

 

PS C:\> $PSConfig.ScriptConfig.textvalue

ProdText

Látható, hogy most már megjelent a UniqueProd ág és a textvalue is már ProdText lett. Ha most beélesítem a Conditional_2_PreProd részt is, akkor így alakul a végső konfiguráció:

PS C:\> $PSConfig

 

Name                           Value

----                           -----

ScriptConfig                   {date, textvalue, bool}

condition                      True

UniqueToProd                   {ProdValue}

AccessToRESTApi                {AppID, Token, ApiURL}

LogSettings                    {subhive, LogFolder}

 

 

PS C:\> $PSConfig.ScriptConfig.textvalue

ProdText

Egyelőre nem látunk változást, a textvalue még mindig ProdText, hiszen a Prod résznek van a legnagyobb sorszáma, így az ottani adatok értékelődnek ki legkésőbb, azaz azok felülírják a PreProd hatását. Viszont ha átírom a Prod rész sorszámát 1-re: Conditional_1_Prod, akkor már más lesz a helyzet:

PS C:\> . C:\PSTools\Section05-Video3Script.ps1

PS C:\> $PSConfig

 

Name                           Value

----                           -----

ScriptConfig                   {date, textvalue, bool}

UniqueToProd                   {ProdValue}

AccessToRESTApi                {AppID, Token, ApiURL}

LogSettings                    {subhive, LogFolder}

 

 

PS C:\> $PSConfig.ScriptConfig.textvalue

PreProdText



Word To HTML Converter