framework/Resources/Scripts/new_client_cache.ps1

Param(
    [Parameter(Mandatory = $true)]
    [string]$EnvironmentName,

    [Parameter(Mandatory = $true)]
    [string]$CacheName,

    [Parameter(Mandatory = $true)]
    [string]$ClientCacheName,

    [string]$Server,

    [int]$Size = 1024,

    [int]$Port = 8250,

    [ValidateSet("Regular", "FullData")]
    [string]$Type = "Regular",
    
    [ValidateSet("LRU", "LFU", "Priority")]
    [string]$EvictionPolicy = "LRU",
    
    [int]$CleanInterval = 15,   # in seconds
    
    [pscredential]$Credentials,
    
    [ValidateRange(1, 100)]
    [int]$EvictionRatio = 5,
    
    [ValidateSet("Low", "BelowNormal", "Normal", "AboveNormal", "High")]
    [string]$DefaultPriority = "Normal",
    
    [switch]$InProc,
    [switch]$Optimistic,
    [switch]$DisableL2FallbackOnMiss,
    [switch]$FailQueryOnPartialDataset,
    [switch]$UpdateServerConfig,
    [string]$ClientNode,
    [string]$ConfigPath,

    [string]$ScriptsFolderPath = ".\Resources\Scripts"
)

. "$ScriptsFolderPath\Resources_Scripts\virtual_machine.ps1"
. "$ScriptsFolderPath\common.ps1"
function GetUploadedVmNames {
    param(
        [Parameter(Mandatory)][string]$ResourceGroup
    )
    return Get-AzVM -ResourceGroupName $ResourceGroup -ErrorAction Stop |
    Where-Object { $_.Tags.ContainsKey("InstallMode") -and $_.Tags["InstallMode"] -eq "server" } |
    Select-Object -ExpandProperty Name 
}

function Get-UploadedVmsWithPrivateIp {
    param(
        [Parameter(Mandatory)][string]$ResourceGroup
    )

    $vms = Get-AzVM -ResourceGroupName $ResourceGroup -ErrorAction Stop
    $vmDetails = @()

    foreach ($vm in $vms) {
        if (-not $vm.NetworkProfile -or -not $vm.NetworkProfile.NetworkInterfaces) {
            continue
        }

        $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id
        $nicName = ($nicId -split "/")[-1]
        $nic = Get-AzNetworkInterface -Name $nicName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue
        if (-not $nic) { continue }

        $privateIps = $nic.IpConfigurations | ForEach-Object { $_.PrivateIpAddress }

        $publicIpAddress = $null
        if ($nic.IpConfigurations.PublicIpAddress) {
            $pipId = $nic.IpConfigurations.PublicIpAddress.Id
            $pipName = ($pipId -split "/")[-1]
            $pip = Get-AzPublicIpAddress -Name $pipName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue
            $publicIpAddress = $pip.IpAddress
        }

        $details = [PSCustomObject]@{
            VmName        = $vm.Name
            ResourceGroup = $ResourceGroup
            Location      = $vm.Location
            VmSize        = $vm.HardwareProfile.VmSize
            PrivateIPs    = $privateIps
            PublicIP      = $publicIpAddress
        }

        $vmDetails += $details
    }

    return $vmDetails
}


function GetClientVMs {
    param(
        [Parameter(Mandatory)][string]$ResourceGroup
    )
    return Get-AzVM -ResourceGroupName $ResourceGroup -ErrorAction Stop |
    Where-Object { $_.Tags.ContainsKey("InstallMode") -and $_.Tags["InstallMode"] -eq "client" }
}

