Clonage de machine virtuelle

De Wiki de Jordan LE NUFF
Sauter à la navigation Sauter à la recherche
(Page créée avec « ==Présentation== Cette page a pour objet de montrer comment cloner des machines virtuelles à partir de PowerCLI. ==Prérequis== *PowerShell ins… »)
 
 
(6 révisions intermédiaires par le même utilisateur non affichées)
Ligne 236 : Ligne 236 :
  
 
==Clonage multiple==
 
==Clonage multiple==
 +
===Prérequis===
 +
*Script <code>vmware_clone_VM.ps1</code> [[#Script|présenté plus haut]]
 +
*Fichier CSV contenant les informations nécessaires des machines à cloner
 +
 +
===Fichier CSV===
 +
Voici un exemple de fichier CSV nommé <code>vms_list_to_clone.csv</code> dont les champs sont séparés par des <code>;</code> :
 +
{{#get_file_data:
 +
file=vmlist
 +
|format=csv with header
 +
|data=VmSource=VmSource,VmHostnameSource=VmHostnameSource,IpSource=IpSource,GwSource=GwSource,VmTarget=VmTarget,IpTarget=IpTarget,GwTarget=GwTarget,ESX=ESX,Datastore=Datastore,Dossier=Dossier,VLAN=VLAN,Utilisateur=Utilisateur,Description=Description
 +
|delimiter=;
 +
}}
 +
{| class="wikitable"
 +
! VmSource
 +
! VmHostnameSource
 +
! IpSource
 +
! GwSource
 +
! VmTarget
 +
! IpTarget
 +
! GwTarget
 +
! ESX
 +
! Datastore
 +
! Dossier
 +
! VLAN
 +
! Utilisateur
 +
! Description {{#for_external_table:<nowiki/>
 +
{{!}}-
 +
{{!}} {{{VmSource}}}
 +
{{!}} {{{VmHostnameSource}}}
 +
{{!}} {{{IpSource}}}
 +
{{!}} {{{GwSource}}}
 +
{{!}} {{{VmTarget}}}
 +
{{!}} {{{IpTarget}}}
 +
{{!}} {{{GwTarget}}}
 +
{{!}} {{{ESX}}}
 +
{{!}} {{{Datastore}}}
 +
{{!}} {{{Dossier}}}
 +
{{!}} {{{VLAN}}}
 +
{{!}} {{{Utilisateur}}}
 +
{{!}} {{{Description}}}
 +
}}
 +
|}
 +
 +
===Script de clonage multiple===
 +
Voici un exemple de script de clonage multiple s'appuyant sur le script <code>vmware_clone_VM.ps1</code> [[#Script|présenté plus haut]], d'une part, et le fichier <code>vms_list_to_clone.csv</code>, d'autre part :
 +
<syntaxhighlight lang="powershell" line highlight="7,9,11,13,57,109-122,127">
 +
#!/usr/bin/pwsh
 +
 +
# Penser à utiliser le script create_credentials.ps1 pour créer les credentials
 +
 +
## Initialisation variables
 +
# Dossier des identifiants
 +
$CredsFileLocation="/data/scripts/.credentials"
 +
# Adresse du vCenter
 +
$UrlVcenter="myvcenter.mydomain.com"
 +
# Identifiant VMware à utiliser
 +
$VmwareUser="myaccount@mydomain.com"
 +
# Chemin du fichier CSV contenant les VMs à cloner
 +
$CsvVmsPath="/data/scripts/vms_list_to_clone.csv"
 +
 +
Import-Csv $CsvVmsPath -Delimiter ";"| Foreach-Object {
 +
 +
Write-Host $_.VmTarget
 +
 +
# VM d'origine
 +
$VmNameSource=$_.VmSource
 +
$VmHostnameSource=$_.VmHostnameSource
 +
$VmIpSource=$_.IpSource
 +
$VmGwSource=$_.GwSource
 +
 +
# VM cible
 +
$VmNameTarget=$_.VmTarget
 +
$VmIpTarget=$_.IpTarget
 +
$VmGwTarget=$_.GwTarget
 +
$VmHostTarget=$_.ESX
 +
$VmDatastoreTarget=$_.Datastore
 +
$VmLocationTarget=$_.Dossier
 +
$VmVlanNameTarget=$_.VLAN
 +
$VmDescriptionTarget=$_.Description
 +
 +
# Utilisateur à utiliser
 +
$VmUser=$_.Utilisateur
 +
$UserTemplate="root" # <== A variabiliser
 +
 +
# Construction des fichiers d'identifiants à utiliser
 +
$VcFileCreds=$($CredsFileLocation + "/" + $UrlVcenter + "_" + $VmwareUser + "_ps.xml")
 +
$VmFileCredsSource=$($CredsFileLocation + "/" + $VmHostnameSource + "_" + $VmUser + "_ps.xml")
 +
$FileCredsTemplate=$($CredsFileLocation + "/template_mysql_" + $UserTemplate + "_ps.xml")
 +
$VmFileCredsTarget=$($CredsFileLocation + "/" + $VmNameTarget + "_" + $VmUser + "_ps.xml")
 +
 +
# Importation des credentials
 +
$VcCreds=Import-Clixml -Path $VcFileCreds
 +
$VmCredsSource=Import-Clixml -Path $VmFileCredsSource
 +
$CredsTemplate=Import-Clixml -Path $FileCredsTemplate
 +
$VmCredsTarget=Import-Clixml -Path $VmFileCredsTarget
 +
 +
# Récupération en clair du mot de passe de l'utilisateur cible
 +
$PasswdTemplate=$CredsTemplate.GetNetworkCredential().Password
 +
$PasswdTarget=$VmCredsTarget.GetNetworkCredential().Password
 +
 +
## Pré-traitement
 +
# Clonage de la VM
 +
& /data/scripts/vmware_clone_VM.ps1 "$VmNameSource" $VmNameTarget -VmHostNameTarget $VmHostTarget -VmDatastoreNameTarget $VmDatastoreTarget -VmLocationTarget "$VmLocationTarget" -VmDescriptionTarget "$VmDescriptionTarget" -DeleteTarget Yes
 +
 +
## Connection au VCenter
 +
Connect-VIServer -Server $UrlVcenter -Credential $VcCreds | Out-Null
 +
 +
## Vérifications
 +
# La VM cible a-t-elle bien été créée ? Si non, fin du script
 +
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
 +
If (!$VmTarget){
 +
Write-Host "La VM cible $VmNameTarget n'existe pas. Fin du script."
 +
exit
 +
} ElseIf ($VmTarget.Count -gt 1) {
 +
Write-Host "La VM cible $VmNameTarget fournie existe plus d'une fois. VM cible ambigüe. Fin du script."
 +
exit
 +
}
 +
 +
# Le VLAN source est-il unique ? Si non, fin du script
 +
$VmSource=Get-VM -name "$VmNameSource" -ErrorAction SilentlyContinue
 +
$VmVlanSource=Get-VirtualPortGroup -VM $VmSource
 +
If (!$VmVlanSource){
 +
Write-Host "Il n'y a pas de VLAN source existant. Fin du script."
 +
exit
 +
} ElseIf ($VmVlanSource.Count -gt 1) {
 +
Write-Host "Il existe plus d'un VLAN source. VLAN source ambigu. Fin du script."
 +
exit
 +
}
 +
 +
# Le VLAN cible existe-t-il ? Si non, fin du script
 +
$VmVlanTarget=Get-VMHost -VM $VmTarget | Get-VirtualPortGroup -Name $VmVlanNameTarget
 +
If (!$VmVlanTarget){
 +
Write-Host "Le VLAN cible $VmVlanNameTarget n'existe pas. Fin du script."
 +
exit
 +
} ElseIf ($VmVlanTarget.Count -gt 1) {
 +
Write-Host "Le VLAN cible $VmVlanNameTarget fourni existe plus d'une fois. VLAN cible ambigu. Fin du script."
 +
exit
 +
}
 +
 +
## Traitement
 +
# Déconnection de la carte réseau
 +
$VmNicTarget=Get-NetworkAdapter -VM $VmTarget | Set-NetworkAdapter -StartConnected:$false –confirm:$false
 +
If (!$VmNicTarget){
 +
Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode déconnecté au démarrage. Fin du script."
 +
exit
 +
}
 +
 +
# Allumage de la VM cible
 +
If ($VmTarget.PowerState -eq 'PoweredOff') {
 +
Start-VM -VM $VmTarget –confirm:$false | Wait-Tools | Out-Null
 +
}
 +
 +
# Désactivation Zabbix, renommage des fichiers portant le nom de la machine, changement adresse IP, réinitialisation des clés SSH
 +
$script=@"
 +
systemctl enable zabbix-agent.service
 +
sleep 10
 +
export MYSQL_PWD=$PasswdTemplate
 +
mysql -uroot -e "ALTER USER 'pma_user'@'192.168.0.40' IDENTIFIED BY '$PasswdTarget';"
 +
mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$PasswdTarget';"
 +
systemctl stop mysqld
 +
sed -i -e 's/'$VmHostnameSource'/'$VmNameTarget'/g' /etc/hostname
 +
sed -i -e 's/'$VmHostnameSource'/'$VmNameTarget'/g' /etc/zabbix/zabbix_agentd.conf
 +
/usr/bin/sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/sysconfig/network-scripts/ifcfg-ens192
 +
/usr/bin/sed -i -e 's/'$VmGwSource'/'$VmGwTarget'/g' /etc/sysconfig/network-scripts/ifcfg-ens192
 +
rm -rf /etc/ssh/ssh_host_*
 +
ssh-keygen -A -q
 +
rm -f /root/.ssh/*rsa*
 +
>/root/.bash_history
 +
"@
 +
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
 +
 +
# Mise à jour du mot de passe
 +
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText "echo $PasswdTarget | passwd --stdin $VmUser" -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
 +
# Redémarrage de la machine cible
 +
Restart-VMGuest -VM $VmTarget | Wait-Tools | Out-Null
 +
 +
# Changement de VLAN de la carte réseau
 +
If ( $VmVlanSource -ne $VmVlanTarget ) {
 +
If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -Portgroup $VmVlanTarget –confirm:$false)) {
 +
Write-Host "Une erreur s'est produite lors du changement de VLAN de la carte réseau. Fin du script."
 +
exit
 +
}
 +
}
 +
 +
# Reconnection de la carte réseau
 +
If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -StartConnected:$true -Connected:$true –confirm:$false)) {
 +
Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode connecté en l'état et au démarrage. Fin du script."
 +
exit
 +
}
 +
Disconnect-VIServer -Confirm:$false
 +
}
 +
</syntaxhighlight>
 +
 +
<u>'''Explications des options :'''</u>
 +
*Ligne 7 :
 +
::Localisation du dossier contenant les identifiants précédemment créés avec le script [[Technique/PowerShell/Gérer_des_identifiants|create_credentials.ps1]]
 +
*Ligne 9 et 11 :
 +
::Adresse et identifiant du vCenter à utiliser
 +
*Ligne 13 :
 +
::Localisation du fichier CSV <code>vms_list_to_clone.csv</code> [[#Fichier CSV|précédemment créé]]
 +
*Ligne 57 :
 +
::Appel du script <code>vmware_clone_VM.ps1</code> précédemment présenté dans [[#Simple_clonage|la partie "Simple clonage" de cette page]].
 +
*Lignes 109 à 122 :
 +
::Script personnalisé contenant les commandes à passer sur la VM
 +
::En l'occurrence, dans cet exemple, les commandes font les actions suivantes :
 +
::*Activation du service de supervision Zabbix
 +
::*Attente que le serveur MySQL soit bien lancé
 +
::*Réinitialisation de mots de passe de certains utilisateurs MySQL
 +
::*Renommage de la machine
 +
::*Changement d'adresse IP
 +
::*Réinitialisation des clés SSH
 +
::*Suppression de l'historique des commandes de l'utilisateur utilisé pour passer les commandes (effacement des mots de passe en clair)
 +
*Ligne 127
 +
::Réinitialisation du mot de passe de l'administrateur de la machine virtuelle
 +
 +
==Rafraîchissement de machine==
 +
===Prérequis===
 +
*Script <code>vmware_clone_VM.ps1</code> [[#Script|présenté plus haut]]
 +
*La machine source et la machine à rafraîchir doivent exister au préalable
 +
 +
===Contexte===
 +
Ce script a été rédigé dans le but de cloner un serveur Jenkins sous OpenSUSE. Cela implique de désactiver les jobs.
 +
 +
Pour une autre utilisation, il faudra adapter la section dans laquelle sont rédigés les scripts qui sont transmis dans les VMs.
 +
 +
===Script de rafraîchissement===
 +
<syntaxhighlight lang="powershell">
 +
#!/usr/bin/pwsh
 +
 +
# Penser à utiliser le script create_credentials.ps1 pour créer les credentials
 +
 +
<#
 +
.SYNOPSIS
 +
    Script pour rafraîchir une VM depuis depuis une autre au travers du vCenter
 +
.DESCRIPTION
 +
    Au préalable, enregistrer les credentials en lançant le script create_credentials.ps1
 +
.PARAMETER VmNameSource
 +
    Le nom de la VM d'origine.
 +
Obligatoire
 +
.PARAMETER VmNameTarget
 +
    Le nom de la VM cible à rafraîchir.
 +
Obligatoire
 +
.EXAMPLE
 +
./vmware_refresh_VM.ps1 -VmNameSource myjenkins1 -VmNameTarget myjenkins2
 +
.NOTES
 +
    Author: LE NUFF Jordan
 +
    Date:  Feb 08, 2021
 +
#>
 +
 +
## Définition des paramètres d'entrée
 +
Param
 +
(
 +
[Parameter(Mandatory=$true, HelpMessage="Nom de la VM source")]
 +
[string]$VmNameSource,
 +
[Parameter(Mandatory=$true, HelpMessage="Nom de la VM cible")]
 +
[string]$VmNameTarget
 +
)
 +
If ($VmNameSource -eq $VmNameTarget) {
 +
Write-Host "La VM cible ne peut pas être la même que la VM source '$VmNameSource'. Fin du script."
 +
exit
 +
}
 +
 +
## Initialisation variables
 +
# Définition de la date
 +
$date=Get-Date -format "dd/MM/yyyy"
 +
# Dossier des identifiants
 +
$CredsFileLocation="/data/scripts/.credentials"
 +
# Adresse IP du vCenter
 +
$UrlVcenter="vcenter01.groupegdb.local"
 +
# Identifiant VMware à utiliser
 +
$VmwareUser="expl@groupegdb.local"
 +
$VmUserTarget="root"
 +
# Construction des fichiers d'identifiants à utiliser
 +
$VcFileCreds=$($CredsFileLocation + "/" + $UrlVcenter + "_" + $VmwareUser + "_ps.xml")
 +
$VmFileCredsSource=$($CredsFileLocation + "/" + $VmNameSource + "_" + $VmUserTarget + "_ps.xml")
 +
$VmFileCredsTarget=$($CredsFileLocation + "/" + $VmNameTarget + "_" + $VmUserTarget + "_ps.xml")
 +
# Importation des credentials
 +
$VcCreds=Import-Clixml -Path $VcFileCreds
 +
$VmCredsSource=Import-Clixml -Path $VmFileCredsSource
 +
$VmCredsTarget=Import-Clixml -Path $VmFileCredsTarget
 +
# Récupération en clair du mot de passe de l'utilisateur cible
 +
$PasswdTarget=$VmCredsTarget.GetNetworkCredential().Password
 +
 +
## Connection au VCenter
 +
Connect-VIServer -Server $UrlVcenter -Credential $VcCreds | Out-Null
 +
 +
# VM d'origine
 +
$VmSource=Get-VM -name $VmNameSource -ErrorAction SilentlyContinue
 +
$VmIpSource=$VmSource.Guest.IPAddress[0]
 +
$VmGwSource="$($VmSource.ExtensionData.Guest.IpStack.IpRouteConfig.IpRoute.Gateway.IpAddress)".Trim()
 +
$VmVlanSource=Get-VirtualPortGroup -VM $VmSource
 +
If (!$VmVlanSource){
 +
Write-Host "Il n'y a pas de VLAN source existant. Fin du script."
 +
exit
 +
} ElseIf ($VmVlanSource.Count -gt 1) {
 +
Write-Host "Il existe plus d'un VLAN source. VLAN source ambigu. Fin du script."
 +
exit
 +
}
 +
# VM cible
 +
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
 +
$VmLocationTarget=Get-Folder -Id $VmTarget.FolderId
 +
$VmIpTarget=$VmTarget.Guest.IPAddress[0]
 +
$VmGwTarget="$($VmTarget.ExtensionData.Guest.IpStack.IpRouteConfig.IpRoute.Gateway.IpAddress)".Trim()
 +
$VmVlanTarget=Get-VirtualPortGroup -VM $VmTarget
 +
If ($VmVlanSource.Count -gt 1) {
 +
Write-Host "Il existe plus d'un VLAN cible. VLAN cible ambigu. Fin du script."
 +
exit
 +
}
 +
$VmHostTarget=Get-VMhost -VM $VmTarget
 +
$VmDatastoreTarget=Get-Datastore -VM $VmTarget
 +
$VmDescriptionTarget="VM créée automatiquement par clonage de la VM $VmNameSource le $date"
 +
 +
# Clonage de la VM
 +
Write-Host "Lancement du clonage avec la commande suivante :"
 +
Write-Host "/data/scripts/vmware_clone_VM.ps1 $VmNameSource $VmNameTarget -VmHostNameTarget $VmHostTarget -VmLocationTarget `"$VmLocationTarget`" -VmDatastoreNameTarget $VmDatastoreTarget -VmDescriptionTarget `"$VmDescriptionTarget`" -DeleteTarget Yes"
 +
& /data/scripts/vmware_clone_VM.ps1 $VmNameSource $VmNameTarget -VmHostNameTarget $VmHostTarget -VmLocationTarget "$VmLocationTarget" -VmDatastoreNameTarget $VmDatastoreTarget -VmDescriptionTarget "$VmDescriptionTarget" -DeleteTarget Yes
 +
 +
## Vérifications
 +
# La VM cible a-t-elle bien été créée ? Si non, fin du script
 +
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
 +
If (!$VmTarget){
 +
Write-Host "La VM cible $VmNameTarget n'existe pas. Il y a eu un problème pendant le clonage. Fin du script."
 +
exit
 +
} ElseIf ($VmTarget.Count -gt 1) {
 +
Write-Host "La VM cible $VmNameTarget fournie existe plus d'une fois. Le clonage n'aurait pas dû avoir lieu. VM cible ambigüe. Fin du script."
 +
exit
 +
}
 +
 +
## Traitement
 +
# Déconnection de la carte réseau
 +
$VmNicTarget=Get-NetworkAdapter -VM $VmTarget | Set-NetworkAdapter -StartConnected:$false –confirm:$false
 +
If (!$VmNicTarget){
 +
Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode déconnecté au démarrage. Fin du script."
 +
exit
 +
}
 +
 +
# Allumage de la VM cible
 +
If ($VmTarget.PowerState -eq 'PoweredOff') {
 +
Start-VM -VM $VmTarget –confirm:$false | Wait-Tools | Out-Null
 +
}
 +
# Arrêt de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl stop jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Arrêt de Jenkins en cours."
 +
# Attente de l'arrêt complet de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactive' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
If ( $OutPut.ScriptOutput -eq '' )
 +
{
 +
$counter = 0
 +
do {
 +
Start-Sleep -s 1
 +
If ( $counter -ge 60 ) {
 +
Write-Host "Le service Jenkins n'est toujours pas arrêté après un délai de 60 secondes. Fin du script."
 +
exit
 +
}
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactiv' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
$counter++
 +
} until ( $OutPut.ScriptOutput -ne '' )
 +
} else {
 +
Write-Host "Jenkins arrêté."
 +
}
 +
# Sauvegarde de la configuration Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'cp /var/lib/jenkins/config.xml /var/lib/jenkins/config.xml_sav' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Sécurité de Jenkins désactivée."
 +
# Désactivation de la sécurité Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'sed -i -e "s@<useSecurity>true</useSecurity>@<useSecurity>false</useSecurity>@" /var/lib/jenkins/config.xml' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Sécurité de Jenkins désactivée."
 +
# Démarrage de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl start jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Démarrage de Jenkins en cours."
 +
# Attente du démarrage complet de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'wget --spider http://localhost:8080/jnlpJars/jenkins-cli.jar 2>&1 |grep -E "Le fichier distant existe|Remote file exists"' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
If ( $OutPut.ScriptOutput -eq '' )
 +
{
 +
$counter = 0
 +
do {
 +
Start-Sleep -s 1
 +
If ( $counter -ge 60 ) {
 +
Write-Host "Le service Jenkins n'est toujours pas démarré après un délai de 60 secondes. Fin du script."
 +
exit
 +
}
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'wget --spider http://localhost:8080/jnlpJars/jenkins-cli.jar 2>&1 |grep -E "Le fichier distant existe|Remote file exists"' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
$counter++
 +
} until ( $OutPut.ScriptOutput -ne '' )
 +
} else {
 +
Write-Host "Jenkins démarré."
 +
}
 +
# Création du script groovy pour désactiver tous les jobs Jenkins et lancement de ce dernier
 +
$script=@'
 +
export JENKINS_URL="http://localhost:8080"
 +
wget -q -O /root/jenkins-cli.jar $JENKINS_URL/jnlpJars/jenkins-cli.jar
 +
cat <<EOF > /root/jenkins_disable_all_jobs.groovy
 +
import jenkins.model.*
 +
 +
def pipelineJobsList = Jenkins.instance.getAllItems(org.jenkinsci.plugins.workflow.job.WorkflowJob.class)
 +
def projectsList = Jenkins.instance.getAllItems(hudson.model.AbstractProject.class)
 +
def multiBranchesProjectsList = Jenkins.instance.getAllItems(org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject)
 +
 +
def allJobsList = []
 +
allJobsList.addAll(pipelineJobsList)
 +
allJobsList.addAll(projectsList)
 +
allJobsList.addAll(multiBranchesProjectsList)
 +
 +
allJobsList.each {i ->
 +
  println(i.fullName + " is disabled ? " + i.isDisabled())
 +
  if (!i.isDisabled()) {
 +
    i.setDisabled(true)
 +
    i.save()
 +
    println(i.fullName + " is now disabled ? " + i.isDisabled())
 +
  }
 +
}
 +
EOF
 +
date >> /root/jenkins_disable_all_jobs.log
 +
ssh -l admin -p 8022 localhost groovy = < /root/jenkins_disable_all_jobs.groovy >> /root/jenkins_disable_all_jobs.log
 +
'@
 +
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
 +
Write-Host "Jobs Jenkins désactivés."
 +
# Arrêt de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl stop jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Arrêt de Jenkins en cours."
 +
# Attente de l'arrêt complet de Jenkins
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactive' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
If ( $OutPut.ScriptOutput -eq '' )
 +
{
 +
$counter = 0
 +
do {
 +
Start-Sleep -s 1
 +
If ( $counter -ge 60 ) {
 +
Write-Host "Le service Jenkins n'est toujours pas arrêté après un délai de 60 secondes. Fin du script."
 +
exit
 +
}
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactiv' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
$counter++
 +
} until ( $OutPut.ScriptOutput -ne '' )
 +
} else {
 +
Write-Host "Jenkins arrêté."
 +
}
 +
# Rétablissement de la sécurité Jenkins grâce à la restauration de l'ancien fichier de configuration
 +
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'mv /var/lib/jenkins/config.xml_sav /var/lib/jenkins/config.xml' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
 +
Write-Host "Sécurité de Jenkins rétablie."
 +
# Désactivation Zabbix, renommage des fichiers portant le nom de la machine, changement adresse IP, réinitialisation des clés SSH
 +
$script=@"
 +
sed -i -e 's/'$VmNameSource'/'$VmNameTarget'/g' /etc/hostname
 +
sed -i -e 's/'$VmNameSource'/'$VmNameTarget'/g' /etc/hosts
 +
sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/hosts
 +
sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/sysconfig/network/ifcfg-eth0
 +
sed -i -e 's/'$VmGwSource'/'$VmGwTarget'/g' /etc/sysconfig/network/ifroute-eth0
 +
rm -rf /etc/ssh/ssh_host_*
 +
ssh-keygen -A
 +
rm -f /root/.ssh/*rsa*
 +
>/root/.bash_history
 +
"@
 +
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
 +
Write-Host "Nom de machine et adresse IP modifiés, réinitialisation conf SSH et suppression informations sensibles effectuées."
 +
# Redémarrage de la machine cible
 +
Write-Host "Redémarrage de la machine $VmTarget en cours."
 +
Restart-VMGuest -VM $VmTarget | Wait-Tools | Out-Null
 +
# Changement de VLAN de la carte réseau
 +
If ( $VmVlanSource -ne $VmVlanTarget ) {
 +
If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -Portgroup $VmVlanTarget –confirm:$false)) {
 +
Write-Host "Une erreur s'est produite lors du changement de VLAN de la carte réseau. Fin du script."
 +
exit
 +
}
 +
Write-Host "Modification VLAN."
 +
}
 +
# Reconnection de la carte réseau
 +
If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -StartConnected:$true -Connected:$true –confirm:$false)) {
 +
Write-Host "Une erreur s'est produite lors de la configuration de la carte réseau en mode connecté en l'état et au démarrage. Fin du script."
 +
exit
 +
}
 +
Write-Host "Machine $VmTarget reconnectée au réseau et accessible."
 +
Write-Host "Refresh de la machine cible $VmTarget par clonage de la machine source $VmSource terminé."
 +
Disconnect-VIServer -Confirm:$false
 +
</syntaxhighlight>
 +
 +
===Utilisation===
 +
L'utilisation de ce script se fait de la façon suivante :
 +
./vmware_refresh_VM.ps1 [-VmNameSource] <string[]> [-VmNameTarget] <string[]>
 +
 +
Voici le détail des options :
 +
*<code>VmNameSource</code>
 +
::Le nom de la VM à cloner. (obligatoire)
 +
*<code>VmNameTarget</code>
 +
::Le nom de la VM cible à créer par clonage. (obligatoire)
 +
 +
===Limitations===
 +
A ce jour, ce script possède des limitations liées aux noms qui existent en double.
 +
 +
Cela concerne les objets suivants :
 +
*Machine Virtuelle
 +
::Deux machines virtuelles peuvent porter le même nom. En revanche, leurs ID seront différents. Ce script se basant sur le nom d'une machine virtuelle, il tombera en erreur et s'arrêtera en cas de machine non-unique.
 +
*VLAN
 +
::Si la machine source possède plus d'un VLAN, le script tombera en erreur.

Version actuelle datée du 11 février 2021 à 09:25

Présentation

Cette page a pour objet de montrer comment cloner des machines virtuelles à partir de PowerCLI.

Prérequis

Simple clonage

Script

Voici un script nommé vmware_clone_VM.ps1 qui permet de cloner une machine vers une autre :

#!/usr/bin/pwsh

# Penser à utiliser le script create_credentials.ps1 pour créer les credentials

<#
.SYNOPSIS
    Script pour exporter une VM depuis le vCenter
.DESCRIPTION
    Au préalable, enregistrer les credentials en lançant le script create_credentials.ps1
.PARAMETER VmNameSource
    Le nom de la VM à cloner. (obligatoire)
.PARAMETER VmNameTarget
    Le nom de la VM cible à créer par clonage. (obligatoire)
.PARAMETER VmHostNameTarget
    Le nom de l'ESXi qui hébergera la VM cible. (faculatif)
	Si absent, prendra la valeur de l'ESXi source.
.PARAMETER VmDatastoreNameTarget
    Le nom du datastore qui hébergera la VM cible. (faculatif)
	Si absent, prendra la valeur du datastore source.
	Si fourni, doit correspondre à un datastore de l'ESXi $VmHostNameTarget.
.PARAMETER VmLocationTarget
    Le dossier de VM dans lequel se trouvera la VM cible. (faculatif)
	Seul le nom du dossier sans son arborescence est attendu.
	Ainsi, si un nom de dossier existe plus d'une fois, le script s'arrêtera.
	Si absent, prendra la valeur du dossier de VM source.
.PARAMETER VmDescriptionTarget
    Description de la VM cible. (faculatif)
.PARAMETER DeleteTarget
    Confirmation de la suppression de la VM cible avant clonage si elle existe. (faculatif)
	Valeur possible : No ou Yes
	Si Yes, la VM cible est définitivement supprimée.
	Si No et si la VM cible n'existe pas, le script s'exécutera normalement et la VM cible sera créée.
	Si No et si la VM cible existe déjà, le script se terminera immédiatement sans réaliser le clonage.
.EXAMPLE
	./vmware_clone_VM.ps1 -DeleteTarget Yes myserver mybackupserver
.NOTES
    Author: LE NUFF Jordan
    Date:   Jan 11, 2021
#>

## Définition des paramètres d'entrée
Param
(
	[Parameter(Mandatory=$true, Position=0, HelpMessage="Nom de la VM source")]
	[string]$VmNameSource,
	[Parameter(Mandatory=$true, Position=1, HelpMessage="Nom de la VM cible")]
	[string]$VmNameTarget,
	[Parameter(Mandatory=$false, HelpMessage="ESXi cible")]
	[string]$VmHostNameTarget,
	[Parameter(Mandatory=$false, HelpMessage="Datastore cible")]
	[string]$VmDatastoreNameTarget,
	[Parameter(Mandatory=$false, HelpMessage="Dossier de VM cible")]
	[string]$VmLocationTarget,
	[Parameter(Mandatory=$false, HelpMessage="Description de VM cible")]
	[string]$VmDescriptionTarget="",
	[Parameter(Mandatory=$false, HelpMessage="Confirmation de la suppression de la VM cible : No ou Yes")]
	[ValidateSet('No','Yes')]
	[string]$DeleteTarget='No'
)
If ($VmNameSource -eq $VmNameTarget) {
	Write-Host "La VM cible ne peut pas être la même que la VM source '$VmNameSource'. Fin du script."
	exit
}

## Initialisation variables
# Dossier des identifiants
$CredsFileLocation="/data/scripts/.credentials"
# Adresse IP du vCenter
$UrlVcenter="vcenter01.groupegdb.local"
# Identifiant VMware à utiliser
$VmwareUser="expl@groupegdb.local"
# Construction du fichier d'identifiants à utiliser
$VcFileCreds=$($CredsFileLocation + "/" + $UrlVcenter + "_" + $VmwareUser + "_ps.xml")
# Importation des credentials
$VcCreds=Import-Clixml -Path $VcFileCreds

## Connection au VCenter
Connect-VIServer -Server $UrlVcenter -Credential $VcCreds | Out-Null

## Vérifications
# La VM source existe-t-elle ? Si non, fin du script
$VmSource=Get-VM -name $VmNameSource -ErrorAction SilentlyContinue
If (!$VmSource){
	Write-Host "La VM source $VmNameSource n'existe pas. Fin du script."
	exit
} ElseIf ($VmSource.Count -gt 1) {
	Write-Host "La VM source $VmNameSource fournie existe plus d'une fois. VM source ambigüe. Fin du script."
	exit
}
# La VM cible existe-t-elle ? Si oui et absence de la confirmation de la suppresion, fin du script
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
If ($VmTarget) {
	If ($VmTarget.Count -gt 1) {
		Write-Host "La VM cible $VmNameCible fournie existe plus d'une fois. VM cible ambigüe. Fin du script."
		exit
	} ElseIf ($DeleteTarget -eq 'No') {
		Write-Host "La VM cible $VmNameTarget existe et sa suppression n'a pas été confirmée en entrée de ce script avec l'option '-DeleteTarget Yes'. Fin du script."
		exit
	}
	If ( $VmTarget.PowerState -ne 'PoweredOff' ) 
	{
		$counter = 0
		Shutdown-VMGuest $VmNameTarget -confirm:$false | Out-Null
		do {
			Start-Sleep -s 1
			If ( $counter -ge 60 ) {
				Write-Host "La VM cible $VmNameTarget n'est toujours pas éteinte après un délai de 60 secondes. Fin du script."
				exit
			}
			$VmTarget = Get-VM $VmNameTarget
			$status = $VmTarget.PowerState
			$counter++
		} until ($status -eq "PoweredOff")
	}
}
# Si l'ESXi cible a été fourni, vérification de son existence
If ($VmHostNameTarget) {
	$VmHostTarget=Get-VMhost -Name $VmHostNameTarget -ErrorAction SilentlyContinue
	# Si inexistant, fin du script
	If (!$VmHostTarget){
		Write-Host "L'ESXi cible $VmHostNameTarget fourni n'existe pas. Fin du script."
		exit
	}
# Si l'ESXi n'a pas été fourni
} ElseIf (!$VmHostNameTarget) {
	# Utilisation du même ESXi que la VM source
	$VmHostTarget=Get-VMhost -VM $VmSource
}
# Si le datastore a été fourni, vérification de son existence
If ($VmDatastoreNameTarget) {
	$VmDatastoreTarget=Get-Datastore -Name $VmDatastoreNameTarget -ErrorAction SilentlyContinue
	# Si inexistant, fin du script
	If (!$VmDatastoreTarget){
		Write-Host "L'ESXi cible $VmDatastoreNameTarget fourni n'existe pas. Fin du script."
		exit
	# Si existant
	}
# Si le datastore n'a pas été fourni
} ElseIf (!$VmHostNameTarget) {
	# Utilisation du même ESXi que la VM source
	$VmDatastoreTarget=Get-Datastore -VM $VmSource
}
# Si le datastore cible n'est pas accessible depuis l'ESXi cible, fin du script
If (!$(Get-Datastore -VMHost $VmHostTarget | Where-Object {$_ -eq $VmDatastoreTarget})){
	Write-Host "Le datastore cible $VmDatastoreTarget n'est pas accessible depuis l'ESXi cible $VmHostTarget. Fin du script."
	exit
}
# Si le dossier de VM cible a été fourni, vérification de son existence
If ($VmLocationTarget) {
	$LocationTarget=Get-Folder -Name $VmLocationTarget -Type VM -ErrorAction SilentlyContinue
	# Si inexistant, fin du script
	If (!$LocationTarget){
		Write-Host "Le dossier de VM cible $VmLocationTarget fourni n'existe pas. Fin du script."
		exit
	} ElseIf ($LocationTarget.Count -gt 1) {
		Write-Host "Le dossier de VM cible $VmLocationTarget fourni existe plus d'une fois. Localisation cible ambigüe. Fin du script."
		exit
	}
# Si le dossier de VM cible n'a pas été fourni
} ElseIf (!$VmHostNameTarget) {
	# Utilisation du même dossier de VM que la VM source
	$LocationTarget=Get-Folder -Id $VmSource.FolderId
}

## Traitement
# Suppression de la VM cible
If ($VmTarget -And $DeleteTarget -eq 'Yes') {
	Write-Host "Suppression de la VM cible $VmTarget"
	Remove-VM -VM $VmTarget DeletePermanently confirm:$false
	Write-Host "La VM $VmTarget a été supprimée avec succès."
}
# Clonage de la machine
If (New-VM -Name $VmNameTarget -VM $VmSource -VMHost $VmHostTarget -Datastore $VmDatastoreTarget -Location $LocationTarget -Description $VmDescriptionTarget) {
	Write-Host "La VM $VmNameTarget a été clonée avec succès depuis la VM $VmSource. Fin du script."
} Else {
	Write-Host "Une erreur est survenue lors du clonage de la VM $VmNameTarget depuis la VM $VmSource Fin du script."
	exit
}

Disconnect-VIServer -Confirm:$false

Utilisation

L'utilisation de ce script se fait de la façon suivante :

./vmware_clone_VM.ps1 [-VmNameSource] <string[]> [-VmNameTarget] <string[]> [-VmHostNameTarget <String>] [-VmDatastoreNameTarget <String>] [-VmLocationTarget <String>] [-VmDescriptionTarget <String[""]>] [-DeleteTarget <String["No"|"Yes"]="No">]

Voici le détail des options :

  • VmNameSource
Le nom de la VM à cloner. (obligatoire)
  • VmNameTarget
Le nom de la VM cible à créer par clonage. (obligatoire)
  • VmHostNameTarget
Le nom de l'ESXi qui hébergera la VM cible. (faculatif)
Si absent, prendra la valeur de l'ESXi source.
  • VmDatastoreNameTarget
Le nom du datastore qui hébergera la VM cible. (faculatif)
Si absent, prendra la valeur du datastore source.
Si fourni, doit correspondre à un datastore de l'ESXi $VmHostNameTarget.
  • VmLocationTarget
Le dossier de VM dans lequel se trouvera la VM cible. (faculatif)
Seul le nom du dossier sans son arborescence est attendu.
Ainsi, si un nom de dossier existe plus d'une fois, le script s'arrêtera.
Si absent, prendra la valeur du dossier de VM source.
  • VmDescriptionTarget
Description de la VM cible. (faculatif)
  • DeleteTarget
Confirmation de la suppression de la VM cible avant clonage si elle existe. (faculatif)
Valeur possible : No ou Yes
Si Yes, la VM cible est définitivement supprimée.
Si No et si la VM cible n'existe pas, le script s'exécutera normalement et la VM cible sera créée.
Si No et si la VM cible existe déjà, le script se terminera immédiatement sans réaliser le clonage.

Limitations

A ce jour, ce script possède des limitations liées aux noms qui existent en double.

Cela concerne les objets suivants :

  • Machine Virtuelle
Deux machines virtuelles peuvent porter le même nom. En revanche, leurs ID seront différents. Ce script se basant sur le nom d'une machine virtuelle, il tombera en erreur et s'arrêtera en cas de machine non-unique.
  • Dossier de VM
Un dossier de VM est défini par
  • Un ID et nom
  • Un ID de parent
Ainsi, l'arborescence d'un dossier n'est pas inclus dans son nom. De ce fait, il n'est pas possible d'indiquer un chemin complet en entrée de ce script. De la même manière que pour les machines virtuelles, Deux dossiers de VM peuvent porter le même nom. Ainsi, le script tombera en erreur et s'arrêtera en cas de dossier de VM non-unique.

Clonage multiple

Prérequis

  • Script vmware_clone_VM.ps1 présenté plus haut
  • Fichier CSV contenant les informations nécessaires des machines à cloner

Fichier CSV

Voici un exemple de fichier CSV nommé vms_list_to_clone.csv dont les champs sont séparés par des ; : Le fichier vmlist est manquant.

VmSource VmHostnameSource IpSource GwSource VmTarget IpTarget GwTarget ESX Datastore Dossier VLAN Utilisateur Description

Script de clonage multiple

Voici un exemple de script de clonage multiple s'appuyant sur le script vmware_clone_VM.ps1 présenté plus haut, d'une part, et le fichier vms_list_to_clone.csv, d'autre part :

  1 #!/usr/bin/pwsh
  2 
  3 # Penser à utiliser le script create_credentials.ps1 pour créer les credentials
  4 
  5 ## Initialisation variables
  6 # Dossier des identifiants
  7 $CredsFileLocation="/data/scripts/.credentials"
  8 # Adresse du vCenter
  9 $UrlVcenter="myvcenter.mydomain.com"
 10 # Identifiant VMware à utiliser
 11 $VmwareUser="myaccount@mydomain.com"
 12 # Chemin du fichier CSV contenant les VMs à cloner
 13 $CsvVmsPath="/data/scripts/vms_list_to_clone.csv"
 14 
 15 Import-Csv $CsvVmsPath -Delimiter ";"| Foreach-Object { 
 16 
 17 	Write-Host $_.VmTarget
 18 
 19 	# VM d'origine
 20 	$VmNameSource=$_.VmSource
 21 	$VmHostnameSource=$_.VmHostnameSource
 22 	$VmIpSource=$_.IpSource
 23 	$VmGwSource=$_.GwSource
 24 
 25 	# VM cible
 26 	$VmNameTarget=$_.VmTarget
 27 	$VmIpTarget=$_.IpTarget
 28 	$VmGwTarget=$_.GwTarget
 29 	$VmHostTarget=$_.ESX
 30 	$VmDatastoreTarget=$_.Datastore
 31 	$VmLocationTarget=$_.Dossier
 32 	$VmVlanNameTarget=$_.VLAN
 33 	$VmDescriptionTarget=$_.Description
 34 
 35 	# Utilisateur à utiliser
 36 	$VmUser=$_.Utilisateur
 37 	$UserTemplate="root" # <== A variabiliser
 38 
 39 	# Construction des fichiers d'identifiants à utiliser
 40 	$VcFileCreds=$($CredsFileLocation + "/" + $UrlVcenter + "_" + $VmwareUser + "_ps.xml")
 41 	$VmFileCredsSource=$($CredsFileLocation + "/" + $VmHostnameSource + "_" + $VmUser + "_ps.xml")
 42 	$FileCredsTemplate=$($CredsFileLocation + "/template_mysql_" + $UserTemplate + "_ps.xml")
 43 	$VmFileCredsTarget=$($CredsFileLocation + "/" + $VmNameTarget + "_" + $VmUser + "_ps.xml")
 44 
 45 	# Importation des credentials
 46 	$VcCreds=Import-Clixml -Path $VcFileCreds
 47 	$VmCredsSource=Import-Clixml -Path $VmFileCredsSource
 48 	$CredsTemplate=Import-Clixml -Path $FileCredsTemplate
 49 	$VmCredsTarget=Import-Clixml -Path $VmFileCredsTarget
 50 
 51 	# Récupération en clair du mot de passe de l'utilisateur cible
 52 	$PasswdTemplate=$CredsTemplate.GetNetworkCredential().Password
 53 	$PasswdTarget=$VmCredsTarget.GetNetworkCredential().Password
 54 
 55 	## Pré-traitement
 56 	# Clonage de la VM
 57 	& /data/scripts/vmware_clone_VM.ps1 "$VmNameSource" $VmNameTarget -VmHostNameTarget $VmHostTarget -VmDatastoreNameTarget $VmDatastoreTarget -VmLocationTarget "$VmLocationTarget" -VmDescriptionTarget "$VmDescriptionTarget" -DeleteTarget Yes
 58 
 59 	## Connection au VCenter
 60 	Connect-VIServer -Server $UrlVcenter -Credential $VcCreds | Out-Null
 61 
 62 	## Vérifications
 63 	# La VM cible a-t-elle bien été créée ? Si non, fin du script
 64 	$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
 65 	If (!$VmTarget){
 66 		Write-Host "La VM cible $VmNameTarget n'existe pas. Fin du script."
 67 		exit
 68 	} ElseIf ($VmTarget.Count -gt 1) {
 69 		Write-Host "La VM cible $VmNameTarget fournie existe plus d'une fois. VM cible ambigüe. Fin du script."
 70 		exit
 71 	}
 72 
 73 	# Le VLAN source est-il unique ? Si non, fin du script
 74 	$VmSource=Get-VM -name "$VmNameSource" -ErrorAction SilentlyContinue
 75 	$VmVlanSource=Get-VirtualPortGroup -VM $VmSource
 76 	If (!$VmVlanSource){
 77 		Write-Host "Il n'y a pas de VLAN source existant. Fin du script."
 78 		exit
 79 	} ElseIf ($VmVlanSource.Count -gt 1) {
 80 		Write-Host "Il existe plus d'un VLAN source. VLAN source ambigu. Fin du script."
 81 		exit
 82 	}
 83 
 84 	# Le VLAN cible existe-t-il ? Si non, fin du script
 85 	$VmVlanTarget=Get-VMHost -VM $VmTarget | Get-VirtualPortGroup -Name $VmVlanNameTarget
 86 	If (!$VmVlanTarget){
 87 		Write-Host "Le VLAN cible $VmVlanNameTarget n'existe pas. Fin du script."
 88 		exit
 89 	} ElseIf ($VmVlanTarget.Count -gt 1) {
 90 		Write-Host "Le VLAN cible $VmVlanNameTarget fourni existe plus d'une fois. VLAN cible ambigu. Fin du script."
 91 		exit
 92 	}
 93 
 94 	## Traitement
 95 	# Déconnection de la carte réseau
 96 	$VmNicTarget=Get-NetworkAdapter -VM $VmTarget | Set-NetworkAdapter -StartConnected:$false confirm:$false
 97 	If (!$VmNicTarget){
 98 		Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode déconnecté au démarrage. Fin du script."
 99 		exit
100 	}
101 
102 	# Allumage de la VM cible
103 	If ($VmTarget.PowerState -eq 'PoweredOff') {
104 		Start-VM -VM $VmTarget confirm:$false | Wait-Tools | Out-Null
105 	}
106 
107 	# Désactivation Zabbix, renommage des fichiers portant le nom de la machine, changement adresse IP, réinitialisation des clés SSH
108 	$script=@"
109 systemctl enable zabbix-agent.service
110 sleep 10
111 export MYSQL_PWD=$PasswdTemplate
112 mysql -uroot -e "ALTER USER 'pma_user'@'192.168.0.40' IDENTIFIED BY '$PasswdTarget';"
113 mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$PasswdTarget';"
114 systemctl stop mysqld
115 sed -i -e 's/'$VmHostnameSource'/'$VmNameTarget'/g' /etc/hostname
116 sed -i -e 's/'$VmHostnameSource'/'$VmNameTarget'/g' /etc/zabbix/zabbix_agentd.conf
117 /usr/bin/sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/sysconfig/network-scripts/ifcfg-ens192
118 /usr/bin/sed -i -e 's/'$VmGwSource'/'$VmGwTarget'/g' /etc/sysconfig/network-scripts/ifcfg-ens192
119 rm -rf /etc/ssh/ssh_host_*
120 ssh-keygen -A -q
121 rm -f /root/.ssh/*rsa*
122 >/root/.bash_history
123 "@
124 	Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
125 
126 	# Mise à jour du mot de passe
127 	Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText "echo $PasswdTarget | passwd --stdin $VmUser" -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
128 
129 	# Redémarrage de la machine cible
130 	Restart-VMGuest -VM $VmTarget | Wait-Tools | Out-Null
131 
132 	# Changement de VLAN de la carte réseau
133 	If ( $VmVlanSource -ne $VmVlanTarget ) {
134 		If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -Portgroup $VmVlanTarget confirm:$false)) {
135 			Write-Host "Une erreur s'est produite lors du changement de VLAN de la carte réseau. Fin du script."
136 			exit
137 		}
138 	}
139 
140 	# Reconnection de la carte réseau
141 	If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -StartConnected:$true -Connected:$true confirm:$false)) {
142 		Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode connecté en l'état et au démarrage. Fin du script."
143 		exit
144 	}
145 	Disconnect-VIServer -Confirm:$false
146 }

Explications des options :

  • Ligne 7 :
Localisation du dossier contenant les identifiants précédemment créés avec le script create_credentials.ps1
  • Ligne 9 et 11 :
Adresse et identifiant du vCenter à utiliser
  • Ligne 13 :
Localisation du fichier CSV vms_list_to_clone.csv précédemment créé
  • Ligne 57 :
Appel du script vmware_clone_VM.ps1 précédemment présenté dans la partie "Simple clonage" de cette page.
  • Lignes 109 à 122 :
Script personnalisé contenant les commandes à passer sur la VM
En l'occurrence, dans cet exemple, les commandes font les actions suivantes :
  • Activation du service de supervision Zabbix
  • Attente que le serveur MySQL soit bien lancé
  • Réinitialisation de mots de passe de certains utilisateurs MySQL
  • Renommage de la machine
  • Changement d'adresse IP
  • Réinitialisation des clés SSH
  • Suppression de l'historique des commandes de l'utilisateur utilisé pour passer les commandes (effacement des mots de passe en clair)
  • Ligne 127
Réinitialisation du mot de passe de l'administrateur de la machine virtuelle

Rafraîchissement de machine

Prérequis

  • Script vmware_clone_VM.ps1 présenté plus haut
  • La machine source et la machine à rafraîchir doivent exister au préalable

Contexte

Ce script a été rédigé dans le but de cloner un serveur Jenkins sous OpenSUSE. Cela implique de désactiver les jobs.

Pour une autre utilisation, il faudra adapter la section dans laquelle sont rédigés les scripts qui sont transmis dans les VMs.

Script de rafraîchissement

#!/usr/bin/pwsh

# Penser à utiliser le script create_credentials.ps1 pour créer les credentials

<#
.SYNOPSIS
    Script pour rafraîchir une VM depuis depuis une autre au travers du vCenter
.DESCRIPTION
    Au préalable, enregistrer les credentials en lançant le script create_credentials.ps1
.PARAMETER VmNameSource
    Le nom de la VM d'origine.
	Obligatoire
.PARAMETER VmNameTarget
    Le nom de la VM cible à rafraîchir.
	Obligatoire
.EXAMPLE
	./vmware_refresh_VM.ps1 -VmNameSource myjenkins1 -VmNameTarget myjenkins2
.NOTES
    Author: LE NUFF Jordan
    Date:   Feb 08, 2021
#>

## Définition des paramètres d'entrée
Param
(
	[Parameter(Mandatory=$true, HelpMessage="Nom de la VM source")]
	[string]$VmNameSource,
	[Parameter(Mandatory=$true, HelpMessage="Nom de la VM cible")]
	[string]$VmNameTarget
)
If ($VmNameSource -eq $VmNameTarget) {
	Write-Host "La VM cible ne peut pas être la même que la VM source '$VmNameSource'. Fin du script."
	exit
}

## Initialisation variables
# Définition de la date
$date=Get-Date -format "dd/MM/yyyy"
# Dossier des identifiants
$CredsFileLocation="/data/scripts/.credentials"
# Adresse IP du vCenter
$UrlVcenter="vcenter01.groupegdb.local"
# Identifiant VMware à utiliser
$VmwareUser="expl@groupegdb.local"
$VmUserTarget="root"
# Construction des fichiers d'identifiants à utiliser
$VcFileCreds=$($CredsFileLocation + "/" + $UrlVcenter + "_" + $VmwareUser + "_ps.xml")
$VmFileCredsSource=$($CredsFileLocation + "/" + $VmNameSource + "_" + $VmUserTarget + "_ps.xml")
$VmFileCredsTarget=$($CredsFileLocation + "/" + $VmNameTarget + "_" + $VmUserTarget + "_ps.xml")
# Importation des credentials
$VcCreds=Import-Clixml -Path $VcFileCreds
$VmCredsSource=Import-Clixml -Path $VmFileCredsSource
$VmCredsTarget=Import-Clixml -Path $VmFileCredsTarget
# Récupération en clair du mot de passe de l'utilisateur cible
$PasswdTarget=$VmCredsTarget.GetNetworkCredential().Password

## Connection au VCenter
Connect-VIServer -Server $UrlVcenter -Credential $VcCreds | Out-Null

# VM d'origine
$VmSource=Get-VM -name $VmNameSource -ErrorAction SilentlyContinue
$VmIpSource=$VmSource.Guest.IPAddress[0]
$VmGwSource="$($VmSource.ExtensionData.Guest.IpStack.IpRouteConfig.IpRoute.Gateway.IpAddress)".Trim()
$VmVlanSource=Get-VirtualPortGroup -VM $VmSource
If (!$VmVlanSource){
	Write-Host "Il n'y a pas de VLAN source existant. Fin du script."
	exit
} ElseIf ($VmVlanSource.Count -gt 1) {
	Write-Host "Il existe plus d'un VLAN source. VLAN source ambigu. Fin du script."
	exit
}
# VM cible
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
$VmLocationTarget=Get-Folder -Id $VmTarget.FolderId
$VmIpTarget=$VmTarget.Guest.IPAddress[0]
$VmGwTarget="$($VmTarget.ExtensionData.Guest.IpStack.IpRouteConfig.IpRoute.Gateway.IpAddress)".Trim()
$VmVlanTarget=Get-VirtualPortGroup -VM $VmTarget
If ($VmVlanSource.Count -gt 1) {
	Write-Host "Il existe plus d'un VLAN cible. VLAN cible ambigu. Fin du script."
	exit
}
$VmHostTarget=Get-VMhost -VM $VmTarget
$VmDatastoreTarget=Get-Datastore -VM $VmTarget
$VmDescriptionTarget="VM créée automatiquement par clonage de la VM $VmNameSource le $date"

# Clonage de la VM
Write-Host "Lancement du clonage avec la commande suivante :"
Write-Host "/data/scripts/vmware_clone_VM.ps1 $VmNameSource $VmNameTarget -VmHostNameTarget $VmHostTarget -VmLocationTarget `"$VmLocationTarget`" -VmDatastoreNameTarget $VmDatastoreTarget -VmDescriptionTarget `"$VmDescriptionTarget`" -DeleteTarget Yes"
& /data/scripts/vmware_clone_VM.ps1 $VmNameSource $VmNameTarget -VmHostNameTarget $VmHostTarget -VmLocationTarget "$VmLocationTarget" -VmDatastoreNameTarget $VmDatastoreTarget -VmDescriptionTarget "$VmDescriptionTarget" -DeleteTarget Yes

## Vérifications
# La VM cible a-t-elle bien été créée ? Si non, fin du script
$VmTarget=Get-VM -name $VmNameTarget -ErrorAction SilentlyContinue
If (!$VmTarget){
	Write-Host "La VM cible $VmNameTarget n'existe pas. Il y a eu un problème pendant le clonage. Fin du script."
	exit
} ElseIf ($VmTarget.Count -gt 1) {
	Write-Host "La VM cible $VmNameTarget fournie existe plus d'une fois. Le clonage n'aurait pas dû avoir lieu. VM cible ambigüe. Fin du script."
	exit
}

## Traitement
# Déconnection de la carte réseau
$VmNicTarget=Get-NetworkAdapter -VM $VmTarget | Set-NetworkAdapter -StartConnected:$false confirm:$false
If (!$VmNicTarget){
	Write-Host "Une erreur s'est produite lors de la coniguration de la carte réseau en mode déconnecté au démarrage. Fin du script."
	exit
}

# Allumage de la VM cible
If ($VmTarget.PowerState -eq 'PoweredOff') {
	Start-VM -VM $VmTarget confirm:$false | Wait-Tools | Out-Null
}
# Arrêt de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl stop jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Arrêt de Jenkins en cours."
# Attente de l'arrêt complet de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactive' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
If ( $OutPut.ScriptOutput -eq '' ) 
{
	$counter = 0
	do {
		Start-Sleep -s 1
		If ( $counter -ge 60 ) {
			Write-Host "Le service Jenkins n'est toujours pas arrêté après un délai de 60 secondes. Fin du script."
			exit
		}
		$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactiv' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
		$counter++
	} until ( $OutPut.ScriptOutput -ne '' )
} else {
	Write-Host "Jenkins arrêté."
}
# Sauvegarde de la configuration Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'cp /var/lib/jenkins/config.xml /var/lib/jenkins/config.xml_sav' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Sécurité de Jenkins désactivée."
# Désactivation de la sécurité Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'sed -i -e "s@<useSecurity>true</useSecurity>@<useSecurity>false</useSecurity>@" /var/lib/jenkins/config.xml' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Sécurité de Jenkins désactivée."
# Démarrage de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl start jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Démarrage de Jenkins en cours."
# Attente du démarrage complet de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'wget --spider http://localhost:8080/jnlpJars/jenkins-cli.jar 2>&1 |grep -E "Le fichier distant existe|Remote file exists"' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
If ( $OutPut.ScriptOutput -eq '' ) 
{
	$counter = 0
	do {
		Start-Sleep -s 1
		If ( $counter -ge 60 ) {
			Write-Host "Le service Jenkins n'est toujours pas démarré après un délai de 60 secondes. Fin du script."
			exit
		}
		$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'wget --spider http://localhost:8080/jnlpJars/jenkins-cli.jar 2>&1 |grep -E "Le fichier distant existe|Remote file exists"' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
		$counter++
	} until ( $OutPut.ScriptOutput -ne '' )
} else {
	Write-Host "Jenkins démarré."
}
# Création du script groovy pour désactiver tous les jobs Jenkins et lancement de ce dernier
$script=@'
export JENKINS_URL="http://localhost:8080"
wget -q -O /root/jenkins-cli.jar $JENKINS_URL/jnlpJars/jenkins-cli.jar
cat <<EOF > /root/jenkins_disable_all_jobs.groovy
import jenkins.model.*

def pipelineJobsList = Jenkins.instance.getAllItems(org.jenkinsci.plugins.workflow.job.WorkflowJob.class)
def projectsList = Jenkins.instance.getAllItems(hudson.model.AbstractProject.class)
def multiBranchesProjectsList = Jenkins.instance.getAllItems(org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject)

def allJobsList = []
allJobsList.addAll(pipelineJobsList)
allJobsList.addAll(projectsList)
allJobsList.addAll(multiBranchesProjectsList)

allJobsList.each {i -> 
  println(i.fullName + " is disabled ? " + i.isDisabled())
  if (!i.isDisabled()) {
    i.setDisabled(true)
    i.save()
    println(i.fullName + " is now disabled ? " + i.isDisabled())
  }
}
EOF
date >> /root/jenkins_disable_all_jobs.log
ssh -l admin -p 8022 localhost groovy = < /root/jenkins_disable_all_jobs.groovy >> /root/jenkins_disable_all_jobs.log
'@
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
Write-Host "Jobs Jenkins désactivés."
# Arrêt de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl stop jenkins' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Arrêt de Jenkins en cours."
# Attente de l'arrêt complet de Jenkins
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactive' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
If ( $OutPut.ScriptOutput -eq '' ) 
{
	$counter = 0
	do {
		Start-Sleep -s 1
		If ( $counter -ge 60 ) {
			Write-Host "Le service Jenkins n'est toujours pas arrêté après un délai de 60 secondes. Fin du script."
			exit
		}
		$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'systemctl status jenkins|grep inactiv' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
		$counter++
	} until ( $OutPut.ScriptOutput -ne '' )
} else {
	Write-Host "Jenkins arrêté."
}
# Rétablissement de la sécurité Jenkins grâce à la restauration de l'ancien fichier de configuration
$OutPut=Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText 'mv /var/lib/jenkins/config.xml_sav /var/lib/jenkins/config.xml' -GuestCredential $VmCredsSource -ErrorAction SilentlyContinue
Write-Host "Sécurité de Jenkins rétablie."
# Désactivation Zabbix, renommage des fichiers portant le nom de la machine, changement adresse IP, réinitialisation des clés SSH
$script=@"
sed -i -e 's/'$VmNameSource'/'$VmNameTarget'/g' /etc/hostname
sed -i -e 's/'$VmNameSource'/'$VmNameTarget'/g' /etc/hosts
sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/hosts
sed -i -e 's/'$VmIpSource'/'$VmIpTarget'/g' /etc/sysconfig/network/ifcfg-eth0
sed -i -e 's/'$VmGwSource'/'$VmGwTarget'/g' /etc/sysconfig/network/ifroute-eth0
rm -rf /etc/ssh/ssh_host_*
ssh-keygen -A
rm -f /root/.ssh/*rsa*
>/root/.bash_history
"@
Invoke-VMScript -VM $VmTarget -ScriptType Bash -ScriptText $script -GuestCredential $VmCredsSource
Write-Host "Nom de machine et adresse IP modifiés, réinitialisation conf SSH et suppression informations sensibles effectuées."
# Redémarrage de la machine cible
Write-Host "Redémarrage de la machine $VmTarget en cours."
Restart-VMGuest -VM $VmTarget | Wait-Tools | Out-Null
# Changement de VLAN de la carte réseau
If ( $VmVlanSource -ne $VmVlanTarget ) {
	If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -Portgroup $VmVlanTarget confirm:$false)) {
		Write-Host "Une erreur s'est produite lors du changement de VLAN de la carte réseau. Fin du script."
		exit
	}
	Write-Host "Modification VLAN."
}
# Reconnection de la carte réseau
If (!$(Set-NetworkAdapter -NetworkAdapter $VmNicTarget -StartConnected:$true -Connected:$true confirm:$false)) {
	Write-Host "Une erreur s'est produite lors de la configuration de la carte réseau en mode connecté en l'état et au démarrage. Fin du script."
	exit
}
Write-Host "Machine $VmTarget reconnectée au réseau et accessible."
Write-Host "Refresh de la machine cible $VmTarget par clonage de la machine source $VmSource terminé."
Disconnect-VIServer -Confirm:$false

Utilisation

L'utilisation de ce script se fait de la façon suivante :

./vmware_refresh_VM.ps1 [-VmNameSource] <string[]> [-VmNameTarget] <string[]>

Voici le détail des options :

  • VmNameSource
Le nom de la VM à cloner. (obligatoire)
  • VmNameTarget
Le nom de la VM cible à créer par clonage. (obligatoire)

Limitations

A ce jour, ce script possède des limitations liées aux noms qui existent en double.

Cela concerne les objets suivants :

  • Machine Virtuelle
Deux machines virtuelles peuvent porter le même nom. En revanche, leurs ID seront différents. Ce script se basant sur le nom d'une machine virtuelle, il tombera en erreur et s'arrêtera en cas de machine non-unique.
  • VLAN
Si la machine source possède plus d'un VLAN, le script tombera en erreur.