Bug CBT – sauvegardes en danger !

Ces derniers jours, un vieux, vieux bug du Change Block Tracking a fait surface chez VMware. Il existerait depuis ESX 4.x ! Tout d’abord un rappel : CBT, c’est ce qui permet aux outils de backup image de ne sauvegarder que les blocs modifiés entre deux sauvegardes de VMs. Cette technologie est fournie par VMware et tous les éditeurs de sauvegarde à ma connaissance s’appuient dessus pour l’implémentation de leur solution.

Le problème est le suivant : pour toute VM avec CBT activé dont on aurait étendu les disques au-delà de 128 Go, 256 Go, 512 Go ou 1024 Go, les informations livrées par CBT seraient incohérentes et pourraient corrompre vos sauvegardes. Et ce, sans le moindre avertissement ou message d’erreur. Le pire scénario possible en somme…

Par exemple:

  • disque de 100 Go étendu de 30 Go = BUG (nous avons franchi les 128 Go).
  • disque de 30 Go étendu de 10 Go = pas de problème.
  • disque de 130 Go étendu de 20 Go = pas de problème.
  • disque de 250 Go étendu de 100 Go = BUG (nous avons franchi les 256 Go).
  • disque de 260 Go étendu de 150 Go = pas de problème.
  • création d’un nouveau disque de130 Go = pas de problème (seules les extensions posent problème).

Bien qu’il soit étonnant que le bug ait mis si longtemps être reconnu, c’est maintenant chose faite et on peut espérer un correctif rapidement. Toutefois, ce futur correctif ne réparera pas vos sauvegardes actuelles, qui resteront corrompues. Il faut donc traiter ce problème avec les moyens du bord.

La seule solution à l’heure actuelle est de réinitialiser CBT pour forcer une nouvelle sauvegarde complète. C’est simple et efficace mais pourrait générer un gros trafic de sauvegarde. Voyons comment procéder.

Identification des machines concernées

C’est loin d’être aussi simple que ça en a l’air, car rien dans les logs des machines virtuelles ne trace la taille des disques virtuels. Votre outil de monitoring pourrait peut-être vous fournir cette information. Dans le cas contraire, nous pouvons commencer par lister toutes les machines virtuelles qui ont un disque de taille supérieure à 128 Go. Pour cela je vous propose le script suivant.

# Variables
$vCenterName = "mon_vcenter"
$vCenterLogin = "mon_admin_vcenter"
$vCenterPassword = "mon_mdp_vcenter"
$HostList = @()
# taille de disque limite pour détecter les VM, en GB
$SizeLimit = 128

# script start
# Ajout des cmdlet powercli
$VMwareManagement = Get-PSSnapin | where {$_.name -match "VMware.VimAutomation.Core"}
if (!$VMwareManagement) {
Add-PSSnapin VMware.VimAutomation.Core
}

# récupération de la liste des VMs
Connect-VIServer -server $vCenterName -User $vCenterLogin -Password $vCenterPassword
$VMs = get-vm

# on recherche les VMs avec des disques de plus de 128 GB et on les ajoute à la liste
foreach ($VM in $VMs){
   $vmdks = $VM | get-harddisk
   foreach ($vmdk in $vmdks) {
       if ($vmdk -ne $null) {
        [INT]$vmdkSize = $vmdk.capacityKB/1MB
        if ($vmdkSize -gt $SizeLimit) {
            if ($HostList -notcontains $VM.Name) {
                $HostList += $VM.Name
                }            
            }
        }
   }
}

# AFfichage à l'écran
Write-Host Il y a $HostList.Count serveurs avec des disques plus gros que 128 Go :
$HostList | Sort-Object | Write-Host

# Export en csv (décommenter les deux lignes pour l'activer)
#$HostList = $HostList | Sort-Object
#$HostList -join "," >> c:\HostList.csv

Vous avez donc maintenant une liste des VMs qui pourraient être affectées par le bug (si leur disque a un jour été étendu au-delà des limites citées plus haut). A partir de là, vous avez deux possibilités :

  • Option 1 : analyser la liste pour identifier les VMs susceptibles d’avoir le problème et réinitialiser CBT pour ces machines uniquement.
    • Avantages:
      • Limiter le trafic de sauvegarde initial.
    • Inconvénients:
      • Risque d’erreur humaine (vous oubliez d’inclure un serveur qui a le bug).
  • Option 2 : réinitialiser CBT pour toutes ces VMs.
    • Avantages:
      • Pas besoin de réfléchir 🙂
      • Rapide.
    •  Inconvénients:
      • Vous allez sauvegarder en full des machines qui n’en n’ont pas besoin.

Traitons ces deux possibilités.

Réinitialisation de CBT au cas par cas

Si vous souhaitez éviter un gros pic de trafic lors de la sauvegarde, ou que vous êtes sûr d’identifier les VMs concernées, c’est la meilleure solution ! Voici un script qui peut vous aider. Il va vous demander le nom des VMs et désactiver CBT pour cette VM.

# Variables
$vCenterName = "mon_vcenter"
$vCenterLogin = "admin_vcenter"
$vCenterPassword = "mot-de-passe_vcenter"

# script start
# Ajout des cmdlet powercli
$VMwareManagement = Get-PSSnapin | where {$_.name -match "VMware.VimAutomation.Core"}
if (!$VMwareManagement) {
Add-PSSnapin VMware.VimAutomation.Core
}