function Add-ClientCacheTags {
    param(
        [object]$Resource
    )
    
    $clientVMs = GetClientVMs -ResourceGroup $Resource.ResourceGroupName
    foreach ($vm in $clientVMs) {
        try {
            # Convert tags dictionary to hashtable
            $tags = @{}
            if ($vm.Tags) {
                foreach ($k in $vm.Tags.Keys) {
                    $tags[$k] = $vm.Tags[$k]
                }
            }

            # Update/add "ClientCaches" tag
            if ($tags.ContainsKey("ClientCaches")) {
                if ($tags["ClientCaches"] -notmatch "\b$ClientCacheName\b") {
                    $tags["ClientCaches"] = "$($tags["ClientCaches"]),$ClientCacheName"
                }
            }
            else {
                $tags["ClientCaches"] = $ClientCacheName
            }
            Set-AzResource -ResourceId $vm.Id -Tag $tags -Force -ErrorAction Stop | Out-Null
        }
        catch {
            Write-Output "Failed to update tags on $($vm.Name): $_"
        }
    }
}

function InvokeCommandOnServerWindows {
    param(
        [string]$ResourceGroupName,
        [string[]]$VmNames
    )
    if ([string]::IsNullOrWhiteSpace($Server)) {
        $vms = Get-UploadedVmsWithPrivateIp -ResourceGroup $ResourceGroupName
        
        if (-not $vms -or $vms.Count -eq 0) {
            throw "No VMs found with tag 'InstallMode=server' in resource group '$ResourceGroupName'."
        }

        $Server = $vms[0].PrivateIPs
    }
    $script = "New-ClientCache -CacheName $($cacheName) -ClientCacheName $($ClientCacheName) -Server $($Server)"
    
    if ($Size) { 
        $script += " -Size $($Size)" 
    }
    if ($Port) {
        $script += " -Port $($Port)" 
    }
    if ($Type) { 
        $script += " -Type $($Type)"
    }
    if ($EvictionPolicy) { 
        $script += " -EvictionPolicy $($EvictionPolicy)" 
    }
    if ($CleanInterval) {
        $script += " -CleanupInterval $($CleanInterval)"
    }
    if ($Credentials) { 
        $script += " -Credentials (New-Object System.Management.Automation.PSCredential('$($Credentials.UserName)', (ConvertTo-SecureString '$($Credentials.GetNetworkCredential().Password)' -AsPlainText -Force)))" 
    }
    if ($EvictionRatio) {
        $script += " -EvictionRatio $($EvictionRatio)" 
    }
    if ($DefaultPriority) {
        $script += " -DefaultPriority $($DefaultPriority)" 
    }
    if ($InProc) {
        $script += " -InProc" 
    }
    if ($Optimistic) { 
        $script += " -Optimistic"
    }
    if ($DisableL2FallbackOnMiss) {
        $script += " -DisableL2FallbackOnMiss"
    }
    if ($FailQueryOnPartialDataset) {
        $script += " -FailQueryOnPartialDataset" 
    }
    if ($UpdateServerConfig) {
        $script += " -UpdateServerConfig" 
    }
    if ($ClientNode) { 
        $script += " -ClientNode '$($ClientNode)'"
    }
    if ($ConfigPath) {
        if (Test-Path $ConfigPath) {

            # vmPath
            $vmPath = ".\config-temp.ncconf"

            # Load file content into a variable
            $configContent = Get-Content -Path $ConfigPath -Raw

            # Save it to config-temp.nconf
            $script = "Set-Content -Path $vmPath -Value `'$configContent`'; " + $script 

            # Prepend the -Path flag to the command
            $script = "$script -Path `"$vmPath`""

            # Clean up the temp file after execution
            $script += "; Remove-Item -Force $vmPath"
        }
        else {
            throw "The specified path '$ConfigPath' does not exist."
        }
    }
    # run this on only 1 VM, and this will be added on the server specified in -Server parameter
    $vm = $VmNames[0]
    $result = Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -VMName $vm -CommandId 'RunPowerShellScript' -ScriptString $script

    foreach ($val in $result.Value) {
        Write-Host $val.Message
    }

    return $result.Status
}

function InvokeCommandOnServerLinux {
    param(
        [string]$ResourceGroupName,
        [string[]]$VmNames
    )
    
    # run this on only 1 VM, and this will be added on the server specified in -Server parameter
    $vm = $VmNames[0]

    if ([string]::IsNullOrWhiteSpace($Server)) {
        $vms = Get-UploadedVmsWithPrivateIp -ResourceGroup $ResourceGroupName
        
        if (-not $vms -or $vms.Count -eq 0) {
            throw "No VMs found with tag 'InstallMode=server' in resource group '$ResourceGroupName'."
        }

        $Server = $vms[0].PrivateIPs
    }

    $NCachePath = Get-LinuxNCacheInstallDir -VMName $vm -ResourceGroupName $ResourceGroupName

    $script = "$NCachePath/bin/tools/new-clientcache -cachename $($cacheName) -clientcachename $($ClientCacheName) -server $($Server)"
    if ($Size) { 
        $script += " -size $($Size)"
    }
    if ($Port) {
        $script += " -port $($Port)"
    }
    if ($Type) { 
        $script += " -type $($Type)" 
    }
    if ($EvictionPolicy) { 
        $script += " -evictionpolicy $($EvictionPolicy)"
    }
    if ($CleanInterval) { 
        $script += " -cleanupinterval $($CleanInterval)"
    }
    if ($Credentials) { 
        $script += " -credentials (New-Object System.Management.Automation.PSCredential('$($Credentials.UserName)', (ConvertTo-SecureString '$($Credentials.GetNetworkCredential().Password)' -AsPlainText -Force)))"
    }
    if ($EvictionRatio) {
        $script += " -evictionratio $($EvictionRatio)"
    }
    if ($DefaultPriority) { 
        $script += " -defaultpriority $($DefaultPriority)"
    }
    if ($InProc) {
        $script += " -inproc" 
    }
    if ($Optimistic) {
        $script += " -optimistic"
    }
    if ($DisableL2FallbackOnMiss) { 
        $script += " -disablel2fallbackonmiss" 
    }
    if ($FailQueryOnPartialDataset) {
        $script += " -failqueryonpartialdataset"
    }
    if ($UpdateServerConfig) { 
        $script += " -updateserverconfig"
    }
    if ($ClientNode) {
        $script += " -clientnode '$($ClientNode)'"
    }
    if ($ConfigPath) {
        if (Test-Path $ConfigPath) {

            #vmPath
            $vmPath = "./config-temp.ncconf"
            # Load file content into a variable
            $configContent = Get-Content -Path $ConfigPath -Raw

            # (Optional) Save it to ./config.nconf if needed
            $script = "echo `'$configContent`' > $vmPath ;" + $script

            # Prepend the -Path flag to the command
            $script += " -path $vmPath"


            $script += "; rm -f $vmPath"
        }
        else {
            throw "The specified path '$ConfigPath' does not exist."
        }
    }
    $result = Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -VMName $vm -CommandId 'RunShellScript' -ScriptString $script

    foreach ($val in $result.Value) {
        Write-Host $val.Message
    }

    return $result.Status
}

