Backup VMWare ESXi Virtual Machines

This service performs a backup of ESXi virtual machines.

ToDo: Replace sshpass with different method. However, ESXi poses some problems to login via SSH keys.

Before running the script please execute commands manually to confirm SSH keys and to test.

The script requires a local installation of ovftool.

 

#!/usr/bin/perl

# -------------------------------------------------------------- # export-vms # Copyright 2009-2013 ]project-open[ # Frank Bergmann <frank.bergmann@project-open.com> # Licensed under GPL V2.0 or higher # -------------------------------------------------------------- # Parameters # my $debug = 1; # Show debug messages? my $real = 1; # Perform VM actions in real? my $esxi_host = "<server>"; # ESXi host (SSH enabled!) my $esxi_user = "root"; # ESXi user (should be root) my $esxi_pass = "<pass>"; # ESXi password my $esxi_compression = 5; # 1=fast, 9=slow but good compression my $exportdir = "/mnt/nas-backup/vmware"; # Where to store the backups my $logdir = "/var/log/backup"; # Where to keep the log? # Constants, no need to modify # my $ovftool = "/usr/lib/vmware-ovftool/ovftool"; my $esxi_vi = "vi://$esxi_user:$esxi_pass@$esxi_host"; print "export-vms: esxi_vi=$esxi_vi\n" if ($debug); my $time = `/bin/date +\%Y\%m\%d.\%H\%M`; chomp($time); my $weekday = `/bin/date +%w`; chomp($weekday); # ------------------------------------------------------------ # Procedures # ------------------------------------------------------------ sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } # Get the power status by a VM identified by a numeric ID sub get_power_state { my $vm_id = shift(); # Get power status my $cmd2 = "sshpass -p $esxi_pass ssh $esxi_user@$esxi_host vim-cmd vmsvc/power.getstate $vm_id |"; my $vm_state = "undefined"; open(VM_STATE, $cmd2); while (my $line = <VM_STATE>) { chomp($line); print "export-vms: line=$line\n" if ($debug > 1); if ($line =~ /Powered\s+(\S+)/) { $vm_state = $1; next; } if ($line =~ /Suspended/) { $vm_state = "suspended"; next; } } close(VM_STATE); print "export-vms: get_power_state: vm_id=$vm_id, vm_state=$vm_state\n" if ($debug > 2); return $vm_state } # Get the list of VMs together with their states # vim-cmd vmsvc/getallvms has sample output like this: # Vmid Name File Guest OS Version Annotation # 13 042.ws2008 [WD-Red2T] ws2008/ws2008.vmx windows7Server64Guest vmx-08 ]po[ testing @ Windows Server 2008 # 14 039.project-open-v50-stage [WD-Red2T] project-open-v50-stage/project-open-v50-stage.vmx rhel6_64Guest vmx-10 ]po[ installer test server # 38 031.gitlab [Samsug-850Pro] gitlab/gitlab.vmx ubuntu64Guest vmx-08 GitLab # sub get_power_states { my %hash=(); my $cmd = "sshpass -p $esxi_pass ssh $esxi_user@$esxi_host vim-cmd vmsvc/getallvms |"; print "export-vms: cmd=$cmd\n" if ($debug); open(VM_LINES, $cmd); while (my $vm_line=trim(<VM_LINES>)) { chomp($vm_line); next if ($vm =~ /Vmid/); print "export-vms: vm_line=$vm_line\n" if ($debug > 1); if ($vm_line =~ /^(\d+)\s+(\S+)\s+\[(\S+)\]\s+(\S+)\s+(\S+)\s+(.*)$/) { my $vm_id = $1; my $vm_name = $2; my $vm_datastore = $3; my $vm_folder = $4; my $vm_guestos = $5; my $vm_annotation = $6; # Get power status my $cmd2 = "sshpass -p $esxi_pass ssh $esxi_user@$esxi_host vim-cmd vmsvc/power.getstate $vm_id |"; my $vm_state = get_power_state($vm_id); $hash{$vm_name} = {id => $vm_id, name => $vm_name, datastore => $vm_datastore, folder => $vm_folder, guestos => $vm_guestos, annotation => $vm_annotation, state => $vm_state}; print "export-vms: vm_id=$vm_id, vm_name=$vm_name, vm_state=$vm_state\n" if ($debug); } } close(VM_LINES); return (%hash); } # ------------------------------------------------------------ # Backup VMs # ------------------------------------------------------------ my %hash = get_power_states(); print "export-vms: \n" if ($debug); print "export-vms: Starting Backup\n" if ($debug); print "export-vms: \n" if ($debug); while (my ($vm_name, $vm_hash) = each %hash) { my $vm_id = $hash{$vm_name}{id}; my $vm_state = $hash{$vm_name}{state}; print "export-vms: \n" if ($debug); print "export-vms: *** $vm_name ***\n" if ($debug); print "export-vms: \n" if ($debug); print "export-vms: vm_name=$vm_name, vm_id=$vm_id, vm_state=$vm_state\n" if ($debug); # Skip certain VMs if ($vm_name =~ /kassel/) { print "export-vms: vm_name=$vm_name: Skipping backup VM for selected VMs\n" if ($debug); next; } # Power off suspended machines, so we can take a backup... if (0 && $vm_state =~ /suspended/) { print "export-vms: vm_name=$vm_name, vm_state=$vm_state: Power off suspended VM to enable backup...\n" if ($debug); my $cmd4 = "sshpass -p $esxi_pass ssh $esxi_user@$esxi_host vim-cmd vmsvc/power.off $vm_id"; print "export-vms: $cmd4\n" if ($debug); system $cmd4 if ($real); }

# Create the actual backup my $cmd = "$ovftool -dm=thin --compress=$esxi_compression --powerOffSource $esxi_vi/$vm_name $exportdir/$esxi_host.$vm_name.$time.ova"; print "export-vms: $cmd\n" if ($debug); my $start = time; system $cmd if ($real); my $duration = time - $start; print "export-vms: executed in $duration\n" if ($debug); # Get current power status my $new_vm_state = get_power_state($vm_id); print "export-vms: vm_name=$vm_name, vm_id=$vm_id, new_vm_state=$new_vm_state\n" if ($debug); # Restart the VM if it was shutdown if ("off" eq $new_vm_state && "on" eq $vm_state) { my $cmd3 = "sshpass -p $esxi_pass ssh $esxi_user@$esxi_host vim-cmd vmsvc/power.on $vm_id"; print "export-vms: $cmd3\n" if ($debug); system $cmd3 if ($real); } } exit 0;  

 

  Contact Us
  Project Open Business Solutions S.L.

Calle Aprestadora 19, 12o-2a

E-08907 Hospitalet de Llobregat (Barcelona)

 Tel Europe: +34 932 202 088
 Tel US: +1 415 429 5995
 Mail: info@project-open.com