preloader
6 January 2011 / #Powercli

Reconfiguration des R.Pools

Suite à mon précédent post sur Mes R.Pools sont-ils bien configurés ?, voici l’ensemble de scripts et de tâche planifiée permettant de mettre en place une reconfiguration automatique de vos Resource Pool.

Un rapport sera envoyer à la fin du traitement s’il y a eu une modification du Resource Pool.

Un seuil minimal est défini pour éviter de reconfigurer le Resource Pool si la modification est mineure (variable modifiable).

La solution est composée de 2 scripts PowerCLI et d’une tâche planifiée Windows 2008 (format exportable XML)

Note : J’ai choisi de réaliser 2 scripts plutôt qu’un seul pour la seule raison que j’essaye au maximum de conserver une frontière entre scripts de ressources et scripts d’exécution (les scripts d’exécution faisant appel aux fonctions des scripts de ressources)

Cela me permet d’avoir un dossier nommé Repository qui contient tous mes scripts de ressources qui pourront être appelés.

Je reconnais que c’est mon choix, que chacun a ses habitudes et que chacun fait comme il l’entend, je voulais juste préciser mes raisons ^^

Tout d’abord, il y a le premier script (de ressources ^^) qui contient la définition du cmdlet Set-RPoolCustomShares

Function Set-RPoolCustomShares {
<#
.SYNOPSIS
    Set custom shares for resource pool
.DESCRIPTION
    Set "supposed to be" custom shares on
    a Production/Qualif Resource Pool
    environnement with High/Low type shares
.NOTES
    Authors:    www.cloudydude.fr
.PARAMETER ESXClus
    Name of Cluster to set.
    Cannot be null.
.EXAMPLE
    PS> Set-RPoolCustomShares -ESXClus "ESXClus01"
#>

    PARAM(
        [Parameter(Mandatory=$true,HelpMessage="Nom du Cluster ?")] [string] $ESXClus
    )

    BEGIN{
        # Pour eviter les retour en warning/error
        $ErrorActionPreference = "SilentlyContinue"
        $WarningPreference = "SilentlyContinue"

        If ((Get-PSSnapin -Name "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue | Measure-Object).count -eq 0) {
            Add-PSSnapin -Name "VMware.VimAutomation.Core"
        }
    }

    PROCESS{
        . "\\SERVEUR\C$\Scripts\Repository\vFunctions.ps1"
        ###
        # Based on the script found on http://www.yellow-bricks.com/2010/02/24/custom-shares-on-a-resource-pools-scripted/
        ###
        # Verification des arguments pour la recuperation de la liste de cluster
        $Cluster = Get-Cluster -Name $ESXClus
        if ($Cluster.count -eq 0) {
            Write-Host -ForegroundColor Red "Cluster" $ESXClus "non présent, vérifiez l'orthographe"
            Break
        }

        $Version = "1.0"
        $SMTPSRV = "smtp.cloudydude.fr"
        $EmailFrom = "expediteur@cloudydude.fr"
        $EmailTo = "destinataire@cloudydude.fr"

        $CPUSharesProd = 80 # Production = 80%
        $CPUSharesQualif = 20 # Qualifition = 20%
        $MemSharesProd = 80 # Production = 80%
        $MemSharesQualif = 20 # Qualifition = 20%
        $CPUSharesUpLimit = 8000 # Limite haute de shares CPU = High
        $MEMSharesUpLimit = 327680 # Limite haute de shares MEM = High
        $MinCPUShares = 100 # Limite basse de shares CPU
        $MinMemShares = 100 # Limite basse de shares MEM
        $Modification = $false
        $MinCPUModificationLimit = 200 # Limite basse de modification (en dessous, pas la modification)
        $MinMEMModificationLimit = 2000 # Limite basse de modification (en dessous, pas la modification)

        # Nomenclature fixe des Resource Pool
        $RP_Prod = "RP_"+$Cluster.Name+"_Prod"
        $RP_Qualif = "RP_"+$Cluster.Name+"_Qualif"

        # Reinitialisation des compteurs
        $NumvCPUsProd = 0
        $NumvCPUsQualif = 0
        $TotalMemoryProd = 0
        $TotalMemoryQualif = 0
        $MEMModificationProd = 0
        $CPUModificationProd = 0
        $MEMModificationQualif = 0
        $CPUModificationQualif = 0

        # Parcours du Resource Pool de Production
        $poolProd = Get-ResourcePool -Name $RP_Prod -location $Cluster.Name
        Foreach ($VM in ($poolProd |Get-VM | where {$_.PowerState -eq "PoweredOn"}) { # On ne prend que les VM allumées
            $NumvCPUsProd += ($VM).NumCpu
            $TotalMemoryProd += ($VM).MemoryMB
        }

        # Parcours du Resource Pool de Qualification
        $poolQualif = Get-ResourcePool -Name $RP_Qualif -location $Cluster.Name
        Foreach ($VM in ($poolQualif |Get-VM | where {$_.PowerState -eq "PoweredOn"}) { # On ne prend que les VM allumées
            $NumvCPUsQualif += ($VM).NumCpu
            $TotalMemoryQualif += ($VM).MemoryMB
        }

        # Calculs des shares en prennant compte du ratio Production/Qualification
        $MemSharesProd = $MemSharesProd * $TotalMemoryProd
        $MemSharesQualif = $MemSharesQualif * $TotalMemoryQualif
        $CPUSharesProd = $CPUSharesProd * $NumvCPUsProd
        $CPUSharesQualif = $CPUSharesQualif * $NumvCPUsQualif

        # Recuperation du maximum de shares entre Production/Qualification
        $MaxMemShares = [Math]::Max($MemSharesProd,$MemSharesQualif)
        $MaxCPUShares = [Math]::Max($CPUSharesProd,$CPUSharesQualif)

        if ($MaxCPUShares -gt 0) {
            # On souhaite utiliser la valeur max donnée en paramètre, on se base donc sur un coefficient
            $CPUShareMultiplier = $CPUSharesUpLimit / $MaxCPUShares
            # On utilise ce coefficient pour calculer les shares définitifs
            $CPUSharesProd = $CPUSharesProd * $CPUShareMultiplier
            $CPUSharesQualif = $CPUSharesQualif * $CPUShareMultiplier
        }

        # On utilise la valeur minimale si besoin
        if ($CPUSharesProd -lt $MinCPUShares) {$CPUSharesProd = $MinCPUShares}
        if ($CPUSharesQualif -lt $MinCPUShares) {$CPUSharesQualif = $MinCPUShares}

        if ($MaxMemShares -gt 0) {
            # On souhaite utiliser la valeur max donnée en paramètre, on se base donc sur un coefficient
            $MemShareMultiplier = $MEMSharesUpLimit / $MaxMemShares
            # On utilise ce coefficient pour calculer les shares définitifs
            $MemSharesProd = $MemSharesProd * $MemShareMultiplier
            $MemSharesQualif = $MemSharesQualif * $MemShareMultiplier
        }

        # On utilise la valeur minimale si besoin
        if ($MemSharesProd -lt $MinMemShares) {$MemSharesProd = $MinMemShares}
        if ($MemSharesQualif -lt $MinMemShares) {$MemSharesQualif = $MinMemShares}

        # Production
        $oldCpuSharesLevelProd = $poolProd.CpuSharesLevel
        $oldMemSharesLevelProd = $poolProd.MemSharesLevel
        $oldNumCpuSharesProd = $poolProd.NumCpuShares
        $oldNumMemSharesProd = $poolProd.NumMemShares
        $newNumCpuSharesProd = [System.Math]::Round($CPUSharesProd,0)
        $newNumMemSharesProd = [System.Math]::Round($MemSharesProd,0)

        # Qualification
        $oldCpuSharesLevelQualif = $poolQualif.CpuSharesLevel
        $oldMemSharesLevelQualif = $poolQualif.MemSharesLevel
        $oldNumCpuSharesQualif = $poolQualif.NumCpuShares
        $oldNumMemSharesQualif = $poolQualif.NumMemShares
        $newNumCpuSharesQualif = [System.Math]::Round($CPUSharesQualif,0)
        $newNumMemSharesQualif = [System.Math]::Round($MemSharesQualif,0)

        # EnTete du mail de rapport
        $MyReport = Get-CustomHTML "Cluster $Cluster"
        $MyReport += Get-CustomHeader "Informations Chassis"
        $MyReport += Get-HTMLDetail "vCPU Production:" $NumvCPUsProd
        $MyReport += Get-HTMLDetail "MEM Production:" $TotalMemoryProd
        $MyReport += Get-HTMLDetail "vCPU Qualification:" $NumvCPUsQualif
        $MyReport += Get-HTMLDetail "MEM Qualification:" $TotalMemoryQualif
        $MyReport += Get-CustomHeaderClose

        # Affichage des informations et reconfiguration des resource pool si besoin
        # Production
        $MEMModificationProd = [Math]::Abs($newNumMemSharesProd - $oldNumMemSharesProd)
        $CPUModificationProd = [Math]::Abs($newNumCpuSharesProd - $oldNumCpuSharesProd)
        if ( (($oldCpuSharesLevelProd -ne "Custom") `
                -Or ($oldMemSharesLevelProd -ne "Custom") `
                -Or ($newNumCpuSharesProd -ne $oldNumCpuSharesProd) `
                -Or ($newNumMemSharesProd -ne $oldNumMemSharesProd) `
            ) -And (($CPUModificationProd -gt $MinCPUModificationLimit) `
                -Or ($MEMModificationProd -gt $MinMEMModificationLimit) `
            )

 {
            $MyReport += Get-CustomHeader "Resource Pool Production (Ancienne conf | Nouvelle conf)"
            $MyReport += Get-HTMLDetail "CpuSharesLevel:" "$oldCpuSharesLevelProd | Custom"
            $MyReport += Get-HTMLDetail "MemSharesLevel:" "$oldMemSharesLevelProd | Custom"
            $MyReport += Get-HTMLDetail "NumCpuShares:" "$oldNumCpuSharesProd | $newNumCpuSharesProd"
            $MyReport += Get-HTMLDetail "NumMemShares:" "$oldNumMemSharesProd | $newNumMemSharesProd"
            $MyReport += Get-CustomHeaderClose
            $Modification = $true

            Set-Resourcepool -Resourcepool $poolProd -CPUsharesLevel Custom -NumCpuShares $newNumCpuSharesProd -MemSharesLevel Custom -NumMemShares $newNumMemSharesProd
        }

        # Qualification
        $MEMModificationQualif = 0
        $CPUModificationQualif = 0
        if ( ($oldCpuSharesLevelQualif -ne "Custom") `
                -Or ($oldMemSharesLevelQualif -ne "Custom") `
                -Or ($newNumCpuSharesQualif -ne $oldNumCpuSharesQualif) `
                -Or ($newNumMemSharesQualif -ne $oldNumMemSharesQualif) `
            ) -And (($CPUModificationQualif -gt $MinCPUModificationLimit) `
                -Or ($MEMModificationQualif -gt $MinMEMModificationLimit) `
            )

 {
            $MyReport += Get-CustomHeader "Resource Pool Qualification (Ancienne conf | Nouvelle conf)"
            $MyReport += Get-HTMLDetail "CpuSharesLevel:" "$oldCpuSharesLevelQualif | Custom"
            $MyReport += Get-HTMLDetail "MemSharesLevel:" "$oldMemSharesLevelQualif | Custom"
            $MyReport += Get-HTMLDetail "NumCpuShares:" "$oldNumCpuSharesQualif | $newNumCpuSharesQualif"
            $MyReport += Get-HTMLDetail "NumMemShares:" "$oldNumMemSharesQualif`| $newNumMemSharesQualif"
            $MyReport += Get-CustomHeaderClose
            $Modification = $true

            Set-Resourcepool -Resourcepool $poolQualif -CPUsharesLevel Custom -NumCpuShares $newNumCpuSharesQualif -MemSharesLevel Custom -NumMemShares $newNumMemSharesQualif
        }

        if ($Modification) {Send-SMTPmail $EmailTo $EmailFrom "[RPool] Modification de $Cluster" $SMTPSRV $MyReport}
    }
}

Edit : Ajout de la vérification du palier minima.

Ensuite, il y a le 2ème script (d’exécution :p) qui sera appelé par la tâche planifiée et qui utilise le cmdlet défini juste au dessus : Set-RPoolCustomShares

PARAM( [string] $ESXClus)

. "\\SERVEUR\C$\Scripts\Repository\Set-RPoolCustomShares.ps1"

If ((Get-PSSnapin -Name "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue | Measure-Object).count -eq 0) {
    Add-PSSnapin -Name "VMware.VimAutomation.Core"
}

$VISRV = "VCENTER"

$VIServer = Connect-VIServer $VISRV
If ($VIServer.IsConnected -ne $true) {
    # Fix for scheduled tasks not running.
    $USER = $env:username
    $APPPATH = "C:\Documents and Settings\" + $USER + "\Application Data"

    #SET THE APPDATA ENVIRONMENT WHEN NEEDED
    if ($env:appdata -eq $null -or $env:appdata -eq 0) {
        $env:appdata = $APPPATH
    }
    $VIServer = Connect-VIServer $VISRV
    If ($VIServer.IsConnected -ne $true) {
        Write $VIServer
        send-SMTPmail -to $EmailTo -from $EmailFrom -subject "ERROR: $VISRV RPool MGMT" -smtpserver $SMTPSRV -body "The Connect-VISERVER Cmdlet did not work, please check you VI Server."
        exit
    }
}

Set-RPoolCustomShares -ESXClus $ESXClus

$VIServer | Disconnect-VIServer -Confirm:$false

Pour finir, il y a la tâche planifiée au format exportable XML Windows 2008 (vous pouvez l’adapter et la réimporter) :

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.1" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Author>ammesiah</Author>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2011-01-10T12:00:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>CLOUDYDUDE\ammesiah</UserId>
      <LogonType>InteractiveTokenOrPassword</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <IdleSettings>
      <StopOnIdleEnd>false</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
    <Priority>5</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe</Command>
      <Arguments>-command "c:\Scripts\ResourcePoolManagement\ResourcePoolManagement.ps1 -ESXClus CLU01"</Arguments>
      <WorkingDirectory>C:\WINDOWS\system32\windowspowershell\v1.0\</WorkingDirectory>
    </Exec>
  </Actions>
</Task>

Au final, on obtient des Resource Pool bien configurés, une Qualification qui ne risque pas d’empiéter sur la Production, et un beau mail de rapport

RPoolConf01


> Frederic MARTIN