function InvokeCommandOnVms {
    param(
        [object]$Resource,
        [string[]]$VmNames
    )

    $os = $Resource.Tags['OsType']
    if ($os -eq "Windows") {
        return InvokeCommandOnServerWindows -ResourceGroupName $resource.ResourceGroupName -VmNames $VmNames
    }
    else {
        return InvokeCommandOnServerLinux -ResourceGroupName $resource.ResourceGroupName -VmNames $VmNames
    }
}

function ExecuteCommands {
    $resource = Get-AzResourceGroup -ErrorAction Stop | Where-Object { $_.Tags -and $_.Tags.Contains("EnvironmentName") -and $_.Tags["EnvironmentName"] -eq $EnvironmentName }
    if (-not $resource) {
        throw "No such environment exists"
    }

    $vmNames = GetUploadedVmNames -ResourceGroup $resource.ResourceGroupName

    $status = InvokeCommandOnVms -Resource $resource -VmNames $vmNames

    if ($status -eq "Succeeded") {
        Add-ClientCacheTags -Resource $Resource
    }
}

try {
    ShowExecutingCommand
    if (-not (Get-AzContext)) {
        Connect-AzAccount
        if (Get-AzContext) {
            ExecuteCommands
        }
    }
    else {
        ExecuteCommands
    }
}
catch {
    Write-Error $($_.Exception.Message)
}