#!/usr/bin/perl -w # # 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; # Use the default port of 902. Change this if your port is different. my $port = 902; open LOG, ">>$log_file"; log_stuff( "Starting backups" ); # # 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"; } # # 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"; } # # Virtual Machine Backup # foreach my $conf (@vmlist) { my ($name,$vmdir,$suffix) = fileparse($conf, '\..*' ); # 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"; } # Get the virtual machine display name my $displayName = $vm->get_config("displayName"); $displayName =~ s/[\() ]//g; # remove special characters # Build the path for the backup filename my $backup = "$backupdir/$displayName.tar.gz"; # Get the current state for the virtual machine my $state = $vm->get_execution_state(); # Log what we are doing log_stuff( "$displayName: Starting backup" ); # 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` ); # 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 { # 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(); } # # 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", $year+1900,$mon+1,$mday,$hour,$min,$sec; } } # Destroys the server object, thus disconnecting from the server. $server->disconnect(); undef $server; log_stuff( "Completed backups" ); close LOG;