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