8 Replies Latest reply on Oct 8, 2009 6:59 AM by bcnx

    Linux LVM Snapshot VM Backup Script

    bradsjm Novice

      I thought it might be useful to someone so I'm posting the perl script I use to do daily backups of my Virtual Machines.

       

      The script handles running machines by suspending them, taking an LVM snapshot, then resuming the VM and doing a backup of the snapshot. This gives me a window of less than 60 seconds of downtime per running virtual machine. You will need to customize this to your own LVM volume names, paths, etc.

       

       

      Note: The editor seems to modify the text so I have attached the script.

       

       

      #!/usr/bin/perl -w

      #

       

       

      1. VM Server Virtual Machine Snapshot Backups

      #

       

      use VMware::VmPerl;

      use VMware::VmPerl::VM;

      use VMware::VmPerl::Server;

      use VMware::VmPerl::ConnectParams;

      use File::Basename;

      use strict;

       

      my $backupdir = "/vm/Backups/daily";

      my $log_file = "/var/log/vmware/vmbackup.log";

       

      my ($server, $vm);

       

      my $server_name = undef;

      my $user        = undef;

      my $passwd      = undef;

       

      1. Use the default port of 902.  Change this if your port is different.

      my $port = 902;

       

      open LOG, ">>$log_file";

      log_stuff( "Starting backups" );

       

      #

      1. Connect to VMware Server

      #

      my $connect_params = VMware::VmPerl::ConnectParams::new($server_name,$port,$user,$passwd);

      $server = VMware::VmPerl::Server::new();

       

      if (!$server->connect($connect_params)) {

      my ($error_number, $error_string) = $server->get_last_error();

      log_stuff( "Connect to server: $error_number: $error_string\n" );

      die "Could not connect to server: Error $error_number: $error_string\n";

      }

       

      #

      1. Get list of Virtual Machines

      #

      my @vmlist = $server->registered_vm_names();

      if (!defined($vmlist[0])) {

      my ($error_number, $error_string) = $server->get_last_error();

      log_stuff( "get_vms: $error_number: $error_string" );

      die "Could not get list of VMs from server: Error $error_number: $error_string\n";

      }

       

      #

      1. Virtual Machine Backup

      #

      foreach my $conf (@vmlist) {

      my ($name,$vmdir,$suffix) = fileparse($conf, '\..*' );

       

      1. connect to virtual machine

      $vm = VMware::VmPerl::VM::new();

      if (!$vm->connect($connect_params, $conf)) {

      my ($error_number, $error_string) = $vm->get_last_error();

      log_stuff( "Connect to $conf: $error_number: $error_string\n" );

      die "Could not connect to $conf: Error $error_number: $error_string\n";

      }

       

      1. Get the virtual machine display name

      my $displayName = $vm->get_config("displayName");

      $displayName =~ s/[\()]//g;  # remove special characters

       

      1. Build the path for the backup filename

      my $backup = "$backupdir/$displayName.tar.gz";

       

      1. Get the current state for the virtual machine

      my $state =  $vm->get_execution_state();

       

      1. Log what we are doing

      log_stuff( "$displayName: Starting backup" );

       

      1. handle virtual machines that are running by using lvm snapshot with a suspend

      if ( $state eq VM_EXECUTION_STATE_ON )

      {

      log_stuff( "$displayName: Suspending Virtual Machine" );

      if (!$vm->suspend()) {

      my ($error_number, $error_string) = $vm->get_last_error();

      log_stuff( "suspend $conf: $error_number: $error_string\n" );

      }

      else

      {

      log_stuff( "$displayName: Creating LVM Snapshot" );

      log_stuff( `lvremove -f /dev/data/vmsnapshot` );

      log_stuff( `lvcreate -L9.85G -s -n vmsnapshot /dev/data/vmware` );

       

      log_stuff( "$displayName: Resuming Virtual Machine" );

      if (!$vm->start()) {

      my ($error_number, $error_string) = $vm->get_last_error();

      log_stuff( "start $conf: $error_number: $error_string\n" );

      }

       

      log_stuff( "$displayName: Mounting LVM Snapshot" );

      log_stuff( `mount -t ext3 -v -r /dev/data/vmsnapshot /mnt` );

       

      1. fix directory to use the snapshot instead of the actual file

      $vmdir =~ s!/vm/Machines!/mnt!g;

      log_stuff( "$displayName: Backup $vmdir -> $backup.tmp" );

      log_stuff( `tar czpf $backup.tmp -C $vmdir .` );

       

      log_stuff( "$displayName: Removing LVM Snapshot" );

      log_stuff( `umount -v /mnt` );

      log_stuff( `lvremove -f /dev/data/vmsnapshot` );

      }

      }

      else

      {

      1. regular backup of suspended or offline machines

      log_stuff( "$displayName: Backup $vmdir -> $backup.tmp" );

      log_stuff( `tar czpf $backup.tmp -C $vmdir .` );

      }

       

      log_stuff( "$displayName: Moving $backup.tmp to $backup" );

      log_stuff( `mv -vf $backup.tmp $backup` );

      log_stuff( "$displayName: Backup Completed" );

      $vm->disconnect();

      }

       

      #

      1. Logging

      #

      sub log_stuff

      {

      my $msg = shift();

       

      if ( $msg )

      {

      chomp($msg);

      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);

      printf LOG "%4d-%02d-%02d %02d:%02d:%02d $msg\n", $year1900,$mon1,$mday,$hour,$min,$sec;

      }

      }

       

      1. Destroys the server object, thus disconnecting from the server.

      $server->disconnect();

      undef $server;

       

      log_stuff( "Completed backups" );

      close LOG;