# connexion au vCenter
Connect-VIServer -server $vCenterName -User $vCenterLogin -Password $vCenterPassword

# on fait une boucle pour pouvoir traiter plusieurs VMs à la suite
do {
    # on demande le nom de machine et on le vérifie
    do {$VMName = Read-Host 'Sur quelle machine voulez-vous réinitialiser CBT ?'}
    until (get-VM $VMName)

    # procédure de reset CBT
    $vm = get-vm $VMName
    if ($vm.ExtensionData.Config.ChangeTrackingEnabled -eq $true) {
        Write-Host "    CBT est activé pour $VMName. Nous allons le réinitialiser."
        $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
        $spec.ChangeTrackingEnabled = $false
        $vm.ExtensionData.ReconfigVM($spec)
        # la modif est appliquée par création et suppression d'un snapshot
        $snap=$vm | New-Snapshot -Name 'Disable CBT'
        $snap | Remove-Snapshot -confirm:$false
        # vérification que ça a marché
        $vm = get-vm $VMName
        if ($vm.ExtensionData.Config.ChangeTrackingEnabled -eq $true) {
            Write-Host -ForegroundColor Yellow "    Il y a eu une erreur; CBT n'a pas été réinitialisé."
            }
        else {
            Write-Host -ForegroundColor Green "    CBT a été réinitialisé avec succès."
            }
        }
    else {
        Write-Host "    CBT n'est pas activé pour $VMName. Aucune action n'est requise."
        }
$Repeat = Read-Host 'Voulez-vous configurer une autre machine ? (o/n)'
}
while ($Repeat -eq "o")

Une remarque: vous observerez qu’en réalité, nous désactivons CBT mais ne le réactivons pas. En effet, c’est l’outil de sauvegarde qui va réactiver CBT lors de la première sauvegarde.

Réinitialisation en masse de CBT

Dans ce scénario nous allons simplement réinitialiser CBT sur toutes les machines disposant d’un disque de taille supérieure à 128 Go. Vous allez sûrement agir sur des VMs ne présentant aucun risque de bug, mais au moins vous êtes sûr de ne pas en oublier ! Voici un script pour vous aider.

# Variables
$vCenterName = "mon_vcenter"
$vCenterLogin = "admin_vcenter"
$vCenterPassword = "mot-de-passe_vcenter"
$HostList = @()
# Size against the disks will be checked in GB
$SizeLimit = 128

# script start
# ajout des cmdlet powercli
$VMwareManagement = Get-PSSnapin | where {$_.name -match "VMware.VimAutomation.Core"}
if (!$VMwareManagement) {
Add-PSSnapin VMware.VimAutomation.Core
}

# on récupère la liste des VMs
Connect-VIServer -server $vCenterName -User $vCenterLogin -Password $vCenterPassword
$VMs = get-vm

# on établit la liste des VMs avec un disque plus grand que 128 Go (variable sizelimit)
foreach ($vm in $VMs){
   $vmdks = $vm | get-harddisk
   foreach ($vmdk in $vmdks) {
       if ($vmdk -ne $null) {
        [INT]$vmdkSize = $vmdk.capacityKB/1MB
        if ($vmdkSize -gt $SizeLimit) {
            if ($HostList -notcontains $VM.Name) {
                $HostList += $VM.Name
                }            
            }
        }
   }
}

# pour chaque serveur de la liste, on vérifie CBT et on le réinitialise si nécessaire
foreach ($esxname in $HostList) {
    $esx = get-vm $esxname
        # on vérifie si CBT est activé
        if ($esx.ExtensionData.Config.ChangeTrackingEnabled -eq $true) {
            Write-Host "    CBT est activé pour $esxname. Nous allons le réinitialiser."
            $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
            $spec.ChangeTrackingEnabled = $false
            $esx.ExtensionData.ReconfigVM($spec)
            #apply setting by creating and removing a snapshot
            $snap=$esx | New-Snapshot -Name 'Disable CBT'
            $snap | Remove-Snapshot -confirm:$false
            #check
            $esx = get-vm $esxname
            if ($esx.ExtensionData.Config.ChangeTrackingEnabled -eq $true) {
                Write-Host -ForegroundColor Yellow "    Erreur; CBT n'a pas pu être réinitialisé."
                }
            else {
                Write-Host -ForegroundColor Green "    CBT a été réinitialisé avec succès."
                }
            }
        else {
            Write-Host "    CBT n'est pas activé pour $esxname. Aucune action n'est requise."
            }
}
Write-Host "Opération terminée."

Et après ?

Une fois les VM concernées reconfigurées, la prochaine sauvegarde sera complète et va recréer une sauvegarde consistante. Les sauvegardes incrémentales suivantes, avec CBT réactivé, le seront aussi.

Cependant, si vous reproduisez le scénario conduisant au bug… vous l’aurez à nouveau ! Il faut donc rester vigilant et réinitialiser CBT si les disques sont étendus à l’avenir, aussi longtemps que le bug n’est pas corrigé.

Update 26/02/15: le bug est corrigé à partir de 5.0 patch 10, 5.1u3 et 5.5 patch 4, mais ne résoudra pas les inconsistances existantes. Il empêchera juste le problème de se produire dans les nouveaux cas. Pas de correction prévue pour ESX4!